pax_global_header00006660000000000000000000000064127143665750014532gustar00rootroot0000000000000052 comment=fde5e16d32adc7ad637e9cd9ad21d4ebc6192535 negroni-0.2.0/000077500000000000000000000000001271436657500131725ustar00rootroot00000000000000negroni-0.2.0/CHANGELOG.md000066400000000000000000000014641271436657500150100ustar00rootroot00000000000000# Change Log **ATTN**: This project uses [semantic versioning](http://semver.org/). ## [Unreleased] ## [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/codegangsta/negroni/compare/v0.2.0...HEAD [0.2.0]: https://github.com/codegangsta/negroni/compare/v0.1.0...v0.2.0 negroni-0.2.0/LICENSE000066400000000000000000000020671271436657500142040ustar00rootroot00000000000000The 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. negroni-0.2.0/README.md000066400000000000000000000225471271436657500144630ustar00rootroot00000000000000# Negroni [![GoDoc](https://godoc.org/github.com/codegangsta/negroni?status.svg)](http://godoc.org/github.com/codegangsta/negroni) [![wercker status](https://app.wercker.com/status/13688a4a94b82d84a0b8d038c4965b61/s "wercker status")](https://app.wercker.com/project/bykey/13688a4a94b82d84a0b8d038c4965b61) [![codebeat](https://codebeat.co/badges/47d320b1-209e-45e8-bd99-9094bc5111e2)](https://codebeat.co/projects/github-com-codegangsta-negroni) 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: * [Português Brasileiro (pt_BR)](translations/README_pt_br.md) * [繁體中文 (zh_tw)](translations/README_zh_tw.md) * [简体中文 (zh_cn)](translations/README_zh_cn.md) * [German (de_DE)](translations/README_de_de.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 ( "github.com/codegangsta/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() // Includes some default middlewares n.UseHandler(mux) http.ListenAndServe(":3000", n) } ~~~ Then install the Negroni package (**go 1.1** and greater is required): ~~~ go get github.com/codegangsta/negroni ~~~ Then run your server: ~~~ go run server.go ~~~ You will now have a Go net/http webserver running on `localhost:3000`. ## Need Help? If you have a question or feature request, [go ask the mailing list](https://groups.google.com/forum/#!forum/negroni-users). The GitHub issues for Negroni will be used exclusively for bug reports and pull requests. ## Is Negroni a Framework? Negroni is **not** a framework. It is a 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, Negroni tries to play well with all of them by fully supporting `net/http`. For instance, integrating with [Gorilla Mux](https://github.com/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(":3000", n) ~~~ ## `negroni.Classic()` `negroni.Classic()` provides some default middleware that is useful for most applications: * `negroni.Recovery` - Panic Recovery Middleware. * `negroni.Logger` - Request/Response Logger Middleware. * `negroni.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](http://golang.org/pkg/net/http#ListenAndServe). ~~~ go n := negroni.Classic() n.Run(":8080") ~~~ In general, you will want to use `net/http` methods and just pass `negroni` has a handler as this is more flexible. E.g. ~~~ go 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](http://github.com/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), )) ~~~ ## 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 | | -----------|--------|-------------| | [RestGate](https://github.com/pjebs/restgate) | [Prasanga Siripala](https://github.com/pjebs) | Secure authentication for REST API endpoints | | [Graceful](https://github.com/tylerb/graceful) | [Tyler Bunnell](https://github.com/tylerb) | Graceful HTTP Shutdown | | [secure](https://github.com/unrolled/secure) | [Cory Jacobsen](https://github.com/unrolled) | Middleware that implements a few quick security wins | | [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| | [binding](https://github.com/mholt/binding) | [Matt Holt](https://github.com/mholt) | Data binding from HTTP requests into structs | | [logrus](https://github.com/meatballhat/negroni-logrus) | [Dan Buch](https://github.com/meatballhat) | Logrus-based logger | | [render](https://github.com/unrolled/render) | [Cory Jacobsen](https://github.com/unrolled) | Render JSON, XML and HTML templates | | [gorelic](https://github.com/jingweno/negroni-gorelic) | [Jingwen Owen Ou](https://github.com/jingweno) | New Relic agent for Go runtime | | [gzip](https://github.com/phyber/negroni-gzip) | [phyber](https://github.com/phyber) | GZIP response compression | | [oauth2](https://github.com/goincremental/negroni-oauth2) | [David Bochenski](https://github.com/bochenski) | oAuth2 middleware | | [sessions](https://github.com/goincremental/negroni-sessions) | [David Bochenski](https://github.com/bochenski) | Session Management | | [permissions2](https://github.com/xyproto/permissions2) | [Alexander Rødseth](https://github.com/xyproto) | Cookies, users and permissions | | [onthefly](https://github.com/xyproto/onthefly) | [Alexander Rødseth](https://github.com/xyproto) | Generate TinySVG, HTML and CSS on the fly | | [cors](https://github.com/rs/cors) | [Olivier Poitrey](https://github.com/rs) | [Cross Origin Resource Sharing](http://www.w3.org/TR/cors/) (CORS) support | | [xrequestid](https://github.com/pilu/xrequestid) | [Andrea Franz](https://github.com/pilu) | Middleware that assigns a random X-Request-Id header to each request | | [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 | | [stats](https://github.com/thoas/stats) | [Florent Messa](https://github.com/thoas) | Store information about your web application (response time, etc.) | | [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 | | [delay](https://github.com/jeffbmartinez/delay) | [Jeff Martinez](https://github.com/jeffbmartinez) | Add delays/latency to endpoints. Useful when testing effects of high latency | ## 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/) negroni-0.2.0/doc.go000066400000000000000000000013101271436657500142610ustar00rootroot00000000000000// 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/codegangsta/negroni // // package main // // import ( // "github.com/codegangsta/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 negroni-0.2.0/logger.go000066400000000000000000000013171271436657500150020ustar00rootroot00000000000000package negroni import ( "log" "net/http" "os" "time" ) // Logger is a middleware handler that logs the request as it goes in and the response as it goes out. type Logger struct { // Logger inherits from log.Logger used to log messages with the Logger middleware *log.Logger } // 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)) } negroni-0.2.0/logger_test.go000066400000000000000000000012111271436657500160320ustar00rootroot00000000000000package negroni import ( "bytes" "log" "net/http" "net/http/httptest" "testing" ) func Test_Logger(t *testing.T) { buff := bytes.NewBufferString("") recorder := httptest.NewRecorder() l := NewLogger() l.Logger = log.New(buff, "[negroni] ", 0) n := New() // replace log for testing n.Use(l) n.UseHandler(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { rw.WriteHeader(http.StatusNotFound) })) req, err := http.NewRequest("GET", "http://localhost:3000/foobar", nil) if err != nil { t.Error(err) } n.ServeHTTP(recorder, req) expect(t, recorder.Code, http.StatusNotFound) refute(t, len(buff.String()), 0) } negroni-0.2.0/negroni.go000066400000000000000000000101111271436657500151540ustar00rootroot00000000000000package 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{}, } } negroni-0.2.0/negroni_test.go000066400000000000000000000042141271436657500162220ustar00rootroot00000000000000package negroni import ( "net/http" "net/http/httptest" "reflect" "testing" ) /* Test Helpers */ func expect(t *testing.T, a interface{}, b interface{}) { if a != b { t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) } } func refute(t *testing.T, a interface{}, b interface{}) { if a == b { t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) } } func TestNegroniRun(t *testing.T) { // just test that Run doesn't bomb go New().Run(":3000") } func TestNegroniServeHTTP(t *testing.T) { result := "" response := httptest.NewRecorder() n := New() n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "foo" next(rw, r) result += "ban" })) n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "bar" next(rw, r) result += "baz" })) n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "bat" rw.WriteHeader(http.StatusBadRequest) })) n.ServeHTTP(response, (*http.Request)(nil)) expect(t, result, "foobarbatbazban") expect(t, response.Code, http.StatusBadRequest) } // Ensures that a Negroni middleware chain // can correctly return all of its handlers. func TestHandlers(t *testing.T) { response := httptest.NewRecorder() n := New() handlers := n.Handlers() expect(t, 0, len(handlers)) n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { rw.WriteHeader(http.StatusOK) })) // Expects the length of handlers to be exactly 1 // after adding exactly one handler to the middleware chain handlers = n.Handlers() expect(t, 1, len(handlers)) // Ensures that the first handler that is in sequence behaves // exactly the same as the one that was registered earlier handlers[0].ServeHTTP(response, (*http.Request)(nil), nil) expect(t, response.Code, http.StatusOK) } func TestNegroni_Use_Nil(t *testing.T) { defer func() { err := recover() if err == nil { t.Errorf("Expected negroni.Use(nil) to panic, but it did not") } }() n := New() n.Use(nil) } negroni-0.2.0/recovery.go000066400000000000000000000016521271436657500153630ustar00rootroot00000000000000package negroni import ( "fmt" "log" "net/http" "os" "runtime" ) // Recovery is a Negroni middleware that recovers from any panics and writes a 500 if there was one. type Recovery struct { Logger *log.Logger PrintStack bool 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 { 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) } } }() next(rw, r) } negroni-0.2.0/recovery_test.go000066400000000000000000000011341271436657500164150ustar00rootroot00000000000000package negroni import ( "bytes" "log" "net/http" "net/http/httptest" "testing" ) func TestRecovery(t *testing.T) { buff := bytes.NewBufferString("") recorder := httptest.NewRecorder() rec := NewRecovery() rec.Logger = log.New(buff, "[negroni] ", 0) n := New() // replace log for testing n.Use(rec) n.UseHandler(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { panic("here is a panic!") })) n.ServeHTTP(recorder, (*http.Request)(nil)) expect(t, recorder.Code, http.StatusInternalServerError) refute(t, recorder.Body.Len(), 0) refute(t, len(buff.String()), 0) } negroni-0.2.0/response_writer.go000066400000000000000000000050321271436657500167530ustar00rootroot00000000000000package 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 0 if the response has not been written. 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 { return &responseWriter{ ResponseWriter: rw, status: http.StatusOK, size: 0, beforeFuncs: nil} } 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) CloseNotify() <-chan bool { return rw.ResponseWriter.(http.CloseNotifier).CloseNotify() } 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 { flusher.Flush() } } negroni-0.2.0/response_writer_test.go000066400000000000000000000065311271436657500200170ustar00rootroot00000000000000package negroni import ( "bufio" "net" "net/http" "net/http/httptest" "testing" "time" ) type closeNotifyingRecorder struct { *httptest.ResponseRecorder closed chan bool } func newCloseNotifyingRecorder() *closeNotifyingRecorder { return &closeNotifyingRecorder{ httptest.NewRecorder(), make(chan bool, 1), } } func (c *closeNotifyingRecorder) close() { c.closed <- true } func (c *closeNotifyingRecorder) CloseNotify() <-chan bool { return c.closed } type hijackableResponse struct { Hijacked bool } func newHijackableResponse() *hijackableResponse { return &hijackableResponse{} } func (h *hijackableResponse) Header() http.Header { return nil } func (h *hijackableResponse) Write(buf []byte) (int, error) { return 0, nil } func (h *hijackableResponse) WriteHeader(code int) {} func (h *hijackableResponse) Flush() {} func (h *hijackableResponse) Hijack() (net.Conn, *bufio.ReadWriter, error) { h.Hijacked = true return nil, nil, nil } func TestResponseWriterWritingString(t *testing.T) { rec := httptest.NewRecorder() rw := NewResponseWriter(rec) rw.Write([]byte("Hello world")) expect(t, rec.Code, rw.Status()) expect(t, rec.Body.String(), "Hello world") expect(t, rw.Status(), http.StatusOK) expect(t, rw.Size(), 11) expect(t, rw.Written(), true) } func TestResponseWriterWritingStrings(t *testing.T) { rec := httptest.NewRecorder() rw := NewResponseWriter(rec) rw.Write([]byte("Hello world")) rw.Write([]byte("foo bar bat baz")) expect(t, rec.Code, rw.Status()) expect(t, rec.Body.String(), "Hello worldfoo bar bat baz") expect(t, rw.Status(), http.StatusOK) expect(t, rw.Size(), 26) } func TestResponseWriterWritingHeader(t *testing.T) { rec := httptest.NewRecorder() rw := NewResponseWriter(rec) rw.WriteHeader(http.StatusNotFound) expect(t, rec.Code, rw.Status()) expect(t, rec.Body.String(), "") expect(t, rw.Status(), http.StatusNotFound) expect(t, rw.Size(), 0) } func TestResponseWriterBefore(t *testing.T) { rec := httptest.NewRecorder() rw := NewResponseWriter(rec) result := "" rw.Before(func(ResponseWriter) { result += "foo" }) rw.Before(func(ResponseWriter) { result += "bar" }) rw.WriteHeader(http.StatusNotFound) expect(t, rec.Code, rw.Status()) expect(t, rec.Body.String(), "") expect(t, rw.Status(), http.StatusNotFound) expect(t, rw.Size(), 0) expect(t, result, "barfoo") } func TestResponseWriterHijack(t *testing.T) { hijackable := newHijackableResponse() rw := NewResponseWriter(hijackable) hijacker, ok := rw.(http.Hijacker) expect(t, ok, true) _, _, err := hijacker.Hijack() if err != nil { t.Error(err) } expect(t, hijackable.Hijacked, true) } func TestResponseWriteHijackNotOK(t *testing.T) { hijackable := new(http.ResponseWriter) rw := NewResponseWriter(*hijackable) hijacker, ok := rw.(http.Hijacker) expect(t, ok, true) _, _, err := hijacker.Hijack() refute(t, err, nil) } func TestResponseWriterCloseNotify(t *testing.T) { rec := newCloseNotifyingRecorder() rw := NewResponseWriter(rec) closed := false notifier := rw.(http.CloseNotifier).CloseNotify() rec.close() select { case <-notifier: closed = true case <-time.After(time.Second): } expect(t, closed, true) } func TestResponseWriterFlusher(t *testing.T) { rec := httptest.NewRecorder() rw := NewResponseWriter(rec) _, ok := rw.(http.Flusher) expect(t, ok, true) } negroni-0.2.0/static.go000066400000000000000000000032471271436657500150160ustar00rootroot00000000000000package negroni import ( "net/http" "path" "strings" ) // Static is a middleware handler that serves static files in the given directory/filesystem. 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) } negroni-0.2.0/static_test.go000066400000000000000000000045351271436657500160560ustar00rootroot00000000000000package negroni import ( "bytes" "net/http" "net/http/httptest" "testing" ) func TestStatic(t *testing.T) { response := httptest.NewRecorder() response.Body = new(bytes.Buffer) n := New() n.Use(NewStatic(http.Dir("."))) req, err := http.NewRequest("GET", "http://localhost:3000/negroni.go", nil) if err != nil { t.Error(err) } n.ServeHTTP(response, req) expect(t, response.Code, http.StatusOK) expect(t, response.Header().Get("Expires"), "") if response.Body.Len() == 0 { t.Errorf("Got empty body for GET request") } } func TestStaticHead(t *testing.T) { response := httptest.NewRecorder() response.Body = new(bytes.Buffer) n := New() n.Use(NewStatic(http.Dir("."))) n.UseHandler(http.NotFoundHandler()) req, err := http.NewRequest("HEAD", "http://localhost:3000/negroni.go", nil) if err != nil { t.Error(err) } n.ServeHTTP(response, req) expect(t, response.Code, http.StatusOK) if response.Body.Len() != 0 { t.Errorf("Got non-empty body for HEAD request") } } func TestStaticAsPost(t *testing.T) { response := httptest.NewRecorder() n := New() n.Use(NewStatic(http.Dir("."))) n.UseHandler(http.NotFoundHandler()) req, err := http.NewRequest("POST", "http://localhost:3000/negroni.go", nil) if err != nil { t.Error(err) } n.ServeHTTP(response, req) expect(t, response.Code, http.StatusNotFound) } func TestStaticBadDir(t *testing.T) { response := httptest.NewRecorder() n := Classic() n.UseHandler(http.NotFoundHandler()) req, err := http.NewRequest("GET", "http://localhost:3000/negroni.go", nil) if err != nil { t.Error(err) } n.ServeHTTP(response, req) refute(t, response.Code, http.StatusOK) } func TestStaticOptionsServeIndex(t *testing.T) { response := httptest.NewRecorder() n := New() s := NewStatic(http.Dir(".")) s.IndexFile = "negroni.go" n.Use(s) req, err := http.NewRequest("GET", "http://localhost:3000/", nil) if err != nil { t.Error(err) } n.ServeHTTP(response, req) expect(t, response.Code, http.StatusOK) } func TestStaticOptionsPrefix(t *testing.T) { response := httptest.NewRecorder() n := New() s := NewStatic(http.Dir(".")) s.Prefix = "/public" n.Use(s) // Check file content behaviour req, err := http.NewRequest("GET", "http://localhost:3000/public/negroni.go", nil) if err != nil { t.Error(err) } n.ServeHTTP(response, req) expect(t, response.Code, http.StatusOK) } negroni-0.2.0/translations/000077500000000000000000000000001271436657500157135ustar00rootroot00000000000000negroni-0.2.0/translations/README_de_de.md000066400000000000000000000201751271436657500203170ustar00rootroot00000000000000# Negroni [![GoDoc](https://godoc.org/github.com/codegangsta/negroni?status.svg)](http://godoc.org/github.com/codegangsta/negroni) [![wercker status](https://app.wercker.com/status/13688a4a94b82d84a0b8d038c4965b61/s "wercker status")](https://app.wercker.com/project/bykey/13688a4a94b82d84a0b8d038c4965b61) Negroni ist ein Ansatz für eine idiomatische Middleware in Go. Sie ist klein, nicht-intrusiv und unterstützt die Nutzung von `net/http` Handlern. Wenn Dir die Idee hinter [Martini](http://github.com/go-martini/martini) gefällt, aber Du denkst, es stecke zu viel Magie darin, dann ist Negroni eine passende Alternative. ## Wo fange ich an? Nachdem Du Go installiert und den [GOPATH](http://golang.org/doc/code.html#GOPATH) eingerichtet hast, erstelle eine `.go`-Datei. Nennen wir sie `server.go`. ~~~ go package main import ( "github.com/codegangsta/negroni" "net/http" "fmt" ) func main() { mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { fmt.Fprintf(w, "Willkommen auf der Homepage!") }) n := negroni.Classic() n.UseHandler(mux) n.Run(":3000") } ~~~ Installiere nun das Negroni Package (**go 1.1** und höher werden vorausgesetzt): ~~~ go get github.com/codegangsta/negroni ~~~ Dann starte Deinen Server: ~~~ go run server.go ~~~ Nun läuft ein `net/http`-Webserver von Go unter `localhost:3000`. ## Hilfe benötigt? Wenn Du eine Frage hast oder Dir ein bestimmte Funktion wünscht, nutze die [Mailing Liste](https://groups.google.com/forum/#!forum/negroni-users). Issues auf Github werden ausschließlich für Bug Reports und Pull Requests genutzt. ## Ist Negroni ein Framework? Negroni ist **kein** Framework. Es ist eine Bibliothek, geschaffen, um kompatibel mit `net/http` zu sein. ## Routing? Negroni ist BYOR (Bring your own Router - Nutze Deinen eigenen Router). Die Go-Community verfügt bereits über eine Vielzahl von großartigen Routern. Negroni versucht möglichst alle zu unterstützen, indem es `net/http` vollständig unterstützt. Beispielsweise sieht eine Implementation mit [Gorilla Mux](http://github.com/gorilla/mux) folgendermaßen aus: ~~~ go router := mux.NewRouter() router.HandleFunc("/", HomeHandler) n := negroni.New(Middleware1, Middleware2) // Oder nutze eine Middleware mit der Use()-Funktion n.Use(Middleware3) // Der Router kommt als letztes n.UseHandler(router) n.Run(":3000") ~~~ ## `negroni.Classic()` `negroni.Classic()` stellt einige Standard-Middlewares bereit, die für die meisten Anwendungen von Nutzen ist: * `negroni.Recovery` - Middleware für Panic Recovery . * `negroni.Logging` - Anfrage/Rückmeldungs-Logging-Middleware. * `negroni.Static` - Ausliefern von statischen Dateien unter dem "public" Verzeichnis. Dies macht es wirklich einfach, mit den nützlichen Funktionen von Negroni zu starten. ## Handlers Negroni stellt einen bidirektionalen Middleware-Flow bereit. Dies wird durch das `negroni.Handler`-Interface erreicht: ~~~ go type Handler interface { ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) } ~~~ Wenn eine Middleware nicht bereits den ResponseWriter genutzt hat, sollte sie die nächste `http.HandlerFunc` in der Verkettung von Middlewares aufrufen und diese ausführen. Das kann von großem Nutzen sein: ~~~ go func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { // Mache etwas vor dem Aufruf next(rw, r) // Mache etwas nach dem Aufruf } ~~~ Und Du kannst eine Middleware durch die `Use`-Funktion der Verkettung von Middlewares zuordnen. ~~~ go n := negroni.New() n.Use(negroni.HandlerFunc(MyMiddleware)) ~~~ Stattdessen kannst Du auch herkömmliche `http.Handler` zuordnen: ~~~ go n := negroni.New() mux := http.NewServeMux() // Ordne Deine Routen zu n.UseHandler(mux) n.Run(":3000") ~~~ ## `Run()` Negroni hat eine nützliche Funktion namens `Run`. `Run` übernimmt eine Zeichenkette `addr` ähnlich wie [http.ListenAndServe](http://golang.org/pkg/net/http#ListenAndServe). ~~~ go n := negroni.Classic() // ... log.Fatal(http.ListenAndServe(":8080", n)) ~~~ ## Routenspezifische Middleware Wenn Du eine Gruppe von Routen hast, welche alle die gleiche Middleware ausführen müssen, kannst Du einfach eine neue Negroni-Instanz erstellen und sie als Route-Handler nutzen: ~~~ go router := mux.NewRouter() adminRoutes := mux.NewRouter() // Füge die Admin-Routen hier hinzu // Erstelle eine neue Negroni-Instanz für die Admin-Middleware router.Handle("/admin", negroni.New( Middleware1, Middleware2, negroni.Wrap(adminRoutes), )) ~~~ ## Middlewares von Dritten Hier ist eine aktuelle Liste von Middlewares, die kompatible mit Negroni sind. Tue Dir keinen Zwang an, Dich einzutragen, wenn Du selbst eine Middleware programmiert hast: | Middleware | Autor | Beschreibung | | -----------|--------|-------------| | [RestGate](https://github.com/pjebs/restgate) | [Prasanga Siripala](https://github.com/pjebs) | Sichere Authentifikation für Endpunkte einer REST API | | [Graceful](https://github.com/stretchr/graceful) | [Tyler Bunnell](https://github.com/tylerb) | Graceful HTTP Shutdown | | [secure](https://github.com/unrolled/secure) | [Cory Jacobsen](https://github.com/unrolled) | Eine Middleware mit ein paar nützlichen Sicherheitseinstellungen | | [JWT Middleware](https://github.com/auth0/go-jwt-middleware) | [Auth0](https://github.com/auth0) | Eine Middleware die nach JWTs im `Authorization`-Feld des Header sucht und sie dekodiert.| | [binding](https://github.com/mholt/binding) | [Matt Holt](https://github.com/mholt) | Data Binding von HTTP-Anfragen in Structs | | [logrus](https://github.com/meatballhat/negroni-logrus) | [Dan Buch](https://github.com/meatballhat) | Logrus-basierender Logger | | [render](https://github.com/unrolled/render) | [Cory Jacobsen](https://github.com/unrolled) | Rendere JSON, XML und HTML Vorlagen | | [gorelic](https://github.com/jingweno/negroni-gorelic) | [Jingwen Owen Ou](https://github.com/jingweno) | New Relic Agent für die Go-Echtzeitumgebung | | [gzip](https://github.com/phyber/negroni-gzip) | [phyber](https://github.com/phyber) | Kompression von HTTP-Rückmeldungen via GZIP | | [oauth2](https://github.com/goincremental/negroni-oauth2) | [David Bochenski](https://github.com/bochenski) | oAuth2 Middleware | | [sessions](https://github.com/goincremental/negroni-sessions) | [David Bochenski](https://github.com/bochenski) | Session Management | | [permissions2](https://github.com/xyproto/permissions2) | [Alexander Rødseth](https://github.com/xyproto) | Cookies, Benutzer und Berechtigungen | | [onthefly](https://github.com/xyproto/onthefly) | [Alexander Rødseth](https://github.com/xyproto) | Generiere TinySVG, HTML und CSS spontan | | [cors](https://github.com/rs/cors) | [Olivier Poitrey](https://github.com/rs) | [Cross Origin Resource Sharing](http://www.w3.org/TR/cors/) (CORS) Unterstützung | | [xrequestid](https://github.com/pilu/xrequestid) | [Andrea Franz](https://github.com/pilu) | Eine Middleware die zufällige X-Request-Id-Header jedem Request anfügt | | [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-basierte Middleware zur Authentifikation | | [stats](https://github.com/thoas/stats) | [Florent Messa](https://github.com/thoas) | Speichere wichtige Informationen über Deine Webanwendung (Reaktionszeit, etc.) | ## Beispiele [Alexander Rødseth](https://github.com/xyproto) programmierte [mooseware](https://github.com/xyproto/mooseware), ein Grundgerüst zum Erstellen von Negroni Middleware-Handerln. ## Aktualisieren in Echtzeit? [gin](https://github.com/codegangsta/gin) und [fresh](https://github.com/pilu/fresh) aktualisieren Deine Negroni-Anwendung automatisch. ## Unverzichbare Informationen für Go- & Negronineulinge * [Nutze einen Kontext zum Übertragen von Middlewareinformationen an Handler (Englisch)](http://elithrar.github.io/article/map-string-interface/) * [Middlewares verstehen (Englisch)](http://mattstauffer.co/blog/laravel-5.0-middleware-replacing-filters) ## Über das Projekt Negroni wurde obsseziv von Niemand gerigeren als dem [Code Gangsta](http://codegangsta.io/) entwickelt. negroni-0.2.0/translations/README_pt_br.md000066400000000000000000000154161271436657500203670ustar00rootroot00000000000000# Negroni [![GoDoc](https://godoc.org/github.com/codegangsta/negroni?status.svg)](http://godoc.org/github.com/codegangsta/negroni) [![wercker status](https://app.wercker.com/status/13688a4a94b82d84a0b8d038c4965b61/s "wercker status")](https://app.wercker.com/project/bykey/13688a4a94b82d84a0b8d038c4965b61) Negroni é uma abordagem idiomática para middleware web em Go. É pequeno, não intrusivo, e incentiva uso da biblioteca `net/http`. Se gosta da idéia do [Martini](http://github.com/go-martini/martini), mas acha que contém muita mágica, então Negroni é ideal. ## Começando Depois de instalar Go e definir seu [GOPATH](http://golang.org/doc/code.html#GOPATH), criar seu primeirto arquivo `.go`. Iremos chamá-lo `server.go`. ~~~ go package main import ( "github.com/codegangsta/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") } ~~~ Depois instale o pacote Negroni (**go 1.1** ou superior) ~~~ go get github.com/codegangsta/negroni ~~~ Depois execute seu servidor: ~~~ go run server.go ~~~ Agora terá um servidor web Go net/http rodando em `localhost:3000`. ## Precisa de Ajuda? Se você tem uma pergunta ou pedido de recurso,[go ask the mailing list](https://groups.google.com/forum/#!forum/negroni-users). O Github issues para o Negroni será usado exclusivamente para Reportar bugs e pull requests. ## Negroni é um Framework? Negroni **não** é a framework. É uma biblioteca que é desenhada para trabalhar diretamente com net/http. ## Roteamento? Negroni é TSPR(Traga seu próprio Roteamento). A comunidade Go já tem um grande número de roteadores http disponíveis, Negroni tenta rodar bem com todos eles pelo suporte total `net/http`/ Por exemplo, a integração com [Gorilla Mux](http://github.com/gorilla/mux) se parece com isso: ~~~ 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) n.Run(":3000") ~~~ ## `negroni.Classic()` `negroni.Classic()` fornece alguns middlewares padrão que são úteis para maioria das aplicações: * `negroni.Recovery` - Panic Recovery Middleware. * `negroni.Logging` - Request/Response Logging Middleware. * `negroni.Static` - Static File serving under the "public" directory. Isso torna muito fácil começar com alguns recursos úteis do Negroni. ## Handlers Negroni fornece um middleware de fluxo bidirecional. Isso é feito através da interface `negroni.Handler`: ~~~ go type Handler interface { ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) } ~~~ Se um middleware não tenha escrito o ResponseWriter, ele deve chamar a próxima `http.HandlerFunc` na cadeia para produzir o próximo handler middleware. Isso pode ser usado muito bem: ~~~ go func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { // do some stuff before next(rw, r) // do some stuff after } ~~~ E pode mapear isso para a cadeia de handler com a função `Use`: ~~~ go n := negroni.New() n.Use(negroni.HandlerFunc(MyMiddleware)) ~~~ Você também pode mapear `http.Handler` antigos: ~~~ go n := negroni.New() mux := http.NewServeMux() // map your routes n.UseHandler(mux) n.Run(":3000") ~~~ ## `Run()` Negroni tem uma função de conveniência chamada `Run`. `Run` pega um endereço de string idêntico para [http.ListenAndServe](http://golang.org/pkg/net/http#ListenAndServe). ~~~ go n := negroni.Classic() // ... log.Fatal(http.ListenAndServe(":8080", n)) ~~~ ## Middleware para Rotas Específicas Se você tem um grupo de rota com rotas que precisam ser executadas por um middleware específico, pode simplesmente criar uma nova instância de Negroni e usar no seu Manipulador de rota. ~~~ go router := mux.NewRouter() adminRoutes := mux.NewRouter() // add admin routes here // Criar um middleware negroni para admin router.Handle("/admin", negroni.New( Middleware1, Middleware2, negroni.Wrap(adminRoutes), )) ~~~ ## Middleware de Terceiros Aqui está uma lista atual de Middleware Compatíveis com Negroni. Sinta se livre para mandar um PR vinculando seu middleware se construiu um: | Middleware | Autor | Descrição | | -----------|--------|-------------| | [Graceful](https://github.com/stretchr/graceful) | [Tyler Bunnell](https://github.com/tylerb) | Graceful HTTP Shutdown | | [secure](https://github.com/unrolled/secure) | [Cory Jacobsen](https://github.com/unrolled) | Implementa rapidamente itens de segurança.| | [binding](https://github.com/mholt/binding) | [Matt Holt](https://github.com/mholt) | Handler para mapeamento/validação de um request a estrutura. | | [logrus](https://github.com/meatballhat/negroni-logrus) | [Dan Buch](https://github.com/meatballhat) | Logrus-based logger | | [render](https://github.com/unrolled/render) | [Cory Jacobsen](https://github.com/unrolled) | Pacote para renderizar JSON, XML, e templates HTML. | | [gorelic](https://github.com/jingweno/negroni-gorelic) | [Jingwen Owen Ou](https://github.com/jingweno) | New Relic agent for Go runtime | | [gzip](https://github.com/phyber/negroni-gzip) | [phyber](https://github.com/phyber) | Handler para adicionar compreção gzip para as requisições | | [oauth2](https://github.com/goincremental/negroni-oauth2) | [David Bochenski](https://github.com/bochenski) | Handler que prove sistema de login OAuth 2.0 para aplicações Martini. Google Sign-in, Facebook Connect e Github login são suportados. | | [sessions](https://github.com/goincremental/negroni-sessions) | [David Bochenski](https://github.com/bochenski) | Handler que provê o serviço de sessão. | | [permissions](https://github.com/xyproto/permissions) | [Alexander Rødseth](https://github.com/xyproto) | Cookies, usuários e permissões. | | [onthefly](https://github.com/xyproto/onthefly) | [Alexander Rødseth](https://github.com/xyproto) | Pacote para gerar TinySVG, HTML e CSS em tempo real. | ## Exemplos [Alexander Rødseth](https://github.com/xyproto) criou [mooseware](https://github.com/xyproto/mooseware), uma estrutura para escrever um handler middleware Negroni. ## Servidor com autoreload? [gin](https://github.com/codegangsta/gin) e [fresh](https://github.com/pilu/fresh) são aplicativos para autoreload do Negroni. ## Leitura Essencial para Iniciantes em Go & Negroni * [Usando um contexto para passar informação de um middleware para o manipulador final](http://elithrar.github.io/article/map-string-interface/) * [Entendendo middleware](http://mattstauffer.co/blog/laravel-5.0-middleware-replacing-filters) ## Sobre Negroni é obsessivamente desenhado por ninguém menos que [Code Gangsta](http://codegangsta.io/) negroni-0.2.0/translations/README_zh_cn.md000066400000000000000000000200651271436657500203560ustar00rootroot00000000000000# Negroni [![GoDoc](https://godoc.org/github.com/codegangsta/negroni?status.svg)](http://godoc.org/github.com/codegangsta/negroni) [![wercker status](https://app.wercker.com/status/13688a4a94b82d84a0b8d038c4965b61/s "wercker status")](https://app.wercker.com/project/bykey/13688a4a94b82d84a0b8d038c4965b61) 在Go语言里,Negroni 是一个很地道的 web 中间件,它是微型,非嵌入式,并鼓励使用原生 `net/http` 处理器的库。 如果你用过并喜欢 [Martini](http://github.com/go-martini/martini) 框架,但又不想框架中有太多魔幻性的特征,那 Negroni 就是你的菜了,相信它非常适合你。 语言翻译: * [Português Brasileiro (pt_BR)](translations/README_pt_br.md) * [简体中文 (zh_CN)](translations/README_zh_cn.md) ## 入门指导 当安装了 Go 语言并设置好了 [GOPATH](http://golang.org/doc/code.html#GOPATH) 后,新建你第一个`.go` 文件,我们叫它 `server.go` 吧。 ~~~ go package main import ( "github.com/codegangsta/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") } ~~~ 然后安装 Negroni 包(它依赖 **Go 1.1** 或更高的版本): ~~~ go get github.com/codegangsta/negroni ~~~ 然后运行刚建好的 server.go 文件: ~~~ go run server.go ~~~ 这时一个 Go `net/http` Web 服务器就跑在 `localhost:3000` 上,使用浏览器打开 `localhost:3000` 可以看到输出结果。 ## 需要你的贡献 如果你有问题或新想法,请到[邮件群组](https://groups.google.com/forum/#!forum/negroni-users)里反馈,GitHub issues 是专门给提交 bug 报告和 pull 请求用途的,欢迎你的参与。 ## Negroni 是一个框架吗? Negroni **不**是一个框架,它是为了方便使用 `net/http` 而设计的一个库而已。 ## 路由呢? Negroni 没有带路由功能,使用 Negroni 时,需要找一个适合你的路由。不过好在 Go 社区里已经有相当多可用的路由,Negroni 更喜欢和那些完全支持 `net/http` 库的路由组合使用,比如,结合 [Gorilla Mux](http://github.com/gorilla/mux) 使用像这样: ~~~ 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) n.Run(":3000") ~~~ ## `negroni.Classic()` 经典实例 `negroni.Classic()` 提供一些默认的中间件,这些中间件在多数应用都很有用。 * `negroni.Recovery` - 异常(恐慌)恢复中间件 * `negroni.Logging` - 请求 / 响应 log 日志中间件 * `negroni.Static` - 静态文件处理中间件,默认目录在 "public" 下. `negroni.Classic()` 让你一开始就非常容易上手 Negroni ,并使用它那些通用的功能。 ## Handlers (处理器) Negroni 提供双向的中间件机制,这个特征很棒,都是得益于 `negroni.Handler` 这个接口。 ~~~ go type Handler interface { ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) } ~~~ 如果一个中间件没有写入 ResponseWriter 响应,它会在中间件链里调用下一个 `http.HandlerFunc` 执行下去, 它可以这么优雅的使用。如下: ~~~ go func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { // do some stuff before next(rw, r) // do some stuff after } ~~~ 你也可以用 `Use` 函数把这些 `http.Handler` 处理器引进到处理器链上来: ~~~ go n := negroni.New() n.Use(negroni.HandlerFunc(MyMiddleware)) ~~~ 你还可以使用 `http.Handler`(s) 把 `http.Handler` 处理器引进来。 ~~~ go n := negroni.New() mux := http.NewServeMux() // map your routes n.UseHandler(mux) n.Run(":3000") ~~~ ## `Run()` Negroni 提供一个很好用的函数叫 `Run` ,把地址字符串传人该函数,即可实现很地道的 [http.ListenAndServe](http://golang.org/pkg/net/http#ListenAndServe) 函数功能了。 ~~~ go n := negroni.Classic() // ... log.Fatal(http.ListenAndServe(":8080", n)) ~~~ ## 特定路由中间件 如果你需要群组路由功能,需要借助特定的路由中间件完成,做法很简单,只需建立一个新 Negroni 实例,传人路由处理器里即可。 ~~~ go router := mux.NewRouter() adminRoutes := mux.NewRouter() // add admin routes here // Create a new negroni for the admin middleware router.Handle("/admin", negroni.New( Middleware1, Middleware2, negroni.Wrap(adminRoutes), )) ~~~ ## 第三方中间件 以下的兼容 Negroni 的中间件列表,如果你也有兼容 Negroni 的中间件,可以提交到这个列表来交换链接,我们很乐意做这样有益的事情。 | 中间件 | 作者 | 描述 | | -------------|------------|-------------| | [RestGate](https://github.com/pjebs/restgate) | [Prasanga Siripala](https://github.com/pjebs) | REST API 接口的安全认证 | | [Graceful](https://github.com/stretchr/graceful) | [Tyler Bunnell](https://github.com/tylerb) | 优雅关闭 HTTP 的中间件 | | [secure](https://github.com/unrolled/secure) | [Cory Jacobsen](https://github.com/unrolled) | Middleware that implements a few quick security wins | | [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| | [binding](https://github.com/mholt/binding) | [Matt Holt](https://github.com/mholt) | HTTP 请求数据注入到 structs 实体| | [logrus](https://github.com/meatballhat/negroni-logrus) | [Dan Buch](https://github.com/meatballhat) | 基于 Logrus-based logger 日志 | | [render](https://github.com/unrolled/render) | [Cory Jacobsen](https://github.com/unrolled) | 渲染 JSON, XML and HTML 中间件 | | [gorelic](https://github.com/jingweno/negroni-gorelic) | [Jingwen Owen Ou](https://github.com/jingweno) | New Relic agent for Go runtime | | [gzip](https://github.com/phyber/negroni-gzip) | [phyber](https://github.com/phyber) | 响应流 GZIP 压缩 | | [oauth2](https://github.com/goincremental/negroni-oauth2) | [David Bochenski](https://github.com/bochenski) | oAuth2 中间件 | | [sessions](https://github.com/goincremental/negroni-sessions) | [David Bochenski](https://github.com/bochenski) | Session 会话管理 | | [permissions2](https://github.com/xyproto/permissions2) | [Alexander Rødseth](https://github.com/xyproto) | Cookies, 用户和权限 | | [onthefly](https://github.com/xyproto/onthefly) | [Alexander Rødseth](https://github.com/xyproto) | 快速生成 TinySVG, HTML and CSS 中间件 | | [cors](https://github.com/rs/cors) | [Olivier Poitrey](https://github.com/rs) | [Cross Origin Resource Sharing](http://www.w3.org/TR/cors/) (CORS) support | | [xrequestid](https://github.com/pilu/xrequestid) | [Andrea Franz](https://github.com/pilu) | 给每个请求指定一个随机 X-Request-Id 头的中间件 | | [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 鉴权认证的中间件 | | [stats](https://github.com/thoas/stats) | [Florent Messa](https://github.com/thoas) | 检测 web 应用当前运行状态信息 (响应时间等等。) | ## 范例 [Alexander Rødseth](https://github.com/xyproto) 创建的 [mooseware](https://github.com/xyproto/mooseware) 是一个写兼容 Negroni 中间件的处理器骨架的范例。 ## 即时编译 [gin](https://github.com/codegangsta/gin) 和 [fresh](https://github.com/pilu/fresh) 这两个应用是即时编译的 Negroni 工具,推荐用户开发的时候使用。 ## Go & Negroni 初学者必读推荐 * [在中间件中使用上下文把消息传递给后端处理器](http://elithrar.github.io/article/map-string-interface/) * [了解中间件](http://mattstauffer.co/blog/laravel-5.0-middleware-replacing-filters) ## 关于 Negroni 由 [Code Gangsta](http://codegangsta.io/) 主导设计开发完成 negroni-0.2.0/translations/README_zh_tw.md000066400000000000000000000160741271436657500204150ustar00rootroot00000000000000# Negroni(尼格龍尼) [![GoDoc](https://godoc.org/github.com/codegangsta/negroni?status.svg)](http://godoc.org/github.com/codegangsta/negroni) [![wercker status](https://app.wercker.com/status/13688a4a94b82d84a0b8d038c4965b61/s "wercker status")](https://app.wercker.com/project/bykey/13688a4a94b82d84a0b8d038c4965b61) 尼格龍尼符合Go的web 中介器特性. 精簡、非侵入式、鼓勵使用 `net/http` Handler. 如果你喜歡[Martini](http://github.com/go-martini/martini),但覺得這其中包太多神奇的功能,那麼尼格龍尼會是你的最佳選擇。 ## 入門 安裝完Go且設好[GOPATH](http://golang.org/doc/code.html#GOPATH),建立你的第一個`.go`檔。可以命名為`server.go`。 ~~~ go package main import ( "github.com/codegangsta/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") } ~~~ 安裝尼格龍尼套件 (最低需求為**go 1.1**或更高版本): ~~~ go get github.com/codegangsta/negroni ~~~ 執行伺服器: ~~~ go run server.go ~~~ 你現在起了一個Go的net/http網頁伺服器在`localhost:3000`. ## 有問題? 如果你有問題或新功能建議,[到這郵件群組討論](https://groups.google.com/forum/#!forum/negroni-users)。尼格龍尼在GitHub上的issues專欄是專門用來回報bug跟pull requests。 ## 尼格龍尼是個framework嗎? 尼格龍尼**不是**framework,是個設計用來直接使用net/http的library。 ## 路由? 尼格龍尼是BYOR (Bring your own Router,帶給你自訂路由)。在Go社群已經有大量可用的http路由器, 尼格龍尼試著做好完全支援`net/http`,例如與[Gorilla Mux](http://github.com/gorilla/mux)整合: ~~~ go router := mux.NewRouter() router.HandleFunc("/", HomeHandler) n := negroni.New(中介器1, 中介器2) // Or use a 中介器 with the Use() function n.Use(中介器3) // router goes last n.UseHandler(router) n.Run(":3000") ~~~ ## `negroni.Classic()` `negroni.Classic()` 提供一些好用的預設中介器: * `negroni.Recovery` - Panic 還原中介器 * `negroni.Logging` - Request/Response 紀錄中介器 * `negroni.Static` - 在"public"目錄下的靜態檔案服務 尼格龍尼的這些功能讓你開發變得很簡單。 ## 處理器(Handlers) 尼格龍尼提供一個雙向中介器的機制,介面為`negroni.Handler`: ~~~ go type Handler interface { ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) } ~~~ 如果中介器沒有寫入ResponseWriter,會呼叫通道裡面的下個`http.HandlerFunc`讓給中介處理器。可以被用來做良好的應用: ~~~ go func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { // 在這之前做一些事 next(rw, r) // 在這之後做一些事 } ~~~ 然後你可以透過`Use`函數對應到處理器的通道: ~~~ go n := negroni.New() n.Use(negroni.HandlerFunc(MyMiddleware)) ~~~ 你也可以應原始的舊`http.Handler`: ~~~ go n := negroni.New() mux := http.NewServeMux() // map your routes n.UseHandler(mux) n.Run(":3000") ~~~ ## `Run()` 尼格龍尼有一個很好用的函數`Run`,`Run`接收addr字串辨識[http.ListenAndServe](http://golang.org/pkg/net/http#ListenAndServe)。 ~~~ go n := negroni.Classic() // ... log.Fatal(http.ListenAndServe(":8080", n)) ~~~ ## 路由特有中介器 如果你有一群路由需要執行特別的中介器,你可以簡單的建立一個新的尼格龍尼實體當作路由處理器。 ~~~ go router := mux.NewRouter() adminRoutes := mux.NewRouter() // add admin routes here // 為管理中介器建立一個新的尼格龍尼 router.Handle("/admin", negroni.New( Middleware1, Middleware2, negroni.Wrap(adminRoutes), )) ~~~ ## 第三方中介器 以下為目前尼格龍尼兼容的中介器清單。如果你自己做了一個中介器請自由放入你的中介器互換連結: | 中介器 | 作者 | 說明 | | -----------|--------|-------------| | [RestGate](https://github.com/pjebs/restgate) | [Prasanga Siripala](https://github.com/pjebs) | REST API入口的安全認證 | | [Graceful](https://github.com/stretchr/graceful) | [Tyler Bunnell](https://github.com/tylerb) | 優雅的HTTP關機 | | [secure](https://github.com/unrolled/secure) | [Cory Jacobsen](https://github.com/unrolled) | 檢疫安全功能的中介器 | | [JWT Middleware](https://github.com/auth0/go-jwt-middleware) | [Auth0](https://github.com/auth0) | 檢查JWT的中介器用來解析傳入請求的`Authorization` header | | [binding](https://github.com/mholt/binding) | [Matt Holt](https://github.com/mholt) | 將HTTP請求轉到structs的資料綁定 | | [logrus](https://github.com/meatballhat/negroni-logrus) | [Dan Buch](https://github.com/meatballhat) | 基於Logrus的紀錄器 | | [render](https://github.com/unrolled/render) | [Cory Jacobsen](https://github.com/unrolled) | 渲染JSON、XML、HTML的樣板 | | [gorelic](https://github.com/jingweno/negroni-gorelic) | [Jingwen Owen Ou](https://github.com/jingweno) | Go執行中的New Relic agent | | [gzip](https://github.com/phyber/negroni-gzip) | [phyber](https://github.com/phyber) | GZIP回應壓縮 | | [oauth2](https://github.com/goincremental/negroni-oauth2) | [David Bochenski](https://github.com/bochenski) | oAuth2中介器 | | [sessions](https://github.com/goincremental/negroni-sessions) | [David Bochenski](https://github.com/bochenski) | Session管理 | | [permissions2](https://github.com/xyproto/permissions2) | [Alexander Rødseth](https://github.com/xyproto) | Cookies與使用者權限 | | [onthefly](https://github.com/xyproto/onthefly) | [Alexander Rødseth](https://github.com/xyproto) | 快速產生TinySVG、HTM、CSS | | [cors](https://github.com/rs/cors) | [Olivier Poitrey](https://github.com/rs) | [Cross Origin Resource Sharing](http://www.w3.org/TR/cors/) 支援(CORS) | | [xrequestid](https://github.com/pilu/xrequestid) | [Andrea Franz](https://github.com/pilu) | 在每個request指定一個隨機X-Request-Id header的中介器 | | [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 授權中介器 | | [stats](https://github.com/thoas/stats) | [Florent Messa](https://github.com/thoas) | 儲存關於你的網頁應用資訊 (回應時間之類) | ## 範例 [mooseware](https://github.com/xyproto/mooseware)是用來寫尼格龍尼中介處理器的骨架,由[Alexander Rødseth](https://github.com/xyproto)建立。 ## 即時程式重載? [gin](https://github.com/codegangsta/gin)和[fresh](https://github.com/pilu/fresh)兩個尼格龍尼即時重載的應用。 ## Go & 尼格龍尼初學者必讀 * [使用Context將資訊從中介器送到處理器](http://elithrar.github.io/article/map-string-interface/) * [理解中介器](http://mattstauffer.co/blog/laravel-5.0-middleware-replacing-filters) ## 關於 尼格龍尼正是[Code Gangsta](http://codegangsta.io/)的執著設計。 譯者: Festum Qin (Festum@G.PL)