aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/zenazn/goji/web
diff options
context:
space:
mode:
authorFelix Hanley <felix@userspace.com.au>2016-12-05 08:16:58 +0000
committerFelix Hanley <felix@userspace.com.au>2016-12-05 08:16:58 +0000
commitb049991a46a2f619344bd6e915745703864d0134 (patch)
treeec1d3897a7b69c7c63a3774d4c42dfbb8cb46432 /vendor/github.com/zenazn/goji/web
parente1c3d6f7db06d592538f1162b2b6b9f1b6efa330 (diff)
downloadgo-dict2rest-b049991a46a2f619344bd6e915745703864d0134.tar.gz
go-dict2rest-b049991a46a2f619344bd6e915745703864d0134.tar.bz2
Clean up source structure and update vendor versionsHEADmaster
Diffstat (limited to 'vendor/github.com/zenazn/goji/web')
-rw-r--r--vendor/github.com/zenazn/goji/web/atomic.go18
-rw-r--r--vendor/github.com/zenazn/goji/web/atomic_appengine.go14
-rw-r--r--vendor/github.com/zenazn/goji/web/bytecode_compiler.go265
-rw-r--r--vendor/github.com/zenazn/goji/web/bytecode_runner.go83
-rw-r--r--vendor/github.com/zenazn/goji/web/chanpool.go31
-rw-r--r--vendor/github.com/zenazn/goji/web/cpool.go23
-rw-r--r--vendor/github.com/zenazn/goji/web/func_equal.go32
-rw-r--r--vendor/github.com/zenazn/goji/web/handler.go42
-rw-r--r--vendor/github.com/zenazn/goji/web/match.go66
-rw-r--r--vendor/github.com/zenazn/goji/web/middleware.go154
-rw-r--r--vendor/github.com/zenazn/goji/web/middleware/envinit.go27
-rw-r--r--vendor/github.com/zenazn/goji/web/middleware/logger.go92
-rw-r--r--vendor/github.com/zenazn/goji/web/middleware/middleware.go4
-rw-r--r--vendor/github.com/zenazn/goji/web/middleware/nocache.go55
-rw-r--r--vendor/github.com/zenazn/goji/web/middleware/options.go97
-rw-r--r--vendor/github.com/zenazn/goji/web/middleware/realip.go51
-rw-r--r--vendor/github.com/zenazn/goji/web/middleware/recoverer.go44
-rw-r--r--vendor/github.com/zenazn/goji/web/middleware/request_id.go88
-rw-r--r--vendor/github.com/zenazn/goji/web/middleware/subrouter.go65
-rw-r--r--vendor/github.com/zenazn/goji/web/middleware/terminal.go60
-rw-r--r--vendor/github.com/zenazn/goji/web/middleware/urlquery.go24
-rw-r--r--vendor/github.com/zenazn/goji/web/mutil/mutil.go3
-rw-r--r--vendor/github.com/zenazn/goji/web/mutil/writer_proxy.go139
-rw-r--r--vendor/github.com/zenazn/goji/web/mux.go213
-rw-r--r--vendor/github.com/zenazn/goji/web/pattern.go58
-rw-r--r--vendor/github.com/zenazn/goji/web/regexp_pattern.go149
-rw-r--r--vendor/github.com/zenazn/goji/web/router.go154
-rw-r--r--vendor/github.com/zenazn/goji/web/string_pattern.go137
-rw-r--r--vendor/github.com/zenazn/goji/web/web.go112
29 files changed, 2300 insertions, 0 deletions
diff --git a/vendor/github.com/zenazn/goji/web/atomic.go b/vendor/github.com/zenazn/goji/web/atomic.go
new file mode 100644
index 0000000..795d8e5
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/atomic.go
@@ -0,0 +1,18 @@
+// +build !appengine
+
+package web
+
+import (
+ "sync/atomic"
+ "unsafe"
+)
+
+func (rt *router) getMachine() *routeMachine {
+ ptr := (*unsafe.Pointer)(unsafe.Pointer(&rt.machine))
+ sm := (*routeMachine)(atomic.LoadPointer(ptr))
+ return sm
+}
+func (rt *router) setMachine(m *routeMachine) {
+ ptr := (*unsafe.Pointer)(unsafe.Pointer(&rt.machine))
+ atomic.StorePointer(ptr, unsafe.Pointer(m))
+}
diff --git a/vendor/github.com/zenazn/goji/web/atomic_appengine.go b/vendor/github.com/zenazn/goji/web/atomic_appengine.go
new file mode 100644
index 0000000..027127a
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/atomic_appengine.go
@@ -0,0 +1,14 @@
+// +build appengine
+
+package web
+
+func (rt *router) getMachine() *routeMachine {
+ rt.lock.Lock()
+ defer rt.lock.Unlock()
+ return rt.machine
+}
+
+// We always hold the lock when calling setMachine.
+func (rt *router) setMachine(m *routeMachine) {
+ rt.machine = m
+}
diff --git a/vendor/github.com/zenazn/goji/web/bytecode_compiler.go b/vendor/github.com/zenazn/goji/web/bytecode_compiler.go
new file mode 100644
index 0000000..b6f52b1
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/bytecode_compiler.go
@@ -0,0 +1,265 @@
+package web
+
+/*
+This file implements a fast router by encoding a list of routes first into a
+pseudo-trie, then encoding that pseudo-trie into a state machine realized as
+a routing bytecode.
+
+The most interesting part of this router is not its speed (it is quite fast),
+but the guarantees it provides. In a naive router, routes are examined one after
+another until a match is found, and this is the programming model we want to
+support. For any given request ("GET /hello/carl"), there is a list of
+"plausible" routes: routes which match the method ("GET"), and which have a
+prefix that is a prefix of the requested path ("/" and "/hello/", for instance,
+but not "/foobar"). Patterns also have some amount of arbitrary code associated
+with them, which tells us whether or not the route matched. Just like the naive
+router, our goal is to call each plausible pattern, in the order they were
+added, until we find one that matches. The "fast" part here is being smart about
+which non-plausible routes we can skip.
+
+First, we sort routes using a pairwise comparison function: sorting occurs as
+normal on the prefixes, with the caveat that a route may not be moved past a
+route that might also match the same string. Among other things, this means
+we're forced to use particularly dumb sorting algorithms, but it only has to
+happen once, and there probably aren't even that many routes to begin with. This
+logic appears inline in the router's handle() function.
+
+We then build a pseudo-trie from the sorted list of routes. It's not quite a
+normal trie because there are certain routes we cannot reorder around other
+routes (since we're providing identical semantics to the naive router), but it's
+close enough and the basic idea is the same.
+
+Finally, we lower this psuedo-trie from its tree representation to a state
+machine bytecode. The bytecode is pretty simple: it contains up to three bytes,
+a choice of a bunch of flags, and an index. The state machine is pretty simple:
+if the bytes match the next few bytes after the cursor, the instruction matches,
+and the state machine advances to the next instruction. If it does not match, it
+jumps to the instruction at the index. Various flags modify this basic behavior,
+the documentation for which can be found below.
+
+The thing we're optimizing for here over pretty much everything else is memory
+locality. We make an effort to lay out both the trie child selection logic and
+the matching of long strings consecutively in memory, making both operations
+very cheap. In fact, our matching logic isn't particularly asymptotically good,
+but in practice the benefits of memory locality outweigh just about everything
+else.
+
+Unfortunately, the code implementing all of this is pretty bad (both inefficient
+and hard to read). Maybe someday I'll come and take a second pass at it.
+*/
+type state struct {
+ mode smMode
+ bs [3]byte
+ i int32
+}
+type stateMachine []state
+
+type smMode uint8
+
+// Many combinations of smModes don't make sense, but since this is interal to
+// the library I don't feel like documenting them.
+const (
+ // The two low bits of the mode are used as a length of how many bytes
+ // of bs are used. If the length is 0, the node is treated as a
+ // wildcard.
+ smLengthMask smMode = 3
+)
+
+const (
+ // Jump to the given index on a match. Ordinarily, the state machine
+ // will jump to the state given by the index if the characters do not
+ // match.
+ smJumpOnMatch smMode = 4 << iota
+ // The index is the index of a route to try. If running the route fails,
+ // the state machine advances by one.
+ smRoute
+ // Reset the state machine's cursor into the input string to the state's
+ // index value.
+ smSetCursor
+ // If this bit is set, the machine transitions into a non-accepting
+ // state if it matches.
+ smFail
+)
+
+type trie struct {
+ prefix string
+ children []trieSegment
+}
+
+// A trie segment is a route matching this point (or -1), combined with a list
+// of trie children that follow that route.
+type trieSegment struct {
+ route int
+ children []trie
+}
+
+func buildTrie(routes []route, dp, dr int) trie {
+ var t trie
+ ts := trieSegment{-1, nil}
+ for i, r := range routes {
+ if len(r.prefix) != dp {
+ continue
+ }
+
+ if i == 0 {
+ ts.route = 0
+ } else {
+ subroutes := routes[ts.route+1 : i]
+ ts.children = buildTrieSegment(subroutes, dp, dr+ts.route+1)
+ t.children = append(t.children, ts)
+ ts = trieSegment{i, nil}
+ }
+ }
+
+ // This could be a little DRYer...
+ subroutes := routes[ts.route+1:]
+ ts.children = buildTrieSegment(subroutes, dp, dr+ts.route+1)
+ t.children = append(t.children, ts)
+
+ for i := range t.children {
+ if t.children[i].route != -1 {
+ t.children[i].route += dr
+ }
+ }
+
+ return t
+}
+
+func commonPrefix(s1, s2 string) string {
+ if len(s1) > len(s2) {
+ return commonPrefix(s2, s1)
+ }
+ for i := 0; i < len(s1); i++ {
+ if s1[i] != s2[i] {
+ return s1[:i]
+ }
+ }
+ return s1
+}
+
+func buildTrieSegment(routes []route, dp, dr int) []trie {
+ if len(routes) == 0 {
+ return nil
+ }
+ var tries []trie
+
+ start := 0
+ p := routes[0].prefix[dp:]
+ for i := 1; i < len(routes); i++ {
+ ip := routes[i].prefix[dp:]
+ cp := commonPrefix(p, ip)
+ if len(cp) == 0 {
+ t := buildTrie(routes[start:i], dp+len(p), dr+start)
+ t.prefix = p
+ tries = append(tries, t)
+ start = i
+ p = ip
+ } else {
+ p = cp
+ }
+ }
+
+ t := buildTrie(routes[start:], dp+len(p), dr+start)
+ t.prefix = p
+ return append(tries, t)
+}
+
+// This is a bit confusing, since the encode method on a trie deals exclusively
+// with trieSegments (i.e., its children), and vice versa.
+//
+// These methods are also hideously inefficient, both in terms of memory usage
+// and algorithmic complexity. If it ever becomes a problem, maybe we can do
+// something smarter than stupid O(N^2) appends, but to be honest, I bet N is
+// small (it almost always is :P) and we only do it once at boot anyways.
+
+func (t trie) encode(dp, off int) stateMachine {
+ ms := make([]stateMachine, len(t.children))
+ subs := make([]stateMachine, len(t.children))
+ var l, msl, subl int
+
+ for i, ts := range t.children {
+ ms[i], subs[i] = ts.encode(dp, 0)
+ msl += len(ms[i])
+ l += len(ms[i]) + len(subs[i])
+ }
+
+ l++
+
+ m := make(stateMachine, 0, l)
+ for i, mm := range ms {
+ for j := range mm {
+ if mm[j].mode&(smRoute|smSetCursor) != 0 {
+ continue
+ }
+
+ mm[j].i += int32(off + msl + subl + 1)
+ }
+ m = append(m, mm...)
+ subl += len(subs[i])
+ }
+
+ m = append(m, state{mode: smJumpOnMatch, i: -1})
+
+ msl = 0
+ for i, sub := range subs {
+ msl += len(ms[i])
+ for j := range sub {
+ if sub[j].mode&(smRoute|smSetCursor) != 0 {
+ continue
+ }
+ if sub[j].i == -1 {
+ sub[j].i = int32(off + msl)
+ } else {
+ sub[j].i += int32(off + len(m))
+ }
+ }
+ m = append(m, sub...)
+ }
+
+ return m
+}
+
+func (ts trieSegment) encode(dp, off int) (me stateMachine, sub stateMachine) {
+ o := 1
+ if ts.route != -1 {
+ o++
+ }
+ me = make(stateMachine, len(ts.children)+o)
+
+ me[0] = state{mode: smSetCursor, i: int32(dp)}
+ if ts.route != -1 {
+ me[1] = state{mode: smRoute, i: int32(ts.route)}
+ }
+
+ for i, t := range ts.children {
+ p := t.prefix
+
+ bc := copy(me[i+o].bs[:], p)
+ me[i+o].mode = smMode(bc) | smJumpOnMatch
+ me[i+o].i = int32(off + len(sub))
+
+ for len(p) > bc {
+ var bs [3]byte
+ p = p[bc:]
+ bc = copy(bs[:], p)
+ sub = append(sub, state{bs: bs, mode: smMode(bc), i: -1})
+ }
+
+ sub = append(sub, t.encode(dp+len(t.prefix), off+len(sub))...)
+ }
+ return
+}
+
+func compile(routes []route) stateMachine {
+ if len(routes) == 0 {
+ return nil
+ }
+ t := buildTrie(routes, 0, 0)
+ m := t.encode(0, 0)
+ for i := range m {
+ if m[i].i == -1 {
+ m[i].mode = m[i].mode | smFail
+ }
+ }
+ return m
+}
diff --git a/vendor/github.com/zenazn/goji/web/bytecode_runner.go b/vendor/github.com/zenazn/goji/web/bytecode_runner.go
new file mode 100644
index 0000000..c32b16a
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/bytecode_runner.go
@@ -0,0 +1,83 @@
+package web
+
+import "net/http"
+
+type routeMachine struct {
+ sm stateMachine
+ routes []route
+}
+
+func matchRoute(route route, m method, ms *method, r *http.Request, c *C) bool {
+ if !route.pattern.Match(r, c) {
+ return false
+ }
+ *ms |= route.method
+
+ if route.method&m != 0 {
+ route.pattern.Run(r, c)
+ return true
+ }
+ return false
+}
+
+func (rm routeMachine) route(c *C, w http.ResponseWriter, r *http.Request) (method, *route) {
+ m := httpMethod(r.Method)
+ var methods method
+ p := r.URL.Path
+
+ if len(rm.sm) == 0 {
+ return methods, nil
+ }
+
+ var i int
+ for {
+ sm := rm.sm[i].mode
+ if sm&smSetCursor != 0 {
+ si := rm.sm[i].i
+ p = r.URL.Path[si:]
+ i++
+ continue
+ }
+
+ length := int(sm & smLengthMask)
+ match := false
+ if length <= len(p) {
+ bs := rm.sm[i].bs
+ switch length {
+ case 3:
+ if p[2] != bs[2] {
+ break
+ }
+ fallthrough
+ case 2:
+ if p[1] != bs[1] {
+ break
+ }
+ fallthrough
+ case 1:
+ if p[0] != bs[0] {
+ break
+ }
+ fallthrough
+ case 0:
+ p = p[length:]
+ match = true
+ }
+ }
+
+ if match && sm&smRoute != 0 {
+ si := rm.sm[i].i
+ if matchRoute(rm.routes[si], m, &methods, r, c) {
+ return 0, &rm.routes[si]
+ }
+ i++
+ } else if match != (sm&smJumpOnMatch == 0) {
+ if sm&smFail != 0 {
+ return methods, nil
+ }
+ i = int(rm.sm[i].i)
+ } else {
+ i++
+ }
+ }
+}
diff --git a/vendor/github.com/zenazn/goji/web/chanpool.go b/vendor/github.com/zenazn/goji/web/chanpool.go
new file mode 100644
index 0000000..6c53c74
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/chanpool.go
@@ -0,0 +1,31 @@
+// +build !go1.3
+
+package web
+
+// This is an alternate implementation of Go 1.3's sync.Pool.
+
+// Maximum size of the pool of spare middleware stacks
+const cPoolSize = 32
+
+type cPool chan *cStack
+
+func makeCPool() *cPool {
+ p := make(cPool, cPoolSize)
+ return &p
+}
+
+func (c cPool) alloc() *cStack {
+ select {
+ case cs := <-c:
+ return cs
+ default:
+ return nil
+ }
+}
+
+func (c cPool) release(cs *cStack) {
+ select {
+ case c <- cs:
+ default:
+ }
+}
diff --git a/vendor/github.com/zenazn/goji/web/cpool.go b/vendor/github.com/zenazn/goji/web/cpool.go
new file mode 100644
index 0000000..59f8764
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/cpool.go
@@ -0,0 +1,23 @@
+// +build go1.3
+
+package web
+
+import "sync"
+
+type cPool sync.Pool
+
+func makeCPool() *cPool {
+ return &cPool{}
+}
+
+func (c *cPool) alloc() *cStack {
+ cs := (*sync.Pool)(c).Get()
+ if cs == nil {
+ return nil
+ }
+ return cs.(*cStack)
+}
+
+func (c *cPool) release(cs *cStack) {
+ (*sync.Pool)(c).Put(cs)
+}
diff --git a/vendor/github.com/zenazn/goji/web/func_equal.go b/vendor/github.com/zenazn/goji/web/func_equal.go
new file mode 100644
index 0000000..9c8f7cb
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/func_equal.go
@@ -0,0 +1,32 @@
+package web
+
+import (
+ "reflect"
+)
+
+/*
+This is more than a little sketchtacular. Go's rules for function pointer
+equality are pretty restrictive: nil function pointers always compare equal, and
+all other pointer types never do. However, this is pretty limiting: it means
+that we can't let people reference the middleware they've given us since we have
+no idea which function they're referring to.
+
+To get better data out of Go, we sketch on the representation of interfaces. We
+happen to know that interfaces are pairs of pointers: one to the real data, one
+to data about the type. Therefore, two interfaces, including two function
+interface{}'s, point to exactly the same objects iff their interface
+representations are identical. And it turns out this is sufficient for our
+purposes.
+
+If you're curious, you can read more about the representation of functions here:
+http://golang.org/s/go11func
+We're in effect comparing the pointers of the indirect layer.
+
+This function also works on non-function values.
+*/
+func funcEqual(a, b interface{}) bool {
+ av := reflect.ValueOf(&a).Elem()
+ bv := reflect.ValueOf(&b).Elem()
+
+ return av.InterfaceData() == bv.InterfaceData()
+}
diff --git a/vendor/github.com/zenazn/goji/web/handler.go b/vendor/github.com/zenazn/goji/web/handler.go
new file mode 100644
index 0000000..746c9f0
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/handler.go
@@ -0,0 +1,42 @@
+package web
+
+import (
+ "log"
+ "net/http"
+)
+
+const unknownHandler = `Unknown handler type %T. See http://godoc.org/github.com/zenazn/goji/web#HandlerType for a list of acceptable types.`
+
+type netHTTPHandlerWrap struct{ http.Handler }
+type netHTTPHandlerFuncWrap struct {
+ fn func(http.ResponseWriter, *http.Request)
+}
+type handlerFuncWrap struct {
+ fn func(C, http.ResponseWriter, *http.Request)
+}
+
+func (h netHTTPHandlerWrap) ServeHTTPC(c C, w http.ResponseWriter, r *http.Request) {
+ h.Handler.ServeHTTP(w, r)
+}
+func (h netHTTPHandlerFuncWrap) ServeHTTPC(c C, w http.ResponseWriter, r *http.Request) {
+ h.fn(w, r)
+}
+func (h handlerFuncWrap) ServeHTTPC(c C, w http.ResponseWriter, r *http.Request) {
+ h.fn(c, w, r)
+}
+
+func parseHandler(h HandlerType) Handler {
+ switch f := h.(type) {
+ case func(c C, w http.ResponseWriter, r *http.Request):
+ return handlerFuncWrap{f}
+ case func(w http.ResponseWriter, r *http.Request):
+ return netHTTPHandlerFuncWrap{f}
+ case Handler:
+ return f
+ case http.Handler:
+ return netHTTPHandlerWrap{f}
+ default:
+ log.Fatalf(unknownHandler, h)
+ panic("log.Fatalf does not return")
+ }
+}
diff --git a/vendor/github.com/zenazn/goji/web/match.go b/vendor/github.com/zenazn/goji/web/match.go
new file mode 100644
index 0000000..1a44144
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/match.go
@@ -0,0 +1,66 @@
+package web
+
+// The key used to store route Matches in the Goji environment. If this key is
+// present in the environment and contains a value of type Match, routing will
+// not be performed, and the Match's Handler will be used instead.
+const MatchKey = "goji.web.Match"
+
+// Match is the type of routing matches. It is inserted into C.Env under
+// MatchKey when the Mux.Router middleware is invoked. If MatchKey is present at
+// route dispatch time, the Handler of the corresponding Match will be called
+// instead of performing routing as usual.
+//
+// By computing a Match and inserting it into the Goji environment as part of a
+// middleware stack (see Mux.Router, for instance), it is possible to customize
+// Goji's routing behavior or replace it entirely.
+type Match struct {
+ // Pattern is the Pattern that matched during routing. Will be nil if no
+ // route matched (Handler will be set to the Mux's NotFound handler)
+ Pattern Pattern
+ // The Handler corresponding to the matched pattern.
+ Handler Handler
+}
+
+// GetMatch returns the Match stored in the Goji environment, or an empty Match
+// if none exists (valid Matches always have a Handler property).
+func GetMatch(c C) Match {
+ if c.Env == nil {
+ return Match{}
+ }
+ mi, ok := c.Env[MatchKey]
+ if !ok {
+ return Match{}
+ }
+ if m, ok := mi.(Match); ok {
+ return m
+ }
+ return Match{}
+}
+
+// RawPattern returns the PatternType that was originally passed to ParsePattern
+// or any of the HTTP method functions (Get, Post, etc.).
+func (m Match) RawPattern() PatternType {
+ switch v := m.Pattern.(type) {
+ case regexpPattern:
+ return v.re
+ case stringPattern:
+ return v.raw
+ default:
+ return v
+ }
+}
+
+// RawHandler returns the HandlerType that was originally passed to the HTTP
+// method functions (Get, Post, etc.).
+func (m Match) RawHandler() HandlerType {
+ switch v := m.Handler.(type) {
+ case netHTTPHandlerWrap:
+ return v.Handler
+ case handlerFuncWrap:
+ return v.fn
+ case netHTTPHandlerFuncWrap:
+ return v.fn
+ default:
+ return v
+ }
+}
diff --git a/vendor/github.com/zenazn/goji/web/middleware.go b/vendor/github.com/zenazn/goji/web/middleware.go
new file mode 100644
index 0000000..7ec545d
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/middleware.go
@@ -0,0 +1,154 @@
+package web
+
+import (
+ "fmt"
+ "log"
+ "net/http"
+ "sync"
+)
+
+// mLayer is a single middleware stack layer. It contains a canonicalized
+// middleware representation, as well as the original function as passed to us.
+type mLayer struct {
+ fn func(*C, http.Handler) http.Handler
+ orig interface{}
+}
+
+// mStack is an entire middleware stack. It contains a slice of middleware
+// layers (outermost first) protected by a mutex, a cache of pre-built stack
+// instances, and a final routing function.
+type mStack struct {
+ lock sync.Mutex
+ stack []mLayer
+ pool *cPool
+ router internalRouter
+}
+
+type internalRouter interface {
+ route(*C, http.ResponseWriter, *http.Request)
+}
+
+/*
+cStack is a cached middleware stack instance. Constructing a middleware stack
+involves a lot of allocations: at the very least each layer will have to close
+over the layer after (inside) it and a stack N levels deep will incur at least N
+separate allocations. Instead of doing this on every request, we keep a pool of
+pre-built stacks around for reuse.
+*/
+type cStack struct {
+ C
+ m http.Handler
+ pool *cPool
+}
+
+func (s *cStack) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ s.C = C{}
+ s.m.ServeHTTP(w, r)
+}
+func (s *cStack) ServeHTTPC(c C, w http.ResponseWriter, r *http.Request) {
+ s.C = c
+ s.m.ServeHTTP(w, r)
+}
+
+const unknownMiddleware = `Unknown middleware type %T. See http://godoc.org/github.com/zenazn/goji/web#MiddlewareType for a list of acceptable types.`
+
+func (m *mStack) appendLayer(fn interface{}) {
+ ml := mLayer{orig: fn}
+ switch f := fn.(type) {
+ case func(http.Handler) http.Handler:
+ ml.fn = func(c *C, h http.Handler) http.Handler {
+ return f(h)
+ }
+ case func(*C, http.Handler) http.Handler:
+ ml.fn = f
+ default:
+ log.Fatalf(unknownMiddleware, fn)
+ }
+ m.stack = append(m.stack, ml)
+}
+
+func (m *mStack) findLayer(l interface{}) int {
+ for i, middleware := range m.stack {
+ if funcEqual(l, middleware.orig) {
+ return i
+ }
+ }
+ return -1
+}
+
+func (m *mStack) invalidate() {
+ m.pool = makeCPool()
+}
+
+func (m *mStack) newStack() *cStack {
+ cs := cStack{}
+ router := m.router
+
+ cs.m = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ router.route(&cs.C, w, r)
+ })
+ for i := len(m.stack) - 1; i >= 0; i-- {
+ cs.m = m.stack[i].fn(&cs.C, cs.m)
+ }
+
+ return &cs
+}
+
+func (m *mStack) alloc() *cStack {
+ p := m.pool
+ cs := p.alloc()
+ if cs == nil {
+ cs = m.newStack()
+ }
+
+ cs.pool = p
+ return cs
+}
+
+func (m *mStack) release(cs *cStack) {
+ cs.C = C{}
+ if cs.pool != m.pool {
+ return
+ }
+ cs.pool.release(cs)
+ cs.pool = nil
+}
+
+func (m *mStack) Use(middleware interface{}) {
+ m.lock.Lock()
+ defer m.lock.Unlock()
+ m.appendLayer(middleware)
+ m.invalidate()
+}
+
+func (m *mStack) Insert(middleware, before interface{}) error {
+ m.lock.Lock()
+ defer m.lock.Unlock()
+ i := m.findLayer(before)
+ if i < 0 {
+ return fmt.Errorf("web: unknown middleware %v", before)
+ }
+
+ m.appendLayer(middleware)
+ inserted := m.stack[len(m.stack)-1]
+ copy(m.stack[i+1:], m.stack[i:])
+ m.stack[i] = inserted
+
+ m.invalidate()
+ return nil
+}
+
+func (m *mStack) Abandon(middleware interface{}) error {
+ m.lock.Lock()
+ defer m.lock.Unlock()
+ i := m.findLayer(middleware)
+ if i < 0 {
+ return fmt.Errorf("web: unknown middleware %v", middleware)
+ }
+
+ copy(m.stack[i:], m.stack[i+1:])
+ m.stack = m.stack[:len(m.stack)-1 : len(m.stack)]
+
+ m.invalidate()
+ return nil
+}
diff --git a/vendor/github.com/zenazn/goji/web/middleware/envinit.go b/vendor/github.com/zenazn/goji/web/middleware/envinit.go
new file mode 100644
index 0000000..ae3b683
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/middleware/envinit.go
@@ -0,0 +1,27 @@
+package middleware
+
+import (
+ "net/http"
+
+ "github.com/zenazn/goji/web"
+)
+
+type envInit struct {
+ c *web.C
+ h http.Handler
+}
+
+func (e envInit) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ if e.c.Env == nil {
+ e.c.Env = make(map[interface{}]interface{})
+ }
+ e.h.ServeHTTP(w, r)
+}
+
+// EnvInit is a middleware that allocates an environment map if it is nil. While
+// it's impossible in general to ensure that Env is never nil in a middleware
+// stack, in most common cases placing this middleware at the top of the stack
+// will eliminate the need for repetative nil checks.
+func EnvInit(c *web.C, h http.Handler) http.Handler {
+ return envInit{c, h}
+}
diff --git a/vendor/github.com/zenazn/goji/web/middleware/logger.go b/vendor/github.com/zenazn/goji/web/middleware/logger.go
new file mode 100644
index 0000000..8bbcac8
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/middleware/logger.go
@@ -0,0 +1,92 @@
+package middleware
+
+import (
+ "bytes"
+ "log"
+ "net/http"
+ "time"
+
+ "github.com/zenazn/goji/web"
+ "github.com/zenazn/goji/web/mutil"
+)
+
+// Logger is a middleware that logs the start and end of each request, along
+// with some useful data about what was requested, what the response status was,
+// and how long it took to return. When standard output is a TTY, Logger will
+// print in color, otherwise it will print in black and white.
+//
+// Logger prints a request ID if one is provided.
+//
+// Logger has been designed explicitly to be Good Enough for use in small
+// applications and for people just getting started with Goji. It is expected
+// that applications will eventually outgrow this middleware and replace it with
+// a custom request logger, such as one that produces machine-parseable output,
+// outputs logs to a different service (e.g., syslog), or formats lines like
+// those printed elsewhere in the application.
+func Logger(c *web.C, h http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ reqID := GetReqID(*c)
+
+ printStart(reqID, r)
+
+ lw := mutil.WrapWriter(w)
+
+ t1 := time.Now()
+ h.ServeHTTP(lw, r)
+
+ if lw.Status() == 0 {
+ lw.WriteHeader(http.StatusOK)
+ }
+ t2 := time.Now()
+
+ printEnd(reqID, lw, t2.Sub(t1))
+ }
+
+ return http.HandlerFunc(fn)
+}
+
+func printStart(reqID string, r *http.Request) {
+ var buf bytes.Buffer
+
+ if reqID != "" {
+ cW(&buf, bBlack, "[%s] ", reqID)
+ }
+ buf.WriteString("Started ")
+ cW(&buf, bMagenta, "%s ", r.Method)
+ cW(&buf, nBlue, "%q ", r.URL.String())
+ buf.WriteString("from ")
+ buf.WriteString(r.RemoteAddr)
+
+ log.Print(buf.String())
+}
+
+func printEnd(reqID string, w mutil.WriterProxy, dt time.Duration) {
+ var buf bytes.Buffer
+
+ if reqID != "" {
+ cW(&buf, bBlack, "[%s] ", reqID)
+ }
+ buf.WriteString("Returning ")
+ status := w.Status()
+ if status < 200 {
+ cW(&buf, bBlue, "%03d", status)
+ } else if status < 300 {
+ cW(&buf, bGreen, "%03d", status)
+ } else if status < 400 {
+ cW(&buf, bCyan, "%03d", status)
+ } else if status < 500 {
+ cW(&buf, bYellow, "%03d", status)
+ } else {
+ cW(&buf, bRed, "%03d", status)
+ }
+ buf.WriteString(" in ")
+ if dt < 500*time.Millisecond {
+ cW(&buf, nGreen, "%s", dt)
+ } else if dt < 5*time.Second {
+ cW(&buf, nYellow, "%s", dt)
+ } else {
+ cW(&buf, nRed, "%s", dt)
+ }
+
+ log.Print(buf.String())
+}
diff --git a/vendor/github.com/zenazn/goji/web/middleware/middleware.go b/vendor/github.com/zenazn/goji/web/middleware/middleware.go
new file mode 100644
index 0000000..23cfde2
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/middleware/middleware.go
@@ -0,0 +1,4 @@
+/*
+Package middleware provides several standard middleware implementations.
+*/
+package middleware
diff --git a/vendor/github.com/zenazn/goji/web/middleware/nocache.go b/vendor/github.com/zenazn/goji/web/middleware/nocache.go
new file mode 100644
index 0000000..ae3d260
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/middleware/nocache.go
@@ -0,0 +1,55 @@
+package middleware
+
+import (
+ "net/http"
+ "time"
+)
+
+// Unix epoch time
+var epoch = time.Unix(0, 0).Format(time.RFC1123)
+
+// Taken from https://github.com/mytrile/nocache
+var noCacheHeaders = map[string]string{
+ "Expires": epoch,
+ "Cache-Control": "no-cache, private, max-age=0",
+ "Pragma": "no-cache",
+ "X-Accel-Expires": "0",
+}
+
+var etagHeaders = []string{
+ "ETag",
+ "If-Modified-Since",
+ "If-Match",
+ "If-None-Match",
+ "If-Range",
+ "If-Unmodified-Since",
+}
+
+// NoCache is a simple piece of middleware that sets a number of HTTP headers to prevent
+// a router (or subrouter) from being cached by an upstream proxy and/or client.
+//
+// As per http://wiki.nginx.org/HttpProxyModule - NoCache sets:
+// Expires: Thu, 01 Jan 1970 00:00:00 UTC
+// Cache-Control: no-cache, private, max-age=0
+// X-Accel-Expires: 0
+// Pragma: no-cache (for HTTP/1.0 proxies/clients)
+func NoCache(h http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+
+ // Delete any ETag headers that may have been set
+ for _, v := range etagHeaders {
+ if r.Header.Get(v) != "" {
+ r.Header.Del(v)
+ }
+ }
+
+ // Set our NoCache headers
+ for k, v := range noCacheHeaders {
+ w.Header().Set(k, v)
+ }
+
+ h.ServeHTTP(w, r)
+ }
+
+ return http.HandlerFunc(fn)
+}
diff --git a/vendor/github.com/zenazn/goji/web/middleware/options.go b/vendor/github.com/zenazn/goji/web/middleware/options.go
new file mode 100644
index 0000000..4bdce5f
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/middleware/options.go
@@ -0,0 +1,97 @@
+package middleware
+
+import (
+ "net/http"
+ "strings"
+
+ "github.com/zenazn/goji/web"
+)
+
+type autoOptionsState int
+
+const (
+ aosInit autoOptionsState = iota
+ aosHeaderWritten
+ aosProxying
+)
+
+// I originally used an httptest.ResponseRecorder here, but package httptest
+// adds a flag which I'm not particularly eager to expose. This is essentially a
+// ResponseRecorder that has been specialized for the purpose at hand to avoid
+// the httptest dependency.
+type autoOptionsProxy struct {
+ w http.ResponseWriter
+ c *web.C
+ state autoOptionsState
+}
+
+func (p *autoOptionsProxy) Header() http.Header {
+ return p.w.Header()
+}
+
+func (p *autoOptionsProxy) Write(buf []byte) (int, error) {
+ switch p.state {
+ case aosInit:
+ p.state = aosHeaderWritten
+ case aosProxying:
+ return len(buf), nil
+ }
+ return p.w.Write(buf)
+}
+
+func (p *autoOptionsProxy) WriteHeader(code int) {
+ methods := getValidMethods(*p.c)
+ switch p.state {
+ case aosInit:
+ if methods != nil && code == http.StatusNotFound {
+ p.state = aosProxying
+ break
+ }
+ p.state = aosHeaderWritten
+ fallthrough
+ default:
+ p.w.WriteHeader(code)
+ return
+ }
+
+ methods = addMethod(methods, "OPTIONS")
+ p.w.Header().Set("Allow", strings.Join(methods, ", "))
+ p.w.WriteHeader(http.StatusOK)
+}
+
+// AutomaticOptions automatically return an appropriate "Allow" header when the
+// request method is OPTIONS and the request would have otherwise been 404'd.
+func AutomaticOptions(c *web.C, h http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "OPTIONS" {
+ w = &autoOptionsProxy{c: c, w: w}
+ }
+
+ h.ServeHTTP(w, r)
+ }
+
+ return http.HandlerFunc(fn)
+}
+
+func getValidMethods(c web.C) []string {
+ if c.Env == nil {
+ return nil
+ }
+ v, ok := c.Env[web.ValidMethodsKey]
+ if !ok {
+ return nil
+ }
+ if methods, ok := v.([]string); ok {
+ return methods
+ }
+ return nil
+}
+
+func addMethod(methods []string, method string) []string {
+ for _, m := range methods {
+ if m == method {
+ return methods
+ }
+ }
+ return append(methods, method)
+}
diff --git a/vendor/github.com/zenazn/goji/web/middleware/realip.go b/vendor/github.com/zenazn/goji/web/middleware/realip.go
new file mode 100644
index 0000000..ae5599f
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/middleware/realip.go
@@ -0,0 +1,51 @@
+package middleware
+
+import (
+ "net/http"
+ "strings"
+)
+
+var xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For")
+var xRealIP = http.CanonicalHeaderKey("X-Real-IP")
+
+// RealIP is a middleware that sets a http.Request's RemoteAddr to the results
+// of parsing either the X-Forwarded-For header or the X-Real-IP header (in that
+// order).
+//
+// This middleware should be inserted fairly early in the middleware stack to
+// ensure that subsequent layers (e.g., request loggers) which examine the
+// RemoteAddr will see the intended value.
+//
+// You should only use this middleware if you can trust the headers passed to
+// you (in particular, the two headers this middleware uses), for example
+// because you have placed a reverse proxy like HAProxy or nginx in front of
+// Goji. If your reverse proxies are configured to pass along arbitrary header
+// values from the client, or if you use this middleware without a reverse
+// proxy, malicious clients will be able to make you very sad (or, depending on
+// how you're using RemoteAddr, vulnerable to an attack of some sort).
+func RealIP(h http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ if rip := realIP(r); rip != "" {
+ r.RemoteAddr = rip
+ }
+ h.ServeHTTP(w, r)
+ }
+
+ return http.HandlerFunc(fn)
+}
+
+func realIP(r *http.Request) string {
+ var ip string
+
+ if xff := r.Header.Get(xForwardedFor); xff != "" {
+ i := strings.Index(xff, ", ")
+ if i == -1 {
+ i = len(xff)
+ }
+ ip = xff[:i]
+ } else if xrip := r.Header.Get(xRealIP); xrip != "" {
+ ip = xrip
+ }
+
+ return ip
+}
diff --git a/vendor/github.com/zenazn/goji/web/middleware/recoverer.go b/vendor/github.com/zenazn/goji/web/middleware/recoverer.go
new file mode 100644
index 0000000..43ad648
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/middleware/recoverer.go
@@ -0,0 +1,44 @@
+package middleware
+
+import (
+ "bytes"
+ "log"
+ "net/http"
+ "runtime/debug"
+
+ "github.com/zenazn/goji/web"
+)
+
+// Recoverer is a middleware that recovers from panics, logs the panic (and a
+// backtrace), and returns a HTTP 500 (Internal Server Error) status if
+// possible.
+//
+// Recoverer prints a request ID if one is provided.
+func Recoverer(c *web.C, h http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ reqID := GetReqID(*c)
+
+ defer func() {
+ if err := recover(); err != nil {
+ printPanic(reqID, err)
+ debug.PrintStack()
+ http.Error(w, http.StatusText(500), 500)
+ }
+ }()
+
+ h.ServeHTTP(w, r)
+ }
+
+ return http.HandlerFunc(fn)
+}
+
+func printPanic(reqID string, err interface{}) {
+ var buf bytes.Buffer
+
+ if reqID != "" {
+ cW(&buf, bBlack, "[%s] ", reqID)
+ }
+ cW(&buf, bRed, "panic: %+v", err)
+
+ log.Print(buf.String())
+}
diff --git a/vendor/github.com/zenazn/goji/web/middleware/request_id.go b/vendor/github.com/zenazn/goji/web/middleware/request_id.go
new file mode 100644
index 0000000..834d8e3
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/middleware/request_id.go
@@ -0,0 +1,88 @@
+package middleware
+
+import (
+ "crypto/rand"
+ "encoding/base64"
+ "fmt"
+ "net/http"
+ "os"
+ "strings"
+ "sync/atomic"
+
+ "github.com/zenazn/goji/web"
+)
+
+// Key to use when setting the request ID.
+const RequestIDKey = "reqID"
+
+var prefix string
+var reqid uint64
+
+/*
+A quick note on the statistics here: we're trying to calculate the chance that
+two randomly generated base62 prefixes will collide. We use the formula from
+http://en.wikipedia.org/wiki/Birthday_problem
+
+P[m, n] \approx 1 - e^{-m^2/2n}
+
+We ballpark an upper bound for $m$ by imagining (for whatever reason) a server
+that restarts every second over 10 years, for $m = 86400 * 365 * 10 = 315360000$
+
+For a $k$ character base-62 identifier, we have $n(k) = 62^k$
+
+Plugging this in, we find $P[m, n(10)] \approx 5.75%$, which is good enough for
+our purposes, and is surely more than anyone would ever need in practice -- a
+process that is rebooted a handful of times a day for a hundred years has less
+than a millionth of a percent chance of generating two colliding IDs.
+*/
+
+func init() {
+ hostname, err := os.Hostname()
+ if hostname == "" || err != nil {
+ hostname = "localhost"
+ }
+ var buf [12]byte
+ var b64 string
+ for len(b64) < 10 {
+ rand.Read(buf[:])
+ b64 = base64.StdEncoding.EncodeToString(buf[:])
+ b64 = strings.NewReplacer("+", "", "/", "").Replace(b64)
+ }
+
+ prefix = fmt.Sprintf("%s/%s", hostname, b64[0:10])
+}
+
+// RequestID is a middleware that injects a request ID into the context of each
+// request. A request ID is a string of the form "host.example.com/random-0001",
+// where "random" is a base62 random string that uniquely identifies this go
+// process, and where the last number is an atomically incremented request
+// counter.
+func RequestID(c *web.C, h http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ if c.Env == nil {
+ c.Env = make(map[interface{}]interface{})
+ }
+ myid := atomic.AddUint64(&reqid, 1)
+ c.Env[RequestIDKey] = fmt.Sprintf("%s-%06d", prefix, myid)
+
+ h.ServeHTTP(w, r)
+ }
+
+ return http.HandlerFunc(fn)
+}
+
+// GetReqID returns a request ID from the given context if one is present.
+// Returns the empty string if a request ID cannot be found.
+func GetReqID(c web.C) string {
+ if c.Env == nil {
+ return ""
+ }
+ v, ok := c.Env[RequestIDKey]
+ if !ok {
+ return ""
+ }
+ if reqID, ok := v.(string); ok {
+ return reqID
+ }
+ return ""
+}
diff --git a/vendor/github.com/zenazn/goji/web/middleware/subrouter.go b/vendor/github.com/zenazn/goji/web/middleware/subrouter.go
new file mode 100644
index 0000000..e5b0921
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/middleware/subrouter.go
@@ -0,0 +1,65 @@
+package middleware
+
+import (
+ "net/http"
+
+ "github.com/zenazn/goji/web"
+)
+
+type subrouter struct {
+ c *web.C
+ h http.Handler
+}
+
+func (s subrouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ if s.c.URLParams != nil {
+ path, ok := s.c.URLParams["*"]
+ if !ok {
+ path, ok = s.c.URLParams["_"]
+ }
+ if ok {
+ oldpath := r.URL.Path
+ oldmatch := web.GetMatch(*s.c)
+ r.URL.Path = path
+ if oldmatch.Handler != nil {
+ delete(s.c.Env, web.MatchKey)
+ }
+
+ defer func() {
+ r.URL.Path = oldpath
+
+ if s.c.Env == nil {
+ return
+ }
+ if oldmatch.Handler != nil {
+ s.c.Env[web.MatchKey] = oldmatch
+ } else {
+ delete(s.c.Env, web.MatchKey)
+ }
+ }()
+ }
+ }
+ s.h.ServeHTTP(w, r)
+}
+
+/*
+SubRouter is a helper middleware that makes writing sub-routers easier.
+
+If you register a sub-router under a key like "/admin/*", Goji's router will
+automatically set c.URLParams["*"] to the unmatched path suffix. This middleware
+will help you set the request URL's Path to this unmatched suffix, allowing you
+to write sub-routers with no knowledge of what routes the parent router matches.
+
+Since Go's regular expressions do not allow you to create a capturing group
+named "*", SubRouter also accepts the string "_". For instance, to duplicate the
+semantics of the string pattern "/foo/*", you might use the regular expression
+"^/foo(?P<_>/.*)$".
+
+This middleware is Match-aware: it will un-set any explicit routing information
+contained in the Goji context in order to prevent routing loops when using
+explicit routing with sub-routers. See the documentation for Mux.Router for
+more.
+*/
+func SubRouter(c *web.C, h http.Handler) http.Handler {
+ return subrouter{c, h}
+}
diff --git a/vendor/github.com/zenazn/goji/web/middleware/terminal.go b/vendor/github.com/zenazn/goji/web/middleware/terminal.go
new file mode 100644
index 0000000..db02917
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/middleware/terminal.go
@@ -0,0 +1,60 @@
+package middleware
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+)
+
+var (
+ // Normal colors
+ nBlack = []byte{'\033', '[', '3', '0', 'm'}
+ nRed = []byte{'\033', '[', '3', '1', 'm'}
+ nGreen = []byte{'\033', '[', '3', '2', 'm'}
+ nYellow = []byte{'\033', '[', '3', '3', 'm'}
+ nBlue = []byte{'\033', '[', '3', '4', 'm'}
+ nMagenta = []byte{'\033', '[', '3', '5', 'm'}
+ nCyan = []byte{'\033', '[', '3', '6', 'm'}
+ nWhite = []byte{'\033', '[', '3', '7', 'm'}
+ // Bright colors
+ bBlack = []byte{'\033', '[', '3', '0', ';', '1', 'm'}
+ bRed = []byte{'\033', '[', '3', '1', ';', '1', 'm'}
+ bGreen = []byte{'\033', '[', '3', '2', ';', '1', 'm'}
+ bYellow = []byte{'\033', '[', '3', '3', ';', '1', 'm'}
+ bBlue = []byte{'\033', '[', '3', '4', ';', '1', 'm'}
+ bMagenta = []byte{'\033', '[', '3', '5', ';', '1', 'm'}
+ bCyan = []byte{'\033', '[', '3', '6', ';', '1', 'm'}
+ bWhite = []byte{'\033', '[', '3', '7', ';', '1', 'm'}
+
+ reset = []byte{'\033', '[', '0', 'm'}
+)
+
+var isTTY bool
+
+func init() {
+ // This is sort of cheating: if stdout is a character device, we assume
+ // that means it's a TTY. Unfortunately, there are many non-TTY
+ // character devices, but fortunately stdout is rarely set to any of
+ // them.
+ //
+ // We could solve this properly by pulling in a dependency on
+ // code.google.com/p/go.crypto/ssh/terminal, for instance, but as a
+ // heuristic for whether to print in color or in black-and-white, I'd
+ // really rather not.
+ fi, err := os.Stdout.Stat()
+ if err == nil {
+ m := os.ModeDevice | os.ModeCharDevice
+ isTTY = fi.Mode()&m == m
+ }
+}
+
+// colorWrite
+func cW(buf *bytes.Buffer, color []byte, s string, args ...interface{}) {
+ if isTTY {
+ buf.Write(color)
+ }
+ fmt.Fprintf(buf, s, args...)
+ if isTTY {
+ buf.Write(reset)
+ }
+}
diff --git a/vendor/github.com/zenazn/goji/web/middleware/urlquery.go b/vendor/github.com/zenazn/goji/web/middleware/urlquery.go
new file mode 100644
index 0000000..36c8820
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/middleware/urlquery.go
@@ -0,0 +1,24 @@
+package middleware
+
+import (
+ "github.com/zenazn/goji/web"
+ "net/http"
+)
+
+// URLQueryKey is the context key for the URL Query
+const URLQueryKey string = "urlquery"
+
+// URLQuery is a middleware to parse the URL Query parameters just once,
+// and store the resulting url.Values in the context.
+func URLQuery(c *web.C, h http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ if c.Env == nil {
+ c.Env = make(map[interface{}]interface{})
+ }
+ c.Env[URLQueryKey] = r.URL.Query()
+
+ h.ServeHTTP(w, r)
+ }
+
+ return http.HandlerFunc(fn)
+}
diff --git a/vendor/github.com/zenazn/goji/web/mutil/mutil.go b/vendor/github.com/zenazn/goji/web/mutil/mutil.go
new file mode 100644
index 0000000..e8d5b28
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/mutil/mutil.go
@@ -0,0 +1,3 @@
+// Package mutil contains various functions that are helpful when writing http
+// middleware.
+package mutil
diff --git a/vendor/github.com/zenazn/goji/web/mutil/writer_proxy.go b/vendor/github.com/zenazn/goji/web/mutil/writer_proxy.go
new file mode 100644
index 0000000..9f6d776
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/mutil/writer_proxy.go
@@ -0,0 +1,139 @@
+package mutil
+
+import (
+ "bufio"
+ "io"
+ "net"
+ "net/http"
+)
+
+// WriterProxy is a proxy around an http.ResponseWriter that allows you to hook
+// into various parts of the response process.
+type WriterProxy interface {
+ http.ResponseWriter
+ // Status returns the HTTP status of the request, or 0 if one has not
+ // yet been sent.
+ Status() int
+ // BytesWritten returns the total number of bytes sent to the client.
+ BytesWritten() int
+ // Tee causes the response body to be written to the given io.Writer in
+ // addition to proxying the writes through. Only one io.Writer can be
+ // tee'd to at once: setting a second one will overwrite the first.
+ // Writes will be sent to the proxy before being written to this
+ // io.Writer. It is illegal for the tee'd writer to be modified
+ // concurrently with writes.
+ Tee(io.Writer)
+ // Unwrap returns the original proxied target.
+ Unwrap() http.ResponseWriter
+}
+
+// WrapWriter wraps an http.ResponseWriter, returning a proxy that allows you to
+// hook into various parts of the response process.
+func WrapWriter(w http.ResponseWriter) WriterProxy {
+ _, cn := w.(http.CloseNotifier)
+ _, fl := w.(http.Flusher)
+ _, hj := w.(http.Hijacker)
+ _, rf := w.(io.ReaderFrom)
+
+ bw := basicWriter{ResponseWriter: w}
+ if cn && fl && hj && rf {
+ return &fancyWriter{bw}
+ }
+ if fl {
+ return &flushWriter{bw}
+ }
+ return &bw
+}
+
+// basicWriter wraps a http.ResponseWriter that implements the minimal
+// http.ResponseWriter interface.
+type basicWriter struct {
+ http.ResponseWriter
+ wroteHeader bool
+ code int
+ bytes int
+ tee io.Writer
+}
+
+func (b *basicWriter) WriteHeader(code int) {
+ if !b.wroteHeader {
+ b.code = code
+ b.wroteHeader = true
+ b.ResponseWriter.WriteHeader(code)
+ }
+}
+func (b *basicWriter) Write(buf []byte) (int, error) {
+ b.WriteHeader(http.StatusOK)
+ n, err := b.ResponseWriter.Write(buf)
+ if b.tee != nil {
+ _, err2 := b.tee.Write(buf[:n])
+ // Prefer errors generated by the proxied writer.
+ if err == nil {
+ err = err2
+ }
+ }
+ b.bytes += n
+ return n, err
+}
+func (b *basicWriter) maybeWriteHeader() {
+ if !b.wroteHeader {
+ b.WriteHeader(http.StatusOK)
+ }
+}
+func (b *basicWriter) Status() int {
+ return b.code
+}
+func (b *basicWriter) BytesWritten() int {
+ return b.bytes
+}
+func (b *basicWriter) Tee(w io.Writer) {
+ b.tee = w
+}
+func (b *basicWriter) Unwrap() http.ResponseWriter {
+ return b.ResponseWriter
+}
+
+// fancyWriter is a writer that additionally satisfies http.CloseNotifier,
+// http.Flusher, http.Hijacker, and io.ReaderFrom. It exists for the common case
+// of wrapping the http.ResponseWriter that package http gives you, in order to
+// make the proxied object support the full method set of the proxied object.
+type fancyWriter struct {
+ basicWriter
+}
+
+func (f *fancyWriter) CloseNotify() <-chan bool {
+ cn := f.basicWriter.ResponseWriter.(http.CloseNotifier)
+ return cn.CloseNotify()
+}
+func (f *fancyWriter) Flush() {
+ fl := f.basicWriter.ResponseWriter.(http.Flusher)
+ fl.Flush()
+}
+func (f *fancyWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ hj := f.basicWriter.ResponseWriter.(http.Hijacker)
+ return hj.Hijack()
+}
+func (f *fancyWriter) ReadFrom(r io.Reader) (int64, error) {
+ if f.basicWriter.tee != nil {
+ return io.Copy(&f.basicWriter, r)
+ }
+ rf := f.basicWriter.ResponseWriter.(io.ReaderFrom)
+ f.basicWriter.maybeWriteHeader()
+ return rf.ReadFrom(r)
+}
+
+var _ http.CloseNotifier = &fancyWriter{}
+var _ http.Flusher = &fancyWriter{}
+var _ http.Hijacker = &fancyWriter{}
+var _ io.ReaderFrom = &fancyWriter{}
+
+type flushWriter struct {
+ basicWriter
+}
+
+func (f *flushWriter) Flush() {
+ fl := f.basicWriter.ResponseWriter.(http.Flusher)
+ fl.Flush()
+}
+
+var _ http.Flusher = &flushWriter{}
diff --git a/vendor/github.com/zenazn/goji/web/mux.go b/vendor/github.com/zenazn/goji/web/mux.go
new file mode 100644
index 0000000..18b9991
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/mux.go
@@ -0,0 +1,213 @@
+package web
+
+import (
+ "net/http"
+)
+
+/*
+Mux is an HTTP multiplexer, much like net/http's ServeMux. It functions as both
+a middleware stack and as an HTTP router.
+
+Middleware provide a great abstraction for actions that must be performed on
+every request, such as request logging and authentication. To append, insert,
+and remove middleware, you can call the Use, Insert, and Abandon functions
+respectively.
+
+Routes may be added using any of the HTTP verb functions (Get, Post, etc.), or
+through the generic Handle function. Goji's routing algorithm is very simple:
+routes are processed in the order they are added, and the first matching route
+will be executed. Routes match if their HTTP method and Pattern both match.
+*/
+type Mux struct {
+ ms mStack
+ rt router
+}
+
+// New creates a new Mux without any routes or middleware.
+func New() *Mux {
+ mux := Mux{
+ ms: mStack{
+ stack: make([]mLayer, 0),
+ pool: makeCPool(),
+ },
+ rt: router{
+ routes: make([]route, 0),
+ notFound: parseHandler(http.NotFound),
+ },
+ }
+ mux.ms.router = &mux.rt
+ return &mux
+}
+
+// ServeHTTP processes HTTP requests. Satisfies net/http.Handler.
+func (m *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ stack := m.ms.alloc()
+ stack.ServeHTTP(w, r)
+ m.ms.release(stack)
+}
+
+// ServeHTTPC creates a context dependent request with the given Mux. Satisfies
+// the Handler interface.
+func (m *Mux) ServeHTTPC(c C, w http.ResponseWriter, r *http.Request) {
+ stack := m.ms.alloc()
+ stack.ServeHTTPC(c, w, r)
+ m.ms.release(stack)
+}
+
+// Middleware Stack functions
+
+// Use appends the given middleware to the middleware stack.
+//
+// No attempt is made to enforce the uniqueness of middlewares. It is illegal to
+// call this function concurrently with active requests.
+func (m *Mux) Use(middleware MiddlewareType) {
+ m.ms.Use(middleware)
+}
+
+// Insert inserts the given middleware immediately before a given existing
+// middleware in the stack. Returns an error if "before" cannot be found in the
+// current stack.
+//
+// No attempt is made to enforce the uniqueness of middlewares. If the insertion
+// point is ambiguous, the first (outermost) one is chosen. It is illegal to
+// call this function concurrently with active requests.
+func (m *Mux) Insert(middleware, before MiddlewareType) error {
+ return m.ms.Insert(middleware, before)
+}
+
+// Abandon removes the given middleware from the middleware stack. Returns an
+// error if no such middleware can be found.
+//
+// If the name of the middleware to delete is ambiguous, the first (outermost)
+// one is chosen. It is illegal to call this function concurrently with active
+// requests.
+func (m *Mux) Abandon(middleware MiddlewareType) error {
+ return m.ms.Abandon(middleware)
+}
+
+// Router functions
+
+type routerMiddleware struct {
+ m *Mux
+ c *C
+ h http.Handler
+}
+
+func (rm routerMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ if rm.c.Env == nil {
+ rm.c.Env = make(map[interface{}]interface{}, 1)
+ }
+ rm.c.Env[MatchKey] = rm.m.rt.getMatch(rm.c, w, r)
+ rm.h.ServeHTTP(w, r)
+}
+
+/*
+Router is a middleware that performs routing and stores the resulting Match in
+Goji's environment. If a routing Match is present at the end of the middleware
+stack, that Match is used instead of re-routing.
+
+This middleware is especially useful to create post-routing middleware, e.g. a
+request logger which prints which pattern or handler was selected, or an
+authentication middleware which only applies to certain routes.
+
+If you use nested Muxes with explicit routing, you should be aware that the
+explicit routing information set by an outer Mux can be picked up by an inner
+Mux, inadvertently causing an infinite routing loop. If you use both explicit
+routing and nested Muxes, you should be sure to unset MatchKey before the inner
+Mux performs routing (or attach a Router to the inner Mux as well).
+*/
+func (m *Mux) Router(c *C, h http.Handler) http.Handler {
+ return routerMiddleware{m, c, h}
+}
+
+/*
+Handle dispatches to the given handler when the pattern matches, regardless of
+HTTP method.
+
+This method is commonly used to implement sub-routing: an admin application, for
+instance, can expose a single handler that is attached to the main Mux by
+calling Handle("/admin/*", adminHandler) or similar. Note that this function
+doesn't strip this prefix from the path before forwarding it on (e.g., the
+handler will see the full path, including the "/admin/" part), but this
+functionality can easily be performed by an extra middleware layer.
+*/
+func (m *Mux) Handle(pattern PatternType, handler HandlerType) {
+ m.rt.handleUntyped(pattern, mALL, handler)
+}
+
+// Connect dispatches to the given handler when the pattern matches and the HTTP
+// method is CONNECT.
+func (m *Mux) Connect(pattern PatternType, handler HandlerType) {
+ m.rt.handleUntyped(pattern, mCONNECT, handler)
+}
+
+// Delete dispatches to the given handler when the pattern matches and the HTTP
+// method is DELETE.
+func (m *Mux) Delete(pattern PatternType, handler HandlerType) {
+ m.rt.handleUntyped(pattern, mDELETE, handler)
+}
+
+// Get dispatches to the given handler when the pattern matches and the HTTP
+// method is GET.
+//
+// All GET handlers also transparently serve HEAD requests, since net/http will
+// take care of all the fiddly bits for you. If you wish to provide an alternate
+// implementation of HEAD, you should add a handler explicitly and place it
+// above your GET handler.
+func (m *Mux) Get(pattern PatternType, handler HandlerType) {
+ m.rt.handleUntyped(pattern, mGET|mHEAD, handler)
+}
+
+// Head dispatches to the given handler when the pattern matches and the HTTP
+// method is HEAD.
+func (m *Mux) Head(pattern PatternType, handler HandlerType) {
+ m.rt.handleUntyped(pattern, mHEAD, handler)
+}
+
+// Options dispatches to the given handler when the pattern matches and the HTTP
+// method is OPTIONS.
+func (m *Mux) Options(pattern PatternType, handler HandlerType) {
+ m.rt.handleUntyped(pattern, mOPTIONS, handler)
+}
+
+// Patch dispatches to the given handler when the pattern matches and the HTTP
+// method is PATCH.
+func (m *Mux) Patch(pattern PatternType, handler HandlerType) {
+ m.rt.handleUntyped(pattern, mPATCH, handler)
+}
+
+// Post dispatches to the given handler when the pattern matches and the HTTP
+// method is POST.
+func (m *Mux) Post(pattern PatternType, handler HandlerType) {
+ m.rt.handleUntyped(pattern, mPOST, handler)
+}
+
+// Put dispatches to the given handler when the pattern matches and the HTTP
+// method is PUT.
+func (m *Mux) Put(pattern PatternType, handler HandlerType) {
+ m.rt.handleUntyped(pattern, mPUT, handler)
+}
+
+// Trace dispatches to the given handler when the pattern matches and the HTTP
+// method is TRACE.
+func (m *Mux) Trace(pattern PatternType, handler HandlerType) {
+ m.rt.handleUntyped(pattern, mTRACE, handler)
+}
+
+// NotFound sets the fallback (i.e., 404) handler for this mux.
+//
+// As a convenience, the context environment variable "goji.web.validMethods"
+// (also available as the constant ValidMethodsKey) will be set to the list of
+// HTTP methods that could have been routed had they been provided on an
+// otherwise identical request.
+func (m *Mux) NotFound(handler HandlerType) {
+ m.rt.notFound = parseHandler(handler)
+}
+
+// Compile compiles the list of routes into bytecode. This only needs to be done
+// once after all the routes have been added, and will be called automatically
+// for you (at some performance cost on the first request) if you do not call it
+// explicitly.
+func (m *Mux) Compile() {
+ m.rt.compile()
+}
diff --git a/vendor/github.com/zenazn/goji/web/pattern.go b/vendor/github.com/zenazn/goji/web/pattern.go
new file mode 100644
index 0000000..9f9fc85
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/pattern.go
@@ -0,0 +1,58 @@
+package web
+
+import (
+ "log"
+ "net/http"
+ "regexp"
+)
+
+// A Pattern determines whether or not a given request matches some criteria.
+// They are often used in routes, which are essentially (pattern, methodSet,
+// handler) tuples. If the method and pattern match, the given handler is used.
+//
+// Built-in implementations of this interface are used to implement regular
+// expression and string matching.
+type Pattern interface {
+ // In practice, most real-world routes have a string prefix that can be
+ // used to quickly determine if a pattern is an eligible match. The
+ // router uses the result of this function to optimize away calls to the
+ // full Match function, which is likely much more expensive to compute.
+ // If your Pattern does not support prefixes, this function should
+ // return the empty string.
+ Prefix() string
+ // Returns true if the request satisfies the pattern. This function is
+ // free to examine both the request and the context to make this
+ // decision. Match should not modify either argument, and since it will
+ // potentially be called several times over the course of matching a
+ // request, it should be reasonably efficient.
+ Match(r *http.Request, c *C) bool
+ // Run the pattern on the request and context, modifying the context as
+ // necessary to bind URL parameters or other parsed state.
+ Run(r *http.Request, c *C)
+}
+
+const unknownPattern = `Unknown pattern type %T. See http://godoc.org/github.com/zenazn/goji/web#PatternType for a list of acceptable types.`
+
+/*
+ParsePattern is used internally by Goji to parse route patterns. It is exposed
+publicly to make it easier to write thin wrappers around the built-in Pattern
+implementations.
+
+ParsePattern fatally exits (using log.Fatalf) if it is passed a value of an
+unexpected type (see the documentation for PatternType for a list of which types
+are accepted). It is the caller's responsibility to ensure that ParsePattern is
+called in a type-safe manner.
+*/
+func ParsePattern(raw PatternType) Pattern {
+ switch v := raw.(type) {
+ case Pattern:
+ return v
+ case *regexp.Regexp:
+ return parseRegexpPattern(v)
+ case string:
+ return parseStringPattern(v)
+ default:
+ log.Fatalf(unknownPattern, v)
+ panic("log.Fatalf does not return")
+ }
+}
diff --git a/vendor/github.com/zenazn/goji/web/regexp_pattern.go b/vendor/github.com/zenazn/goji/web/regexp_pattern.go
new file mode 100644
index 0000000..95e7e09
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/regexp_pattern.go
@@ -0,0 +1,149 @@
+package web
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "net/http"
+ "regexp"
+ "regexp/syntax"
+)
+
+type regexpPattern struct {
+ re *regexp.Regexp
+ prefix string
+ names []string
+}
+
+func (p regexpPattern) Prefix() string {
+ return p.prefix
+}
+func (p regexpPattern) Match(r *http.Request, c *C) bool {
+ return p.match(r, c, false)
+}
+func (p regexpPattern) Run(r *http.Request, c *C) {
+ p.match(r, c, false)
+}
+
+func (p regexpPattern) match(r *http.Request, c *C, dryrun bool) bool {
+ matches := p.re.FindStringSubmatch(r.URL.Path)
+ if matches == nil || len(matches) == 0 {
+ return false
+ }
+
+ if c == nil || dryrun || len(matches) == 1 {
+ return true
+ }
+
+ if c.URLParams == nil {
+ c.URLParams = make(map[string]string, len(matches)-1)
+ }
+ for i := 1; i < len(matches); i++ {
+ c.URLParams[p.names[i]] = matches[i]
+ }
+ return true
+}
+
+func (p regexpPattern) String() string {
+ return fmt.Sprintf("regexpPattern(%v)", p.re)
+}
+
+func (p regexpPattern) Raw() *regexp.Regexp {
+ return p.re
+}
+
+/*
+I'm sorry, dear reader. I really am.
+
+The problem here is to take an arbitrary regular expression and:
+1. return a regular expression that is just like it, but left-anchored,
+ preferring to return the original if possible.
+2. determine a string literal prefix that all matches of this regular expression
+ have, much like regexp.Regexp.Prefix(). Unfortunately, Prefix() does not work
+ in the presence of anchors, so we need to write it ourselves.
+
+What this actually means is that we need to sketch on the internals of the
+standard regexp library to forcefully extract the information we want.
+
+Unfortunately, regexp.Regexp hides a lot of its state, so our abstraction is
+going to be pretty leaky. The biggest leak is that we blindly assume that all
+regular expressions are perl-style, not POSIX. This is probably Mostly True, and
+I think most users of the library probably won't be able to notice.
+*/
+func sketchOnRegex(re *regexp.Regexp) (*regexp.Regexp, string) {
+ rawRe := re.String()
+ sRe, err := syntax.Parse(rawRe, syntax.Perl)
+ if err != nil {
+ log.Printf("WARN(web): unable to parse regexp %v as perl. "+
+ "This route might behave unexpectedly.", re)
+ return re, ""
+ }
+ sRe = sRe.Simplify()
+ p, err := syntax.Compile(sRe)
+ if err != nil {
+ log.Printf("WARN(web): unable to compile regexp %v. This "+
+ "route might behave unexpectedly.", re)
+ return re, ""
+ }
+ if p.StartCond()&syntax.EmptyBeginText == 0 {
+ // I hope doing this is always legal...
+ newRe, err := regexp.Compile(`\A` + rawRe)
+ if err != nil {
+ log.Printf("WARN(web): unable to create a left-"+
+ "anchored regexp from %v. This route might "+
+ "behave unexpectedly", re)
+ return re, ""
+ }
+ re = newRe
+ }
+
+ // Run the regular expression more or less by hand :(
+ pc := uint32(p.Start)
+ atStart := true
+ i := &p.Inst[pc]
+ var buf bytes.Buffer
+Sadness:
+ for {
+ switch i.Op {
+ case syntax.InstEmptyWidth:
+ if !atStart {
+ break Sadness
+ }
+ case syntax.InstCapture, syntax.InstNop:
+ // nop!
+ case syntax.InstRune, syntax.InstRune1, syntax.InstRuneAny,
+ syntax.InstRuneAnyNotNL:
+
+ atStart = false
+ if len(i.Rune) != 1 ||
+ syntax.Flags(i.Arg)&syntax.FoldCase != 0 {
+ break Sadness
+ }
+ buf.WriteRune(i.Rune[0])
+ default:
+ break Sadness
+ }
+ pc = i.Out
+ i = &p.Inst[pc]
+ }
+ return re, buf.String()
+}
+
+func parseRegexpPattern(re *regexp.Regexp) regexpPattern {
+ re, prefix := sketchOnRegex(re)
+ rnames := re.SubexpNames()
+ // We have to make our own copy since package regexp forbids us
+ // from scribbling over the slice returned by SubexpNames().
+ names := make([]string, len(rnames))
+ for i, rname := range rnames {
+ if rname == "" {
+ rname = fmt.Sprintf("$%d", i)
+ }
+ names[i] = rname
+ }
+ return regexpPattern{
+ re: re,
+ prefix: prefix,
+ names: names,
+ }
+}
diff --git a/vendor/github.com/zenazn/goji/web/router.go b/vendor/github.com/zenazn/goji/web/router.go
new file mode 100644
index 0000000..1fbc41f
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/router.go
@@ -0,0 +1,154 @@
+package web
+
+import (
+ "net/http"
+ "sort"
+ "strings"
+ "sync"
+)
+
+type method int
+
+const (
+ mCONNECT method = 1 << iota
+ mDELETE
+ mGET
+ mHEAD
+ mOPTIONS
+ mPATCH
+ mPOST
+ mPUT
+ mTRACE
+ // We only natively support the methods above, but we pass through other
+ // methods. This constant pretty much only exists for the sake of mALL.
+ mIDK
+
+ mALL method = mCONNECT | mDELETE | mGET | mHEAD | mOPTIONS | mPATCH |
+ mPOST | mPUT | mTRACE | mIDK
+)
+
+// The key used to communicate to the NotFound handler what methods would have
+// been allowed if they'd been provided.
+const ValidMethodsKey = "goji.web.ValidMethods"
+
+var validMethodsMap = map[string]method{
+ "CONNECT": mCONNECT,
+ "DELETE": mDELETE,
+ "GET": mGET,
+ "HEAD": mHEAD,
+ "OPTIONS": mOPTIONS,
+ "PATCH": mPATCH,
+ "POST": mPOST,
+ "PUT": mPUT,
+ "TRACE": mTRACE,
+}
+
+type route struct {
+ prefix string
+ method method
+ pattern Pattern
+ handler Handler
+}
+
+type router struct {
+ lock sync.Mutex
+ routes []route
+ notFound Handler
+ machine *routeMachine
+}
+
+func httpMethod(mname string) method {
+ if method, ok := validMethodsMap[mname]; ok {
+ return method
+ }
+ return mIDK
+}
+
+func (rt *router) compile() *routeMachine {
+ rt.lock.Lock()
+ defer rt.lock.Unlock()
+ sm := routeMachine{
+ sm: compile(rt.routes),
+ routes: rt.routes,
+ }
+ rt.setMachine(&sm)
+ return &sm
+}
+
+func (rt *router) getMatch(c *C, w http.ResponseWriter, r *http.Request) Match {
+ rm := rt.getMachine()
+ if rm == nil {
+ rm = rt.compile()
+ }
+
+ methods, route := rm.route(c, w, r)
+ if route != nil {
+ return Match{
+ Pattern: route.pattern,
+ Handler: route.handler,
+ }
+ }
+
+ if methods == 0 {
+ return Match{Handler: rt.notFound}
+ }
+
+ var methodsList = make([]string, 0)
+ for mname, meth := range validMethodsMap {
+ if methods&meth != 0 {
+ methodsList = append(methodsList, mname)
+ }
+ }
+ sort.Strings(methodsList)
+
+ if c.Env == nil {
+ c.Env = map[interface{}]interface{}{
+ ValidMethodsKey: methodsList,
+ }
+ } else {
+ c.Env[ValidMethodsKey] = methodsList
+ }
+ return Match{Handler: rt.notFound}
+}
+
+func (rt *router) route(c *C, w http.ResponseWriter, r *http.Request) {
+ match := GetMatch(*c)
+ if match.Handler == nil {
+ match = rt.getMatch(c, w, r)
+ }
+ match.Handler.ServeHTTPC(*c, w, r)
+}
+
+func (rt *router) handleUntyped(p PatternType, m method, h HandlerType) {
+ rt.handle(ParsePattern(p), m, parseHandler(h))
+}
+
+func (rt *router) handle(p Pattern, m method, h Handler) {
+ rt.lock.Lock()
+ defer rt.lock.Unlock()
+
+ // Calculate the sorted insertion point, because there's no reason to do
+ // swapping hijinks if we're already making a copy. We need to use
+ // bubble sort because we can only compare adjacent elements.
+ pp := p.Prefix()
+ var i int
+ for i = len(rt.routes); i > 0; i-- {
+ rip := rt.routes[i-1].prefix
+ if rip <= pp || strings.HasPrefix(rip, pp) {
+ break
+ }
+ }
+
+ newRoutes := make([]route, len(rt.routes)+1)
+ copy(newRoutes, rt.routes[:i])
+ newRoutes[i] = route{
+ prefix: pp,
+ method: m,
+ pattern: p,
+ handler: h,
+ }
+ copy(newRoutes[i+1:], rt.routes[i:])
+
+ rt.setMachine(nil)
+ rt.routes = newRoutes
+}
diff --git a/vendor/github.com/zenazn/goji/web/string_pattern.go b/vendor/github.com/zenazn/goji/web/string_pattern.go
new file mode 100644
index 0000000..aa9b33a
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/string_pattern.go
@@ -0,0 +1,137 @@
+package web
+
+import (
+ "fmt"
+ "net/http"
+ "regexp"
+ "strings"
+)
+
+// stringPattern is a struct describing
+type stringPattern struct {
+ raw string
+ pats []string
+ breaks []byte
+ literals []string
+ wildcard bool
+}
+
+func (s stringPattern) Prefix() string {
+ return s.literals[0]
+}
+func (s stringPattern) Match(r *http.Request, c *C) bool {
+ return s.match(r, c, true)
+}
+func (s stringPattern) Run(r *http.Request, c *C) {
+ s.match(r, c, false)
+}
+func (s stringPattern) match(r *http.Request, c *C, dryrun bool) bool {
+ path := r.URL.Path
+ var matches map[string]string
+ if !dryrun {
+ if s.wildcard {
+ matches = make(map[string]string, len(s.pats)+1)
+ } else if len(s.pats) != 0 {
+ matches = make(map[string]string, len(s.pats))
+ }
+ }
+ for i, pat := range s.pats {
+ sli := s.literals[i]
+ if !strings.HasPrefix(path, sli) {
+ return false
+ }
+ path = path[len(sli):]
+
+ m := 0
+ bc := s.breaks[i]
+ for ; m < len(path); m++ {
+ if path[m] == bc || path[m] == '/' {
+ break
+ }
+ }
+ if m == 0 {
+ // Empty strings are not matches, otherwise routes like
+ // "/:foo" would match the path "/"
+ return false
+ }
+ if !dryrun {
+ matches[pat] = path[:m]
+ }
+ path = path[m:]
+ }
+ // There's exactly one more literal than pat.
+ tail := s.literals[len(s.pats)]
+ if s.wildcard {
+ if !strings.HasPrefix(path, tail) {
+ return false
+ }
+ if !dryrun {
+ matches["*"] = path[len(tail)-1:]
+ }
+ } else if path != tail {
+ return false
+ }
+
+ if c == nil || dryrun {
+ return true
+ }
+
+ if c.URLParams == nil {
+ c.URLParams = matches
+ } else {
+ for k, v := range matches {
+ c.URLParams[k] = v
+ }
+ }
+ return true
+}
+
+func (s stringPattern) String() string {
+ return fmt.Sprintf("stringPattern(%q)", s.raw)
+}
+
+func (s stringPattern) Raw() string {
+ return s.raw
+}
+
+// "Break characters" are characters that can end patterns. They are not allowed
+// to appear in pattern names. "/" was chosen because it is the standard path
+// separator, and "." was chosen because it often delimits file extensions. ";"
+// and "," were chosen because Section 3.3 of RFC 3986 suggests their use.
+const bc = "/.;,"
+
+var patternRe = regexp.MustCompile(`[` + bc + `]:([^` + bc + `]+)`)
+
+func parseStringPattern(s string) stringPattern {
+ raw := s
+ var wildcard bool
+ if strings.HasSuffix(s, "/*") {
+ s = s[:len(s)-1]
+ wildcard = true
+ }
+
+ matches := patternRe.FindAllStringSubmatchIndex(s, -1)
+ pats := make([]string, len(matches))
+ breaks := make([]byte, len(matches))
+ literals := make([]string, len(matches)+1)
+ n := 0
+ for i, match := range matches {
+ a, b := match[2], match[3]
+ literals[i] = s[n : a-1] // Need to leave off the colon
+ pats[i] = s[a:b]
+ if b == len(s) {
+ breaks[i] = '/'
+ } else {
+ breaks[i] = s[b]
+ }
+ n = b
+ }
+ literals[len(matches)] = s[n:]
+ return stringPattern{
+ raw: raw,
+ pats: pats,
+ breaks: breaks,
+ literals: literals,
+ wildcard: wildcard,
+ }
+}
diff --git a/vendor/github.com/zenazn/goji/web/web.go b/vendor/github.com/zenazn/goji/web/web.go
new file mode 100644
index 0000000..21f6fcc
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/web/web.go
@@ -0,0 +1,112 @@
+/*
+Package web provides a fast and flexible middleware stack and mux.
+
+This package attempts to solve three problems that net/http does not. First, it
+allows you to specify flexible patterns, including routes with named parameters
+and regular expressions. Second, it allows you to write reconfigurable
+middleware stacks. And finally, it allows you to attach additional context to
+requests, in a manner that can be manipulated by both compliant middleware and
+handlers.
+*/
+package web
+
+import (
+ "net/http"
+)
+
+/*
+C is a request-local context object which is threaded through all compliant
+middleware layers and given to the final request handler.
+*/
+type C struct {
+ // URLParams is a map of variables extracted from the URL (typically
+ // from the path portion) during routing. See the documentation for the
+ // URL Pattern you are using (or the documentation for PatternType for
+ // the case of standard pattern types) for more information about how
+ // variables are extracted and named.
+ URLParams map[string]string
+ // Env is a free-form environment for storing request-local data. Keys
+ // may be arbitrary types that support equality, however package-private
+ // types with type-safe accessors provide a convenient way for packages
+ // to mediate access to their request-local data.
+ Env map[interface{}]interface{}
+}
+
+// Handler is similar to net/http's http.Handler, but also accepts a Goji
+// context object.
+type Handler interface {
+ ServeHTTPC(C, http.ResponseWriter, *http.Request)
+}
+
+// HandlerFunc is similar to net/http's http.HandlerFunc, but supports a context
+// object. Implements both http.Handler and Handler.
+type HandlerFunc func(C, http.ResponseWriter, *http.Request)
+
+// ServeHTTP implements http.Handler, allowing HandlerFunc's to be used with
+// net/http and other compliant routers. When used in this way, the underlying
+// function will be passed an empty context.
+func (h HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ h(C{}, w, r)
+}
+
+// ServeHTTPC implements Handler.
+func (h HandlerFunc) ServeHTTPC(c C, w http.ResponseWriter, r *http.Request) {
+ h(c, w, r)
+}
+
+/*
+PatternType is the type denoting Patterns and types that Goji internally
+converts to Pattern (via the ParsePattern function). In order to provide an
+expressive API, this type is an alias for interface{} that is named for the
+purposes of documentation, however only the following concrete types are
+accepted:
+ - types that implement Pattern
+ - string, which is interpreted as a Sinatra-like URL pattern. In
+ particular, the following syntax is recognized:
+ - a path segment starting with a colon will match any
+ string placed at that position. e.g., "/:name" will match
+ "/carl", binding "name" to "carl".
+ - a pattern ending with "/*" will match any route with that
+ prefix. For instance, the pattern "/u/:name/*" will match
+ "/u/carl/" and "/u/carl/projects/123", but not "/u/carl"
+ (because there is no trailing slash). In addition to any names
+ bound in the pattern, the special key "*" is bound to the
+ unmatched tail of the match, but including the leading "/". So
+ for the two matching examples above, "*" would be bound to "/"
+ and "/projects/123" respectively.
+ Unlike http.ServeMux's patterns, string patterns support neither the
+ "rooted subtree" behavior nor Host-specific routes. Users who require
+ either of these features are encouraged to compose package http's mux
+ with the mux provided by this package.
+ - regexp.Regexp, which is assumed to be a Perl-style regular expression
+ that is anchored on the left (i.e., the beginning of the string). If
+ your regular expression is not anchored on the left, a
+ hopefully-identical left-anchored regular expression will be created
+ and used instead.
+
+ Capturing groups will be converted into bound URL parameters in
+ URLParams. If the capturing group is named, that name will be used;
+ otherwise the special identifiers "$1", "$2", etc. will be used.
+*/
+type PatternType interface{}
+
+/*
+HandlerType is the type of Handlers and types that Goji internally converts to
+Handler. In order to provide an expressive API, this type is an alias for
+interface{} that is named for the purposes of documentation, however only the
+following concrete types are accepted:
+ - types that implement http.Handler
+ - types that implement Handler
+ - func(http.ResponseWriter, *http.Request)
+ - func(web.C, http.ResponseWriter, *http.Request)
+*/
+type HandlerType interface{}
+
+/*
+MiddlewareType is the type of Goji middleware. In order to provide an expressive
+API, this type is an alias for interface{} that is named for the purposes of
+documentation, however only the following concrete types are accepted:
+ - func(http.Handler) http.Handler
+ - func(*web.C, http.Handler) http.Handler
+*/
+type MiddlewareType interface{}