diff --git a/vendor/github.com/gorilla/context/LICENSE b/vendor/github.com/gorilla/context/LICENSE new file mode 100644 index 0000000..0e5fb87 --- /dev/null +++ b/vendor/github.com/gorilla/context/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 Rodrigo Moraes. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gorilla/context/README.md b/vendor/github.com/gorilla/context/README.md new file mode 100644 index 0000000..08f8669 --- /dev/null +++ b/vendor/github.com/gorilla/context/README.md @@ -0,0 +1,10 @@ +context +======= +[![Build Status](https://travis-ci.org/gorilla/context.png?branch=master)](https://travis-ci.org/gorilla/context) + +gorilla/context is a general purpose registry for global request variables. + +> Note: gorilla/context, having been born well before `context.Context` existed, does not play well +> with the shallow copying of the request that [`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext) (added to net/http Go 1.7 onwards) performs. You should either use *just* gorilla/context, or moving forward, the new `http.Request.Context()`. + +Read the full documentation here: http://www.gorillatoolkit.org/pkg/context diff --git a/vendor/github.com/gorilla/context/context.go b/vendor/github.com/gorilla/context/context.go new file mode 100644 index 0000000..81cb128 --- /dev/null +++ b/vendor/github.com/gorilla/context/context.go @@ -0,0 +1,143 @@ +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package context + +import ( + "net/http" + "sync" + "time" +) + +var ( + mutex sync.RWMutex + data = make(map[*http.Request]map[interface{}]interface{}) + datat = make(map[*http.Request]int64) +) + +// Set stores a value for a given key in a given request. +func Set(r *http.Request, key, val interface{}) { + mutex.Lock() + if data[r] == nil { + data[r] = make(map[interface{}]interface{}) + datat[r] = time.Now().Unix() + } + data[r][key] = val + mutex.Unlock() +} + +// Get returns a value stored for a given key in a given request. +func Get(r *http.Request, key interface{}) interface{} { + mutex.RLock() + if ctx := data[r]; ctx != nil { + value := ctx[key] + mutex.RUnlock() + return value + } + mutex.RUnlock() + return nil +} + +// GetOk returns stored value and presence state like multi-value return of map access. +func GetOk(r *http.Request, key interface{}) (interface{}, bool) { + mutex.RLock() + if _, ok := data[r]; ok { + value, ok := data[r][key] + mutex.RUnlock() + return value, ok + } + mutex.RUnlock() + return nil, false +} + +// GetAll returns all stored values for the request as a map. Nil is returned for invalid requests. +func GetAll(r *http.Request) map[interface{}]interface{} { + mutex.RLock() + if context, ok := data[r]; ok { + result := make(map[interface{}]interface{}, len(context)) + for k, v := range context { + result[k] = v + } + mutex.RUnlock() + return result + } + mutex.RUnlock() + return nil +} + +// GetAllOk returns all stored values for the request as a map and a boolean value that indicates if +// the request was registered. +func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) { + mutex.RLock() + context, ok := data[r] + result := make(map[interface{}]interface{}, len(context)) + for k, v := range context { + result[k] = v + } + mutex.RUnlock() + return result, ok +} + +// Delete removes a value stored for a given key in a given request. +func Delete(r *http.Request, key interface{}) { + mutex.Lock() + if data[r] != nil { + delete(data[r], key) + } + mutex.Unlock() +} + +// Clear removes all values stored for a given request. +// +// This is usually called by a handler wrapper to clean up request +// variables at the end of a request lifetime. See ClearHandler(). +func Clear(r *http.Request) { + mutex.Lock() + clear(r) + mutex.Unlock() +} + +// clear is Clear without the lock. +func clear(r *http.Request) { + delete(data, r) + delete(datat, r) +} + +// Purge removes request data stored for longer than maxAge, in seconds. +// It returns the amount of requests removed. +// +// If maxAge <= 0, all request data is removed. +// +// This is only used for sanity check: in case context cleaning was not +// properly set some request data can be kept forever, consuming an increasing +// amount of memory. In case this is detected, Purge() must be called +// periodically until the problem is fixed. +func Purge(maxAge int) int { + mutex.Lock() + count := 0 + if maxAge <= 0 { + count = len(data) + data = make(map[*http.Request]map[interface{}]interface{}) + datat = make(map[*http.Request]int64) + } else { + min := time.Now().Unix() - int64(maxAge) + for r := range data { + if datat[r] < min { + clear(r) + count++ + } + } + } + mutex.Unlock() + return count +} + +// ClearHandler wraps an http.Handler and clears request values at the end +// of a request lifetime. +func ClearHandler(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer Clear(r) + h.ServeHTTP(w, r) + }) +} diff --git a/vendor/github.com/gorilla/context/doc.go b/vendor/github.com/gorilla/context/doc.go new file mode 100644 index 0000000..448d1bf --- /dev/null +++ b/vendor/github.com/gorilla/context/doc.go @@ -0,0 +1,88 @@ +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package context stores values shared during a request lifetime. + +Note: gorilla/context, having been born well before `context.Context` existed, +does not play well > with the shallow copying of the request that +[`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext) +(added to net/http Go 1.7 onwards) performs. You should either use *just* +gorilla/context, or moving forward, the new `http.Request.Context()`. + +For example, a router can set variables extracted from the URL and later +application handlers can access those values, or it can be used to store +sessions values to be saved at the end of a request. There are several +others common uses. + +The idea was posted by Brad Fitzpatrick to the go-nuts mailing list: + + http://groups.google.com/group/golang-nuts/msg/e2d679d303aa5d53 + +Here's the basic usage: first define the keys that you will need. The key +type is interface{} so a key can be of any type that supports equality. +Here we define a key using a custom int type to avoid name collisions: + + package foo + + import ( + "github.com/gorilla/context" + ) + + type key int + + const MyKey key = 0 + +Then set a variable. Variables are bound to an http.Request object, so you +need a request instance to set a value: + + context.Set(r, MyKey, "bar") + +The application can later access the variable using the same key you provided: + + func MyHandler(w http.ResponseWriter, r *http.Request) { + // val is "bar". + val := context.Get(r, foo.MyKey) + + // returns ("bar", true) + val, ok := context.GetOk(r, foo.MyKey) + // ... + } + +And that's all about the basic usage. We discuss some other ideas below. + +Any type can be stored in the context. To enforce a given type, make the key +private and wrap Get() and Set() to accept and return values of a specific +type: + + type key int + + const mykey key = 0 + + // GetMyKey returns a value for this package from the request values. + func GetMyKey(r *http.Request) SomeType { + if rv := context.Get(r, mykey); rv != nil { + return rv.(SomeType) + } + return nil + } + + // SetMyKey sets a value for this package in the request values. + func SetMyKey(r *http.Request, val SomeType) { + context.Set(r, mykey, val) + } + +Variables must be cleared at the end of a request, to remove all values +that were stored. This can be done in an http.Handler, after a request was +served. Just call Clear() passing the request: + + context.Clear(r) + +...or use ClearHandler(), which conveniently wraps an http.Handler to clear +variables at the end of a request lifetime. + +The Routers from the packages gorilla/mux and gorilla/pat call Clear() +so if you are using either of them you don't need to clear the context manually. +*/ +package context diff --git a/vendor/github.com/gorilla/pat/LICENSE b/vendor/github.com/gorilla/pat/LICENSE new file mode 100644 index 0000000..0e5fb87 --- /dev/null +++ b/vendor/github.com/gorilla/pat/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 Rodrigo Moraes. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gorilla/pat/README.md b/vendor/github.com/gorilla/pat/README.md new file mode 100644 index 0000000..d89500c --- /dev/null +++ b/vendor/github.com/gorilla/pat/README.md @@ -0,0 +1,70 @@ +pat +=== +[![GoDoc](https://godoc.org/github.com/gorilla/pat?status.svg)](https://godoc.org/github.com/gorilla/pat) +[![Build Status](https://travis-ci.org/gorilla/pat.svg?branch=master)](https://travis-ci.org/gorilla/pat) + +### How to use? + +pat is pretty simple. The documentation lives [here](http://www.gorillatoolkit.org/pkg/pat). + +### Install +With a properly configured Go toolchain: +```sh +go get github.com/gorilla/pat +``` + +### Example + +Here's an example of a RESTful api: + +```go +package main + +import ( + "log" + "net/http" + + "github.com/gorilla/pat" +) + +func homeHandler(wr http.ResponseWriter, req *http.Request) { + wr.WriteHeader(http.StatusOK) + wr.Write([]byte("Yay! We're home, Jim!")) +} + +func getAllTheThings(wr http.ResponseWriter, req *http.Request) { + wr.WriteHeader(http.StatusOK) + wr.Write([]byte("Look, Jim! Get all the things!")) +} + +func putOneThing(wr http.ResponseWriter, req *http.Request) { + wr.WriteHeader(http.StatusOK) + wr.Write([]byte("Look, Jim! Put one thing!")) +} + +func deleteOneThing(wr http.ResponseWriter, req *http.Request) { + wr.WriteHeader(http.StatusOK) + wr.Write([]byte("Look, Jim! Delete one thing!")) +} + +func main() { + router := pat.New() + + router.Get("/things", getAllTheThings) + + router.Put("/things/{id}", putOneThing) + router.Delete("/things/{id}", deleteOneThing) + + router.Get("/", homeHandler) + + http.Handle("/", router) + + log.Print("Listening on 127.0.0.1:8000...") + log.Fatal(http.ListenAndServe(":8000", nil)) +} +``` +Notice how the routes descend? That's because Pat will take the first route +that matches. For your own testing, take the line ```router.Get("/", +homeHandler)``` and put it above the other routes and run the example. When you +try to curl any of the routes, you'll only get what the homeHandler returns. +Design your routes carefully. diff --git a/vendor/github.com/gorilla/pat/doc.go b/vendor/github.com/gorilla/pat/doc.go new file mode 100644 index 0000000..df66d08 --- /dev/null +++ b/vendor/github.com/gorilla/pat/doc.go @@ -0,0 +1,67 @@ +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package gorilla/pat is a request router and dispatcher with a pat-like +interface. It is an alternative to gorilla/mux that showcases how it can +be used as a base for different API flavors. Package pat is documented at: + + http://godoc.org/github.com/bmizerany/pat + +Let's start registering a couple of URL paths and handlers: + + func main() { + r := pat.New() + r.Get("/products", ProductsHandler) + r.Get("/articles", ArticlesHandler) + r.Get("/", HomeHandler) + http.Handle("/", r) + } + +Here we register three routes mapping URL paths to handlers. This is +equivalent to how http.HandleFunc() works: if an incoming GET request matches +one of the paths, the corresponding handler is called passing +(http.ResponseWriter, *http.Request) as parameters. + +Note: gorilla/pat matches path prefixes, so you must register the most +specific paths first. + +Note: differently from pat, these methods accept a handler function, and not an +http.Handler. We think this is shorter and more convenient. To set an +http.Handler, use the Add() method. + +Paths can have variables. They are defined using the format {name} or +{name:pattern}. If a regular expression pattern is not defined, the matched +variable will be anything until the next slash. For example: + + r := pat.New() + r.Get("/articles/{category}/{id:[0-9]+}", ArticleHandler) + r.Get("/articles/{category}/", ArticlesCategoryHandler) + r.Get("/products/{key}", ProductHandler) + +The names are used to create a map of route variables which are stored in the +URL query, prefixed by a colon: + + category := req.URL.Query().Get(":category") + +As in the gorilla/mux package, other matchers can be added to the registered +routes and URLs can be reversed as well. To build a URL for a route, first +add a name to it: + + r.Get("/products/{key}", ProductHandler).Name("product") + +Then you can get it using the name and generate a URL: + + url, err := r.GetRoute("product").URL("key", "transmogrifier") + +...and the result will be a url.URL with the following path: + + "/products/transmogrifier" + +Check the mux documentation for more details about URL building and extra +matchers: + + http://gorilla-web.appspot.com/pkg/mux/ +*/ +package pat diff --git a/vendor/github.com/gorilla/pat/pat.go b/vendor/github.com/gorilla/pat/pat.go new file mode 100644 index 0000000..26a03ea --- /dev/null +++ b/vendor/github.com/gorilla/pat/pat.go @@ -0,0 +1,126 @@ +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pat + +import ( + "net/http" + "net/url" + "path" + "strings" + + "github.com/gorilla/context" + "github.com/gorilla/mux" +) + +// New returns a new router. +func New() *Router { + return &Router{} +} + +// Router is a request router that implements a pat-like API. +// +// pat docs: http://godoc.org/github.com/bmizerany/pat +type Router struct { + mux.Router +} + +// Add registers a pattern with a handler for the given request method. +func (r *Router) Add(meth, pat string, h http.Handler) *mux.Route { + return r.NewRoute().PathPrefix(pat).Handler(h).Methods(meth) +} + +// Options registers a pattern with a handler for OPTIONS requests. +func (r *Router) Options(pat string, h http.HandlerFunc) *mux.Route { + return r.Add("OPTIONS", pat, h) +} + +// Delete registers a pattern with a handler for DELETE requests. +func (r *Router) Delete(pat string, h http.HandlerFunc) *mux.Route { + return r.Add("DELETE", pat, h) +} + +// Head registers a pattern with a handler for HEAD requests. +func (r *Router) Head(pat string, h http.HandlerFunc) *mux.Route { + return r.Add("HEAD", pat, h) +} + +// Get registers a pattern with a handler for GET requests. +func (r *Router) Get(pat string, h http.HandlerFunc) *mux.Route { + return r.Add("GET", pat, h) +} + +// Post registers a pattern with a handler for POST requests. +func (r *Router) Post(pat string, h http.HandlerFunc) *mux.Route { + return r.Add("POST", pat, h) +} + +// Put registers a pattern with a handler for PUT requests. +func (r *Router) Put(pat string, h http.HandlerFunc) *mux.Route { + return r.Add("PUT", pat, h) +} + +// Patch registers a pattern with a handler for PATCH requests. +func (r *Router) Patch(pat string, h http.HandlerFunc) *mux.Route { + return r.Add("PATCH", pat, h) +} + +// ServeHTTP dispatches the handler registered in the matched route. +func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { + // Clean path to canonical form and redirect. + if p := cleanPath(req.URL.Path); p != req.URL.Path { + w.Header().Set("Location", p) + w.WriteHeader(http.StatusMovedPermanently) + return + } + var match mux.RouteMatch + var handler http.Handler + if matched := r.Match(req, &match); matched { + handler = match.Handler + registerVars(req, match.Vars) + } + if handler == nil { + if r.NotFoundHandler == nil { + r.NotFoundHandler = http.NotFoundHandler() + } + handler = r.NotFoundHandler + } + if !r.KeepContext { + defer context.Clear(req) + } + handler.ServeHTTP(w, req) +} + +// registerVars adds the matched route variables to the URL query. +func registerVars(r *http.Request, vars map[string]string) { + parts, i := make([]string, len(vars)), 0 + for key, value := range vars { + parts[i] = url.QueryEscape(":"+key) + "=" + url.QueryEscape(value) + i++ + } + q := strings.Join(parts, "&") + if r.URL.RawQuery == "" { + r.URL.RawQuery = q + } else { + r.URL.RawQuery += "&" + q + } +} + +// cleanPath returns the canonical path for p, eliminating . and .. elements. +// Borrowed from the net/http package. +func cleanPath(p string) string { + if p == "" { + return "/" + } + if p[0] != '/' { + p = "/" + p + } + np := path.Clean(p) + // path.Clean removes trailing slash except for root; + // put the trailing slash back if necessary. + if p[len(p)-1] == '/' && np != "/" { + np += "/" + } + return np +} diff --git a/vendor/github.com/urfave/negroni/CHANGELOG.md b/vendor/github.com/urfave/negroni/CHANGELOG.md new file mode 100644 index 0000000..5e77c3f --- /dev/null +++ b/vendor/github.com/urfave/negroni/CHANGELOG.md @@ -0,0 +1,35 @@ +# Change Log + +**ATTN**: This project uses [semantic versioning](http://semver.org/). + +## [Unreleased] +### Added +- `Recovery.ErrorHandlerFunc` for custom error handling during recovery + +### Fixed +- `Written()` correct returns `false` if no response header has been written + +### Changed +- Set default status to `0` in the case that no handler writes status -- was + previously `200` (in 0.2.0, before that it was `0` so this reestablishes that + behavior) +- Catch `panic`s thrown by callbacks provided to the `Recovery` handler + +## [0.2.0] - 2016-05-10 +### Added +- Support for variadic handlers in `New()` +- Added `Negroni.Handlers()` to fetch all of the handlers for a given chain +- Allowed size in `Recovery` handler was bumped to 8k +- `Negroni.UseFunc` to push another handler onto the chain + +### Changed +- Set the status before calling `beforeFuncs` so the information is available to them +- Set default status to `200` in the case that no handler writes status -- was previously `0` +- Panic if `nil` handler is given to `negroni.Use` + +## 0.1.0 - 2013-07-22 +### Added +- Initial implementation. + +[Unreleased]: https://github.com/urfave/negroni/compare/v0.2.0...HEAD +[0.2.0]: https://github.com/urfave/negroni/compare/v0.1.0...v0.2.0 diff --git a/vendor/github.com/urfave/negroni/LICENSE b/vendor/github.com/urfave/negroni/LICENSE new file mode 100644 index 0000000..08b5e20 --- /dev/null +++ b/vendor/github.com/urfave/negroni/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Jeremy Saenz + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/urfave/negroni/README.md b/vendor/github.com/urfave/negroni/README.md new file mode 100644 index 0000000..44d35cc --- /dev/null +++ b/vendor/github.com/urfave/negroni/README.md @@ -0,0 +1,444 @@ +# Negroni +[![GoDoc](https://godoc.org/github.com/urfave/negroni?status.svg)](http://godoc.org/github.com/urfave/negroni) +[![Build Status](https://travis-ci.org/urfave/negroni.svg?branch=master)](https://travis-ci.org/urfave/negroni) +[![codebeat](https://codebeat.co/badges/47d320b1-209e-45e8-bd99-9094bc5111e2)](https://codebeat.co/projects/github-com-urfave-negroni) + +**Notice:** This is the library formerly known as +`github.com/codegangsta/negroni` -- Github will automatically redirect requests +to this repository, but we recommend updating your references for clarity. + +Negroni is an idiomatic approach to web middleware in Go. It is tiny, +non-intrusive, and encourages use of `net/http` Handlers. + +If you like the idea of [Martini](https://github.com/go-martini/martini), but +you think it contains too much magic, then Negroni is a great fit. + +Language Translations: +* [German (de_DE)](translations/README_de_de.md) +* [Português Brasileiro (pt_BR)](translations/README_pt_br.md) +* [简体中文 (zh_cn)](translations/README_zh_cn.md) +* [繁體中文 (zh_tw)](translations/README_zh_tw.md) +* [日本語 (ja_JP)](translations/README_ja_JP.md) + +## Getting Started + +After installing Go and setting up your +[GOPATH](http://golang.org/doc/code.html#GOPATH), create your first `.go` file. +We'll call it `server.go`. + + +``` go +package main + +import ( + "fmt" + "net/http" + + "github.com/urfave/negroni" +) + +func main() { + mux := http.NewServeMux() + mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { + fmt.Fprintf(w, "Welcome to the home page!") + }) + + n := negroni.Classic() // Includes some default middlewares + n.UseHandler(mux) + + http.ListenAndServe(":3000", n) +} +``` + +Then install the Negroni package (**NOTE**: >= **go 1.1** is required): + +``` +go get github.com/urfave/negroni +``` + +Then run your server: + +``` +go run server.go +``` + +You will now have a Go `net/http` webserver running on `localhost:3000`. + +## Is Negroni a Framework? + +Negroni is **not** a framework. It is a middleware-focused library that is +designed to work directly with `net/http`. + +## Routing? + +Negroni is BYOR (Bring your own Router). The Go community already has a number +of great http routers available, and Negroni tries to play well with all of them +by fully supporting `net/http`. For instance, integrating with [Gorilla Mux] +looks like so: + +``` go +router := mux.NewRouter() +router.HandleFunc("/", HomeHandler) + +n := negroni.New(Middleware1, Middleware2) +// Or use a middleware with the Use() function +n.Use(Middleware3) +// router goes last +n.UseHandler(router) + +http.ListenAndServe(":3001", n) +``` + +## `negroni.Classic()` + +`negroni.Classic()` provides some default middleware that is useful for most +applications: + +* [`negroni.Recovery`](#recovery) - Panic Recovery Middleware. +* [`negroni.Logger`](#logger) - Request/Response Logger Middleware. +* [`negroni.Static`](#static) - Static File serving under the "public" + directory. + +This makes it really easy to get started with some useful features from Negroni. + +## Handlers + +Negroni provides a bidirectional middleware flow. This is done through the +`negroni.Handler` interface: + +``` go +type Handler interface { + ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) +} +``` + +If a middleware hasn't already written to the `ResponseWriter`, it should call +the next `http.HandlerFunc` in the chain to yield to the next middleware +handler. This can be used for great good: + +``` go +func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + // do some stuff before + next(rw, r) + // do some stuff after +} +``` + +And you can map it to the handler chain with the `Use` function: + +``` go +n := negroni.New() +n.Use(negroni.HandlerFunc(MyMiddleware)) +``` + +You can also map plain old `http.Handler`s: + +``` go +n := negroni.New() + +mux := http.NewServeMux() +// map your routes + +n.UseHandler(mux) + +http.ListenAndServe(":3000", n) +``` + +## `Run()` + +Negroni has a convenience function called `Run`. `Run` takes an addr string +identical to [`http.ListenAndServe`](https://godoc.org/net/http#ListenAndServe). + + +``` go +package main + +import ( + "github.com/urfave/negroni" +) + +func main() { + n := negroni.Classic() + n.Run(":8080") +} +``` + +In general, you will want to use `net/http` methods and pass `negroni` as a +`Handler`, as this is more flexible, e.g.: + + +``` go +package main + +import ( + "fmt" + "log" + "net/http" + "time" + + "github.com/urfave/negroni" +) + +func main() { + mux := http.NewServeMux() + mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { + fmt.Fprintf(w, "Welcome to the home page!") + }) + + n := negroni.Classic() // Includes some default middlewares + n.UseHandler(mux) + + s := &http.Server{ + Addr: ":8080", + Handler: n, + ReadTimeout: 10 * time.Second, + WriteTimeout: 10 * time.Second, + MaxHeaderBytes: 1 << 20, + } + log.Fatal(s.ListenAndServe()) +} +``` + +## Route Specific Middleware + +If you have a route group of routes that need specific middleware to be +executed, you can simply create a new Negroni instance and use it as your route +handler. + +``` go +router := mux.NewRouter() +adminRoutes := mux.NewRouter() +// add admin routes here + +// Create a new negroni for the admin middleware +router.PathPrefix("/admin").Handler(negroni.New( + Middleware1, + Middleware2, + negroni.Wrap(adminRoutes), +)) +``` + +If you are using [Gorilla Mux], here is an example using a subrouter: + +``` go +router := mux.NewRouter() +subRouter := mux.NewRouter().PathPrefix("/subpath").Subrouter().StrictSlash(true) +subRouter.HandleFunc("/", someSubpathHandler) // "/subpath/" +subRouter.HandleFunc("/:id", someSubpathHandler) // "/subpath/:id" + +// "/subpath" is necessary to ensure the subRouter and main router linkup +router.PathPrefix("/subpath").Handler(negroni.New( + Middleware1, + Middleware2, + negroni.Wrap(subRouter), +)) +``` + +## Bundled Middleware + +### Static + +This middleware will serve files on the filesystem. If the files do not exist, +it proxies the request to the next middleware. If you want the requests for +non-existent files to return a `404 File Not Found` to the user you should look +at using [http.FileServer](https://golang.org/pkg/net/http/#FileServer) as +a handler. + +Example: + + +``` go +package main + +import ( + "fmt" + "net/http" + + "github.com/urfave/negroni" +) + +func main() { + mux := http.NewServeMux() + mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { + fmt.Fprintf(w, "Welcome to the home page!") + }) + + // Example of using a http.FileServer if you want "server-like" rather than "middleware" behavior + // mux.Handle("/public", http.FileServer(http.Dir("/home/public"))) + + n := negroni.New() + n.Use(negroni.NewStatic(http.Dir("/tmp"))) + n.UseHandler(mux) + + http.ListenAndServe(":3002", n) +} +``` + +Will serve files from the `/tmp` directory first, but proxy calls to the next +handler if the request does not match a file on the filesystem. + +### Recovery + +This middleware catches `panic`s and responds with a `500` response code. If +any other middleware has written a response code or body, this middleware will +fail to properly send a 500 to the client, as the client has already received +the HTTP response code. Additionally, an `ErrorHandlerFunc` can be attached +to report 500's to an error reporting service such as Sentry or Airbrake. + +Example: + + +``` go +package main + +import ( + "net/http" + + "github.com/urfave/negroni" +) + +func main() { + mux := http.NewServeMux() + mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { + panic("oh no") + }) + + n := negroni.New() + n.Use(negroni.NewRecovery()) + n.UseHandler(mux) + + http.ListenAndServe(":3003", n) +} +``` + +Will return a `500 Internal Server Error` to each request. It will also log the +stack traces as well as print the stack trace to the requester if `PrintStack` +is set to `true` (the default). + +Example with error handler: + +``` go +package main + +import ( + "net/http" + + "github.com/urfave/negroni" +) + +func main() { + mux := http.NewServeMux() + mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { + panic("oh no") + }) + + n := negroni.New() + recovery := negroni.NewRecovery() + recovery.ErrorHandlerFunc = reportToSentry + n.Use(recovery) + n.UseHandler(mux) + + http.ListenAndServe(":3003", n) +} + +func reportToSentry(error interface{}) { + // write code here to report error to Sentry +} +``` + + +## Logger + +This middleware logs each incoming request and response. + +Example: + + +``` go +package main + +import ( + "fmt" + "net/http" + + "github.com/urfave/negroni" +) + +func main() { + mux := http.NewServeMux() + mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { + fmt.Fprintf(w, "Welcome to the home page!") + }) + + n := negroni.New() + n.Use(negroni.NewLogger()) + n.UseHandler(mux) + + http.ListenAndServe(":3004", n) +} +``` + +Will print a log similar to: + +``` +[negroni] Started GET / +[negroni] Completed 200 OK in 145.446µs +``` + +on each request. + +## Third Party Middleware + +Here is a current list of Negroni compatible middlware. Feel free to put up a PR +linking your middleware if you have built one: + +| Middleware | Author | Description | +| -----------|--------|-------------| +| [binding](https://github.com/mholt/binding) | [Matt Holt](https://github.com/mholt) | Data binding from HTTP requests into structs | +| [cloudwatch](https://github.com/cvillecsteele/negroni-cloudwatch) | [Colin Steele](https://github.com/cvillecsteele) | AWS cloudwatch metrics middleware | +| [cors](https://github.com/rs/cors) | [Olivier Poitrey](https://github.com/rs) | [Cross Origin Resource Sharing](http://www.w3.org/TR/cors/) (CORS) support | +| [csp](https://github.com/awakenetworks/csp) | [Awake Networks](https://github.com/awakenetworks) | [Content Security Policy](https://www.w3.org/TR/CSP2/) (CSP) support | +| [delay](https://github.com/jeffbmartinez/delay) | [Jeff Martinez](https://github.com/jeffbmartinez) | Add delays/latency to endpoints. Useful when testing effects of high latency | +| [New Relic Go Agent](https://github.com/yadvendar/negroni-newrelic-go-agent) | [Yadvendar Champawat](https://github.com/yadvendar) | Official [New Relic Go Agent](https://github.com/newrelic/go-agent) (currently in beta) | +| [gorelic](https://github.com/jingweno/negroni-gorelic) | [Jingwen Owen Ou](https://github.com/jingweno) | New Relic agent for Go runtime | +| [Graceful](https://github.com/tylerb/graceful) | [Tyler Bunnell](https://github.com/tylerb) | Graceful HTTP Shutdown | +| [gzip](https://github.com/phyber/negroni-gzip) | [phyber](https://github.com/phyber) | GZIP response compression | +| [JWT Middleware](https://github.com/auth0/go-jwt-middleware) | [Auth0](https://github.com/auth0) | Middleware checks for a JWT on the `Authorization` header on incoming requests and decodes it| +| [logrus](https://github.com/meatballhat/negroni-logrus) | [Dan Buch](https://github.com/meatballhat) | Logrus-based logger | +| [oauth2](https://github.com/goincremental/negroni-oauth2) | [David Bochenski](https://github.com/bochenski) | oAuth2 middleware | +| [onthefly](https://github.com/xyproto/onthefly) | [Alexander Rødseth](https://github.com/xyproto) | Generate TinySVG, HTML and CSS on the fly | +| [permissions2](https://github.com/xyproto/permissions2) | [Alexander Rødseth](https://github.com/xyproto) | Cookies, users and permissions | +| [prometheus](https://github.com/zbindenren/negroni-prometheus) | [Rene Zbinden](https://github.com/zbindenren) | Easily create metrics endpoint for the [prometheus](http://prometheus.io) instrumentation tool | +| [render](https://github.com/unrolled/render) | [Cory Jacobsen](https://github.com/unrolled) | Render JSON, XML and HTML templates | +| [RestGate](https://github.com/pjebs/restgate) | [Prasanga Siripala](https://github.com/pjebs) | Secure authentication for REST API endpoints | +| [secure](https://github.com/unrolled/secure) | [Cory Jacobsen](https://github.com/unrolled) | Middleware that implements a few quick security wins | +| [sessions](https://github.com/goincremental/negroni-sessions) | [David Bochenski](https://github.com/bochenski) | Session Management | +| [stats](https://github.com/thoas/stats) | [Florent Messa](https://github.com/thoas) | Store information about your web application (response time, etc.) | +| [VanGoH](https://github.com/auroratechnologies/vangoh) | [Taylor Wrobel](https://github.com/twrobel3) | Configurable [AWS-Style](http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html) HMAC authentication middleware | +| [xrequestid](https://github.com/pilu/xrequestid) | [Andrea Franz](https://github.com/pilu) | Middleware that assigns a random X-Request-Id header to each request | +| [mgo session](https://github.com/joeljames/nigroni-mgo-session) | [Joel James](https://github.com/joeljames) | Middleware that handles creating and closing mgo sessions per request | +| [digits](https://github.com/bamarni/digits) | [Bilal Amarni](https://github.com/bamarni) | Middleware that handles [Twitter Digits](https://get.digits.com/) authentication | + +## Examples + +[Alexander Rødseth](https://github.com/xyproto) created +[mooseware](https://github.com/xyproto/mooseware), a skeleton for writing a +Negroni middleware handler. + +## Live code reload? + +[gin](https://github.com/codegangsta/gin) and +[fresh](https://github.com/pilu/fresh) both live reload negroni apps. + +## Essential Reading for Beginners of Go & Negroni + +* [Using a Context to pass information from middleware to end handler](http://elithrar.github.io/article/map-string-interface/) +* [Understanding middleware](https://mattstauffer.co/blog/laravel-5.0-middleware-filter-style) + +## About + +Negroni is obsessively designed by none other than the [Code +Gangsta](https://codegangsta.io/) + +[Gorilla Mux]: https://github.com/gorilla/mux +[`http.FileSystem`]: https://godoc.org/net/http#FileSystem diff --git a/vendor/github.com/urfave/negroni/doc.go b/vendor/github.com/urfave/negroni/doc.go new file mode 100644 index 0000000..add1ed9 --- /dev/null +++ b/vendor/github.com/urfave/negroni/doc.go @@ -0,0 +1,25 @@ +// Package negroni is an idiomatic approach to web middleware in Go. It is tiny, non-intrusive, and encourages use of net/http Handlers. +// +// If you like the idea of Martini, but you think it contains too much magic, then Negroni is a great fit. +// +// For a full guide visit http://github.com/urfave/negroni +// +// package main +// +// import ( +// "github.com/urfave/negroni" +// "net/http" +// "fmt" +// ) +// +// func main() { +// mux := http.NewServeMux() +// mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { +// fmt.Fprintf(w, "Welcome to the home page!") +// }) +// +// n := negroni.Classic() +// n.UseHandler(mux) +// n.Run(":3000") +// } +package negroni diff --git a/vendor/github.com/urfave/negroni/logger.go b/vendor/github.com/urfave/negroni/logger.go new file mode 100644 index 0000000..04cd53b --- /dev/null +++ b/vendor/github.com/urfave/negroni/logger.go @@ -0,0 +1,35 @@ +package negroni + +import ( + "log" + "net/http" + "os" + "time" +) + +// ALogger interface +type ALogger interface { + Println(v ...interface{}) + Printf(format string, v ...interface{}) +} + +// Logger is a middleware handler that logs the request as it goes in and the response as it goes out. +type Logger struct { + // ALogger implements just enough log.Logger interface to be compatible with other implementations + ALogger +} + +// NewLogger returns a new Logger instance +func NewLogger() *Logger { + return &Logger{log.New(os.Stdout, "[negroni] ", 0)} +} + +func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + start := time.Now() + l.Printf("Started %s %s", r.Method, r.URL.Path) + + next(rw, r) + + res := rw.(ResponseWriter) + l.Printf("Completed %v %s in %v", res.Status(), http.StatusText(res.Status()), time.Since(start)) +} diff --git a/vendor/github.com/urfave/negroni/negroni.go b/vendor/github.com/urfave/negroni/negroni.go new file mode 100644 index 0000000..9c7c187 --- /dev/null +++ b/vendor/github.com/urfave/negroni/negroni.go @@ -0,0 +1,133 @@ +package negroni + +import ( + "log" + "net/http" + "os" +) + +// Handler handler is an interface that objects can implement to be registered to serve as middleware +// in the Negroni middleware stack. +// ServeHTTP should yield to the next middleware in the chain by invoking the next http.HandlerFunc +// passed in. +// +// If the Handler writes to the ResponseWriter, the next http.HandlerFunc should not be invoked. +type Handler interface { + ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) +} + +// HandlerFunc is an adapter to allow the use of ordinary functions as Negroni handlers. +// If f is a function with the appropriate signature, HandlerFunc(f) is a Handler object that calls f. +type HandlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) + +func (h HandlerFunc) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + h(rw, r, next) +} + +type middleware struct { + handler Handler + next *middleware +} + +func (m middleware) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + m.handler.ServeHTTP(rw, r, m.next.ServeHTTP) +} + +// Wrap converts a http.Handler into a negroni.Handler so it can be used as a Negroni +// middleware. The next http.HandlerFunc is automatically called after the Handler +// is executed. +func Wrap(handler http.Handler) Handler { + return HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + handler.ServeHTTP(rw, r) + next(rw, r) + }) +} + +// Negroni is a stack of Middleware Handlers that can be invoked as an http.Handler. +// Negroni middleware is evaluated in the order that they are added to the stack using +// the Use and UseHandler methods. +type Negroni struct { + middleware middleware + handlers []Handler +} + +// New returns a new Negroni instance with no middleware preconfigured. +func New(handlers ...Handler) *Negroni { + return &Negroni{ + handlers: handlers, + middleware: build(handlers), + } +} + +// Classic returns a new Negroni instance with the default middleware already +// in the stack. +// +// Recovery - Panic Recovery Middleware +// Logger - Request/Response Logging +// Static - Static File Serving +func Classic() *Negroni { + return New(NewRecovery(), NewLogger(), NewStatic(http.Dir("public"))) +} + +func (n *Negroni) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + n.middleware.ServeHTTP(NewResponseWriter(rw), r) +} + +// Use adds a Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni. +func (n *Negroni) Use(handler Handler) { + if handler == nil { + panic("handler cannot be nil") + } + + n.handlers = append(n.handlers, handler) + n.middleware = build(n.handlers) +} + +// UseFunc adds a Negroni-style handler function onto the middleware stack. +func (n *Negroni) UseFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)) { + n.Use(HandlerFunc(handlerFunc)) +} + +// UseHandler adds a http.Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni. +func (n *Negroni) UseHandler(handler http.Handler) { + n.Use(Wrap(handler)) +} + +// UseHandler adds a http.HandlerFunc-style handler function onto the middleware stack. +func (n *Negroni) UseHandlerFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request)) { + n.UseHandler(http.HandlerFunc(handlerFunc)) +} + +// Run is a convenience function that runs the negroni stack as an HTTP +// server. The addr string takes the same format as http.ListenAndServe. +func (n *Negroni) Run(addr string) { + l := log.New(os.Stdout, "[negroni] ", 0) + l.Printf("listening on %s", addr) + l.Fatal(http.ListenAndServe(addr, n)) +} + +// Returns a list of all the handlers in the current Negroni middleware chain. +func (n *Negroni) Handlers() []Handler { + return n.handlers +} + +func build(handlers []Handler) middleware { + var next middleware + + if len(handlers) == 0 { + return voidMiddleware() + } else if len(handlers) > 1 { + next = build(handlers[1:]) + } else { + next = voidMiddleware() + } + + return middleware{handlers[0], &next} +} + +func voidMiddleware() middleware { + return middleware{ + HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {}), + &middleware{}, + } +} diff --git a/vendor/github.com/urfave/negroni/recovery.go b/vendor/github.com/urfave/negroni/recovery.go new file mode 100644 index 0000000..8396cb1 --- /dev/null +++ b/vendor/github.com/urfave/negroni/recovery.go @@ -0,0 +1,65 @@ +package negroni + +import ( + "fmt" + "log" + "net/http" + "os" + "runtime" + "runtime/debug" +) + +// Recovery is a Negroni middleware that recovers from any panics and writes a 500 if there was one. +type Recovery struct { + Logger ALogger + PrintStack bool + ErrorHandlerFunc func(interface{}) + StackAll bool + StackSize int +} + +// NewRecovery returns a new instance of Recovery +func NewRecovery() *Recovery { + return &Recovery{ + Logger: log.New(os.Stdout, "[negroni] ", 0), + PrintStack: true, + StackAll: false, + StackSize: 1024 * 8, + } +} + +func (rec *Recovery) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + defer func() { + if err := recover(); err != nil { + if rw.Header().Get("Content-Type") == "" { + rw.Header().Set("Content-Type", "text/plain; charset=utf-8") + } + + rw.WriteHeader(http.StatusInternalServerError) + + stack := make([]byte, rec.StackSize) + stack = stack[:runtime.Stack(stack, rec.StackAll)] + + f := "PANIC: %s\n%s" + rec.Logger.Printf(f, err, stack) + + if rec.PrintStack { + fmt.Fprintf(rw, f, err, stack) + } + + if rec.ErrorHandlerFunc != nil { + func() { + defer func() { + if err := recover(); err != nil { + rec.Logger.Printf("provided ErrorHandlerFunc panic'd: %s, trace:\n%s", err, debug.Stack()) + rec.Logger.Printf("%s\n", debug.Stack()) + } + }() + rec.ErrorHandlerFunc(err) + }() + } + } + }() + + next(rw, r) +} diff --git a/vendor/github.com/urfave/negroni/response_writer.go b/vendor/github.com/urfave/negroni/response_writer.go new file mode 100644 index 0000000..bfb83a6 --- /dev/null +++ b/vendor/github.com/urfave/negroni/response_writer.go @@ -0,0 +1,113 @@ +package negroni + +import ( + "bufio" + "fmt" + "net" + "net/http" +) + +// ResponseWriter is a wrapper around http.ResponseWriter that provides extra information about +// the response. It is recommended that middleware handlers use this construct to wrap a responsewriter +// if the functionality calls for it. +type ResponseWriter interface { + http.ResponseWriter + http.Flusher + // Status returns the status code of the response or 200 if the response has + // not been written (as this is the default response code in net/http) + Status() int + // Written returns whether or not the ResponseWriter has been written. + Written() bool + // Size returns the size of the response body. + Size() int + // Before allows for a function to be called before the ResponseWriter has been written to. This is + // useful for setting headers or any other operations that must happen before a response has been written. + Before(func(ResponseWriter)) +} + +type beforeFunc func(ResponseWriter) + +// NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter +func NewResponseWriter(rw http.ResponseWriter) ResponseWriter { + nrw := &responseWriter{ + ResponseWriter: rw, + } + + if _, ok := rw.(http.CloseNotifier); ok { + return &responseWriterCloseNotifer{nrw} + } + + return nrw +} + +type responseWriter struct { + http.ResponseWriter + status int + size int + beforeFuncs []beforeFunc +} + +func (rw *responseWriter) WriteHeader(s int) { + rw.status = s + rw.callBefore() + rw.ResponseWriter.WriteHeader(s) +} + +func (rw *responseWriter) Write(b []byte) (int, error) { + if !rw.Written() { + // The status will be StatusOK if WriteHeader has not been called yet + rw.WriteHeader(http.StatusOK) + } + size, err := rw.ResponseWriter.Write(b) + rw.size += size + return size, err +} + +func (rw *responseWriter) Status() int { + return rw.status +} + +func (rw *responseWriter) Size() int { + return rw.size +} + +func (rw *responseWriter) Written() bool { + return rw.status != 0 +} + +func (rw *responseWriter) Before(before func(ResponseWriter)) { + rw.beforeFuncs = append(rw.beforeFuncs, before) +} + +func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { + hijacker, ok := rw.ResponseWriter.(http.Hijacker) + if !ok { + return nil, nil, fmt.Errorf("the ResponseWriter doesn't support the Hijacker interface") + } + return hijacker.Hijack() +} + +func (rw *responseWriter) callBefore() { + for i := len(rw.beforeFuncs) - 1; i >= 0; i-- { + rw.beforeFuncs[i](rw) + } +} + +func (rw *responseWriter) Flush() { + flusher, ok := rw.ResponseWriter.(http.Flusher) + if ok { + if !rw.Written() { + // The status will be StatusOK if WriteHeader has not been called yet + rw.WriteHeader(http.StatusOK) + } + flusher.Flush() + } +} + +type responseWriterCloseNotifer struct { + *responseWriter +} + +func (rw *responseWriterCloseNotifer) CloseNotify() <-chan bool { + return rw.ResponseWriter.(http.CloseNotifier).CloseNotify() +} diff --git a/vendor/github.com/urfave/negroni/static.go b/vendor/github.com/urfave/negroni/static.go new file mode 100644 index 0000000..34be967 --- /dev/null +++ b/vendor/github.com/urfave/negroni/static.go @@ -0,0 +1,88 @@ +package negroni + +import ( + "net/http" + "path" + "strings" +) + +// Static is a middleware handler that serves static files in the given +// directory/filesystem. If the file does not exist on the filesystem, it +// passes along to the next middleware in the chain. If you desire "fileserver" +// type behavior where it returns a 404 for unfound files, you should consider +// using http.FileServer from the Go stdlib. +type Static struct { + // Dir is the directory to serve static files from + Dir http.FileSystem + // Prefix is the optional prefix used to serve the static directory content + Prefix string + // IndexFile defines which file to serve as index if it exists. + IndexFile string +} + +// NewStatic returns a new instance of Static +func NewStatic(directory http.FileSystem) *Static { + return &Static{ + Dir: directory, + Prefix: "", + IndexFile: "index.html", + } +} + +func (s *Static) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + if r.Method != "GET" && r.Method != "HEAD" { + next(rw, r) + return + } + file := r.URL.Path + // if we have a prefix, filter requests by stripping the prefix + if s.Prefix != "" { + if !strings.HasPrefix(file, s.Prefix) { + next(rw, r) + return + } + file = file[len(s.Prefix):] + if file != "" && file[0] != '/' { + next(rw, r) + return + } + } + f, err := s.Dir.Open(file) + if err != nil { + // discard the error? + next(rw, r) + return + } + defer f.Close() + + fi, err := f.Stat() + if err != nil { + next(rw, r) + return + } + + // try to serve index file + if fi.IsDir() { + // redirect if missing trailing slash + if !strings.HasSuffix(r.URL.Path, "/") { + http.Redirect(rw, r, r.URL.Path+"/", http.StatusFound) + return + } + + file = path.Join(file, s.IndexFile) + f, err = s.Dir.Open(file) + if err != nil { + next(rw, r) + return + } + defer f.Close() + + fi, err = f.Stat() + if err != nil || fi.IsDir() { + next(rw, r) + return + } + } + + http.ServeContent(rw, r, file, fi.ModTime(), f) +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 5376e93..fcf878a 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -2,6 +2,18 @@ "comment": "", "ignore": "test", "package": [ + { + "checksumSHA1": "g/V4qrXjUGG9B+e3hB+4NAYJ5Gs=", + "path": "github.com/gorilla/context", + "revision": "08b5f424b9271eedf6f9f0ce86cb9396ed337a42", + "revisionTime": "2016-08-17T18:46:32Z" + }, + { + "checksumSHA1": "41syjEeyv9W/6j89XArd1yyWNBU=", + "path": "github.com/gorilla/pat", + "revision": "cf955c3d1f2c27ee96f93e9738085c762ff5f49d", + "revisionTime": "2016-04-13T04:16:32Z" + }, { "checksumSHA1": "ynJSWoF6v+3zMnh9R0QmmG6iGV8=", "path": "github.com/pkg/errors", @@ -13,6 +25,12 @@ "path": "github.com/urfave/cli", "revision": "d86a009f5e13f83df65d0d6cee9a2e3f1445f0da", "revisionTime": "2016-11-02T13:18:01Z" + }, + { + "checksumSHA1": "X2ZRQ4fqi/jVJSZcc2ttuHO33Ek=", + "path": "github.com/urfave/negroni", + "revision": "e0e50f7dc431c043cb33f91b09c3419d48b7cff5", + "revisionTime": "2016-11-02T02:38:13Z" } ], "rootPath": "git.xbudex.com/buddy/what-is-my-ip"