Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The LUCI Authors. All rights reserved. | 1 // Copyright 2015 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 // Package middleware defines base type for context-aware HTTP request handler. | 5 // Package middleware defines base type for context-aware HTTP request handler. |
| 6 // See appengine/middleware for examples of how to use it in GAE environment. | 6 // See appengine/middleware for examples of how to use it in GAE environment. |
| 7 package middleware | 7 package middleware |
| 8 | 8 |
| 9 import ( | 9 import ( |
| 10 "net/http" | 10 "net/http" |
| 11 | 11 |
| 12 "github.com/julienschmidt/httprouter" | 12 "github.com/julienschmidt/httprouter" |
| 13 "golang.org/x/net/context" | 13 "golang.org/x/net/context" |
| 14 ) | 14 ) |
| 15 | 15 |
| 16 // Handler is the type for all request handlers. Of particular note, it's the | 16 // Handler is the type for all request handlers. Of particular note, it's the |
| 17 // same as httprouter.Handle, except that it also has a context parameter. | 17 // same as httprouter.Handle, except that it also has a context parameter. |
| 18 type Handler func(context.Context, http.ResponseWriter, *http.Request, httproute r.Params) | 18 type Handler func(context.Context, http.ResponseWriter, *http.Request, httproute r.Params) |
| 19 | 19 |
| 20 // ChainedHandler is the same as Handler, except that it includes a Handler | |
| 21 // parameter that calls the next ChainedHandler in the middleware chain when inv oked. | |
| 22 type ChainedHandler func(context.Context, http.ResponseWriter, *http.Request, ht tprouter.Params, Handler) | |
|
nishanths
2016/06/09 04:23:47
ChainedHandler can eventually be renamed to Handle
| |
| 23 | |
| 20 // Middleware takes a handler, wraps it with some additional logic, and returns | 24 // Middleware takes a handler, wraps it with some additional logic, and returns |
| 21 // resulting handler. | 25 // resulting handler. |
| 22 type Middleware func(Handler) Handler | 26 type Middleware func(Handler) Handler |
| 23 | 27 |
| 24 // Base is a start of the middlware chain. It sets up initial context with all | 28 // Chain contains a Handler and a pointer to the next element in the Chain. |
| 29 type Chain struct { | |
| 30 » Handler ChainedHandler | |
| 31 » next *Chain | |
| 32 } | |
| 33 | |
| 34 // Handle calls the chain's Handler function after adding necessary arguments. | |
| 35 func (c *Chain) Handle(ctx context.Context, wr http.ResponseWriter, r *http.Requ est, p httprouter.Params) { | |
| 36 » c.Handler(ctx, wr, r, p, c.next.Handle) | |
| 37 } | |
| 38 | |
| 39 // Add adds chains to an existing chain. | |
| 40 func (c *Chain) Add(chains ...Chain) { | |
| 41 » if len(chains) == 0 { | |
| 42 » » return | |
| 43 » } | |
| 44 » // TODO(nishanths): Hold a private reference to the tail *Chain in the | |
| 45 » // Chain struct to eliminate this loop. | |
| 46 » for ; c.next != nil; c = c.next { | |
| 47 » } | |
| 48 » c.next = &chains[0] | |
| 49 » chains[0].Add(chains[1:]...) | |
| 50 } | |
| 51 | |
| 52 // AddHandlers adds a list of ChainedHandlers to a Chain. | |
| 53 func (c *Chain) AddHandlers(handlers ...ChainedHandler) { | |
| 54 » chain := NewChain(handlers...) | |
| 55 » c.Add(chain) | |
| 56 } | |
| 57 | |
| 58 // NewChain creates a Chain from ChainedHandler list. | |
| 59 func NewChain(handlers ...ChainedHandler) Chain { | |
| 60 » if len(handlers) == 0 { | |
| 61 » » return voidChain() | |
| 62 » } | |
| 63 » next := NewChain(handlers[1:]...) | |
| 64 » return Chain{handlers[0], &next} | |
| 65 } | |
| 66 | |
| 67 // voidChain returns a Chain that has no Chain after it (that is, it's next | |
| 68 // field is nil). | |
| 69 func voidChain() Chain { | |
| 70 » return Chain{ | |
| 71 » » ChainedHandler(func(c context.Context, rw http.ResponseWriter, r *http.Request, p httprouter.Params, next Handler) {}), | |
| 72 » » nil, | |
| 73 » } | |
| 74 } | |
| 75 | |
| 76 // Base is a start of the middleware chain. It sets up initial context with all | |
| 25 // base services and passes it to the given handler. Return value of Base can | 77 // base services and passes it to the given handler. Return value of Base can |
| 26 // be plugged in into httprouter directly. | 78 // be plugged in into httprouter directly. |
| 27 type Base func(Handler) httprouter.Handle | 79 type Base func(Handler) httprouter.Handle |
| 28 | 80 |
| 29 // TestingBase is Base that passes given context to the handler. Useful in | 81 // TestingBase is Base that passes given context to the handler. Useful in |
| 30 // tests. | 82 // tests. |
| 31 func TestingBase(c context.Context) Base { | 83 func TestingBase(c context.Context) Base { |
| 32 return func(h Handler) httprouter.Handle { | 84 return func(h Handler) httprouter.Handle { |
| 33 return func(rw http.ResponseWriter, r *http.Request, p httproute r.Params) { | 85 return func(rw http.ResponseWriter, r *http.Request, p httproute r.Params) { |
| 34 h(c, rw, r, p) | 86 h(c, rw, r, p) |
| 35 } | 87 } |
| 36 } | 88 } |
| 37 } | 89 } |
| 38 | 90 |
| 39 // WithContextValue is a middleware that adds a value to the context before | 91 // WithContextValue is a middleware that adds a value to the context before |
| 40 // calling the handler. | 92 // calling the handler. |
| 41 func WithContextValue(h Handler, key, val interface{}) Handler { | 93 func WithContextValue(h Handler, key, val interface{}) Handler { |
| 42 return func(c context.Context, rw http.ResponseWriter, r *http.Request, p httprouter.Params) { | 94 return func(c context.Context, rw http.ResponseWriter, r *http.Request, p httprouter.Params) { |
| 43 h(context.WithValue(c, key, val), rw, r, p) | 95 h(context.WithValue(c, key, val), rw, r, p) |
| 44 } | 96 } |
| 45 } | 97 } |
| OLD | NEW |