diff options
author | Raúl Benencia <raul@thousandeyes.com> | 2018-04-13 16:30:31 -0700 |
---|---|---|
committer | Raúl Benencia <raul@thousandeyes.com> | 2018-05-11 15:02:34 -0700 |
commit | 77c172b823b64ebface655681ab0749b9d2f7081 (patch) | |
tree | 09c13e626eb95ae1d33e76ed683172eab1ab6c96 /vendor/github.com/justinas/alice/chain.go |
First public commit
Diffstat (limited to 'vendor/github.com/justinas/alice/chain.go')
-rw-r--r-- | vendor/github.com/justinas/alice/chain.go | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/vendor/github.com/justinas/alice/chain.go b/vendor/github.com/justinas/alice/chain.go new file mode 100644 index 0000000..da0e2b5 --- /dev/null +++ b/vendor/github.com/justinas/alice/chain.go @@ -0,0 +1,112 @@ +// Package alice provides a convenient way to chain http handlers. +package alice + +import "net/http" + +// A constructor for a piece of middleware. +// Some middleware use this constructor out of the box, +// so in most cases you can just pass somepackage.New +type Constructor func(http.Handler) http.Handler + +// Chain acts as a list of http.Handler constructors. +// Chain is effectively immutable: +// once created, it will always hold +// the same set of constructors in the same order. +type Chain struct { + constructors []Constructor +} + +// New creates a new chain, +// memorizing the given list of middleware constructors. +// New serves no other function, +// constructors are only called upon a call to Then(). +func New(constructors ...Constructor) Chain { + return Chain{append(([]Constructor)(nil), constructors...)} +} + +// Then chains the middleware and returns the final http.Handler. +// New(m1, m2, m3).Then(h) +// is equivalent to: +// m1(m2(m3(h))) +// When the request comes in, it will be passed to m1, then m2, then m3 +// and finally, the given handler +// (assuming every middleware calls the following one). +// +// A chain can be safely reused by calling Then() several times. +// stdStack := alice.New(ratelimitHandler, csrfHandler) +// indexPipe = stdStack.Then(indexHandler) +// authPipe = stdStack.Then(authHandler) +// Note that constructors are called on every call to Then() +// and thus several instances of the same middleware will be created +// when a chain is reused in this way. +// For proper middleware, this should cause no problems. +// +// Then() treats nil as http.DefaultServeMux. +func (c Chain) Then(h http.Handler) http.Handler { + if h == nil { + h = http.DefaultServeMux + } + + for i := range c.constructors { + h = c.constructors[len(c.constructors)-1-i](h) + } + + return h +} + +// ThenFunc works identically to Then, but takes +// a HandlerFunc instead of a Handler. +// +// The following two statements are equivalent: +// c.Then(http.HandlerFunc(fn)) +// c.ThenFunc(fn) +// +// ThenFunc provides all the guarantees of Then. +func (c Chain) ThenFunc(fn http.HandlerFunc) http.Handler { + if fn == nil { + return c.Then(nil) + } + return c.Then(fn) +} + +// Append extends a chain, adding the specified constructors +// as the last ones in the request flow. +// +// Append returns a new chain, leaving the original one untouched. +// +// stdChain := alice.New(m1, m2) +// extChain := stdChain.Append(m3, m4) +// // requests in stdChain go m1 -> m2 +// // requests in extChain go m1 -> m2 -> m3 -> m4 +func (c Chain) Append(constructors ...Constructor) Chain { + newCons := make([]Constructor, 0, len(c.constructors)+len(constructors)) + newCons = append(newCons, c.constructors...) + newCons = append(newCons, constructors...) + + return Chain{newCons} +} + +// Extend extends a chain by adding the specified chain +// as the last one in the request flow. +// +// Extend returns a new chain, leaving the original one untouched. +// +// stdChain := alice.New(m1, m2) +// ext1Chain := alice.New(m3, m4) +// ext2Chain := stdChain.Extend(ext1Chain) +// // requests in stdChain go m1 -> m2 +// // requests in ext1Chain go m3 -> m4 +// // requests in ext2Chain go m1 -> m2 -> m3 -> m4 +// +// Another example: +// aHtmlAfterNosurf := alice.New(m2) +// aHtml := alice.New(m1, func(h http.Handler) http.Handler { +// csrf := nosurf.New(h) +// csrf.SetFailureHandler(aHtmlAfterNosurf.ThenFunc(csrfFail)) +// return csrf +// }).Extend(aHtmlAfterNosurf) +// // requests to aHtml hitting nosurfs success handler go m1 -> nosurf -> m2 -> target-handler +// // requests to aHtml hitting nosurfs failure handler go m1 -> nosurf -> m2 -> csrfFail +func (c Chain) Extend(chain Chain) Chain { + return c.Append(chain.constructors...) +} |