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) | |
|
iannucci
2016/06/09 21:30:08
Since we have all the middleware in this repo, it
Vadim Sh.
2016/06/09 21:45:12
+1
Having both Handler and ChainedHandler is conf
nishanths
2016/06/13 17:30:44
I like this too. I've changed the router package t
| |
| 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 } | |
|
iannucci
2016/06/09 21:30:08
Why not just a []Handler? I think it could simplif
Vadim Sh.
2016/06/09 21:45:12
+1
since chains are append-only, it is even fine
nishanths
2016/06/13 17:30:44
Good point. The API primariy now uses router.Handl
| |
| 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 » if c.next != nil { | |
| 37 » » c.Handler(ctx, wr, r, p, c.next.Handle) | |
| 38 » } | |
| 39 } | |
| 40 | |
| 41 // Append adds chains to an existing chain and returns the result. | |
| 42 func (c Chain) Append(chains ...Chain) Chain { | |
| 43 » if len(chains) == 0 { | |
| 44 » » return c | |
| 45 » } | |
| 46 » // TODO(nishanths): Hold a private reference to the tail *Chain in the | |
| 47 » // Chain struct to eliminate this loop. | |
| 48 » for ; c.next != nil; c = *c.next { | |
| 49 » } | |
| 50 » c.next = &chains[0] | |
| 51 » return chains[0].Append(chains[1:]...) | |
| 52 } | |
| 53 | |
| 54 // AppendHandlers adds a list of ChainedHandlers to a Chain. | |
| 55 func (c Chain) AppendHandlers(handlers ...ChainedHandler) Chain { | |
| 56 » chain := NewChain(handlers...) | |
| 57 » return c.Append(chain) | |
| 58 } | |
| 59 | |
| 60 // NewChain creates a Chain from ChainedHandler list. | |
| 61 func NewChain(handlers ...ChainedHandler) Chain { | |
| 62 » if len(handlers) == 0 { | |
| 63 » » return Chain{handlers[0], nil} | |
| 64 » } | |
| 65 » next := NewChain(handlers[1:]...) | |
| 66 » return Chain{handlers[0], &next} | |
| 67 } | |
| 68 | |
| 69 // 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 | 70 // base services and passes it to the given handler. Return value of Base can |
| 26 // be plugged in into httprouter directly. | 71 // be plugged in into httprouter directly. |
| 27 type Base func(Handler) httprouter.Handle | 72 type Base func(Handler) httprouter.Handle |
| 28 | 73 |
| 29 // TestingBase is Base that passes given context to the handler. Useful in | 74 // TestingBase is Base that passes given context to the handler. Useful in |
| 30 // tests. | 75 // tests. |
| 31 func TestingBase(c context.Context) Base { | 76 func TestingBase(c context.Context) Base { |
| 32 return func(h Handler) httprouter.Handle { | 77 return func(h Handler) httprouter.Handle { |
| 33 return func(rw http.ResponseWriter, r *http.Request, p httproute r.Params) { | 78 return func(rw http.ResponseWriter, r *http.Request, p httproute r.Params) { |
| 34 h(c, rw, r, p) | 79 h(c, rw, r, p) |
| 35 } | 80 } |
| 36 } | 81 } |
| 37 } | 82 } |
| 38 | 83 |
| 39 // WithContextValue is a middleware that adds a value to the context before | 84 // WithContextValue is a middleware that adds a value to the context before |
| 40 // calling the handler. | 85 // calling the handler. |
| 41 func WithContextValue(h Handler, key, val interface{}) Handler { | 86 func WithContextValue(h Handler, key, val interface{}) Handler { |
| 42 return func(c context.Context, rw http.ResponseWriter, r *http.Request, p httprouter.Params) { | 87 return func(c context.Context, rw http.ResponseWriter, r *http.Request, p httprouter.Params) { |
| 43 h(context.WithValue(c, key, val), rw, r, p) | 88 h(context.WithValue(c, key, val), rw, r, p) |
| 44 } | 89 } |
| 45 } | 90 } |
| OLD | NEW |