aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/zenazn/goji
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
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')
-rw-r--r--vendor/github.com/zenazn/goji/LICENSE20
-rw-r--r--vendor/github.com/zenazn/goji/bind/bind.go155
-rw-r--r--vendor/github.com/zenazn/goji/bind/einhorn.go91
-rw-r--r--vendor/github.com/zenazn/goji/bind/einhorn_stub.go12
-rw-r--r--vendor/github.com/zenazn/goji/bind/systemd.go36
-rw-r--r--vendor/github.com/zenazn/goji/bind/systemd_stub.go6
-rw-r--r--vendor/github.com/zenazn/goji/default.go102
-rw-r--r--vendor/github.com/zenazn/goji/example/main.go177
-rw-r--r--vendor/github.com/zenazn/goji/example/middleware.go47
-rw-r--r--vendor/github.com/zenazn/goji/example/models.go49
-rw-r--r--vendor/github.com/zenazn/goji/goji.go36
-rw-r--r--vendor/github.com/zenazn/goji/graceful/clone.go11
-rw-r--r--vendor/github.com/zenazn/goji/graceful/clone16.go34
-rw-r--r--vendor/github.com/zenazn/goji/graceful/einhorn.go21
-rw-r--r--vendor/github.com/zenazn/goji/graceful/graceful.go62
-rw-r--r--vendor/github.com/zenazn/goji/graceful/listener/conn.go151
-rw-r--r--vendor/github.com/zenazn/goji/graceful/listener/listener.go178
-rw-r--r--vendor/github.com/zenazn/goji/graceful/listener/shard.go98
-rw-r--r--vendor/github.com/zenazn/goji/graceful/middleware.go103
-rw-r--r--vendor/github.com/zenazn/goji/graceful/serve.go33
-rw-r--r--vendor/github.com/zenazn/goji/graceful/serve13.go76
-rw-r--r--vendor/github.com/zenazn/goji/graceful/server.go108
-rw-r--r--vendor/github.com/zenazn/goji/graceful/signal.go197
-rw-r--r--vendor/github.com/zenazn/goji/serve.go64
-rw-r--r--vendor/github.com/zenazn/goji/serve_appengine.go23
-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
54 files changed, 4190 insertions, 0 deletions
diff --git a/vendor/github.com/zenazn/goji/LICENSE b/vendor/github.com/zenazn/goji/LICENSE
new file mode 100644
index 0000000..446aba0
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2014, 2015, 2016 Carl Jackson (carl@avtok.com)
+
+MIT License
+
+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.
diff --git a/vendor/github.com/zenazn/goji/bind/bind.go b/vendor/github.com/zenazn/goji/bind/bind.go
new file mode 100644
index 0000000..43d11dd
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/bind/bind.go
@@ -0,0 +1,155 @@
+/*
+Package bind provides a convenient way to bind to sockets. It exposes a flag in
+the default flag set named "bind" which provides syntax to bind TCP and UNIX
+sockets. It also supports binding to arbitrary file descriptors passed by a
+parent (for instance, systemd), and for binding to Einhorn sockets (including
+Einhorn ACK support).
+
+If the value passed to bind contains a colon, as in ":8000" or "127.0.0.1:9001",
+it will be treated as a TCP address. If it begins with a "/" or a ".", it will
+be treated as a path to a UNIX socket. If it begins with the string "fd@", as in
+"fd@3", it will be treated as a file descriptor (useful for use with systemd,
+for instance). If it begins with the string "einhorn@", as in "einhorn@0", the
+corresponding einhorn socket will be used.
+
+If an option is not explicitly passed, the implementation will automatically
+select between using "einhorn@0", "fd@3", and ":8000", depending on whether
+Einhorn or systemd (or neither) is detected.
+
+This package is a teensy bit magical, and goes out of its way to Do The Right
+Thing in many situations, including in both development and production. If
+you're looking for something less magical, you'd probably be better off just
+calling net.Listen() the old-fashioned way.
+*/
+package bind
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "net"
+ "os"
+ "strconv"
+ "strings"
+ "sync"
+)
+
+var bind string
+
+func init() {
+ einhornInit()
+ systemdInit()
+}
+
+// DefaultBind specifies the fallback used for WithFlag() if it is
+// unable to discover an environment hint (after checking $GOJI_BIND,
+// Einhorn, systemd, and $PORT).
+//
+// If DefaultBind is overridden, it must be set before calling
+// WithFlag().
+var DefaultBind = ":8000"
+
+// WithFlag adds a standard flag to the global flag instance that
+// allows configuration of the default socket. Users who call
+// Default() must call this function before flags are parsed, for
+// example in an init() block.
+//
+// When selecting the default bind string, this function will examine
+// its environment for hints about what port to bind to, selecting the
+// GOJI_BIND environment variable, Einhorn, systemd, the PORT
+// environment variable, and the value of DefaultBind, in order. In
+// most cases, this means that the default behavior of the default
+// socket will be reasonable for use in your circumstance.
+func WithFlag() {
+ s := Sniff()
+ if s == "" {
+ s = DefaultBind
+ }
+ flag.StringVar(&bind, "bind", s,
+ `Address to bind on. If this value has a colon, as in ":8000" or
+ "127.0.0.1:9001", it will be treated as a TCP address. If it
+ begins with a "/" or a ".", it will be treated as a path to a
+ UNIX socket. If it begins with the string "fd@", as in "fd@3",
+ it will be treated as a file descriptor (useful for use with
+ systemd, for instance). If it begins with the string "einhorn@",
+ as in "einhorn@0", the corresponding einhorn socket will be
+ used. If an option is not explicitly passed, the implementation
+ will automatically select among "einhorn@0" (Einhorn), "fd@3"
+ (systemd), and ":8000" (fallback) based on its environment.`)
+}
+
+// Sniff attempts to select a sensible default bind string by examining its
+// environment. It examines the GOJI_BIND environment variable, Einhorn,
+// systemd, and the PORT environment variable, in that order, selecting the
+// first plausible option. It returns the empty string if no sensible default
+// could be extracted from the environment.
+func Sniff() string {
+ if bind := os.Getenv("GOJI_BIND"); bind != "" {
+ return bind
+ } else if usingEinhorn() {
+ return "einhorn@0"
+ } else if usingSystemd() {
+ return "fd@3"
+ } else if port := os.Getenv("PORT"); port != "" {
+ return ":" + port
+ }
+ return ""
+}
+
+func listenTo(bind string) (net.Listener, error) {
+ if strings.Contains(bind, ":") {
+ return net.Listen("tcp", bind)
+ } else if strings.HasPrefix(bind, ".") || strings.HasPrefix(bind, "/") {
+ return net.Listen("unix", bind)
+ } else if strings.HasPrefix(bind, "fd@") {
+ fd, err := strconv.Atoi(bind[3:])
+ if err != nil {
+ return nil, fmt.Errorf("error while parsing fd %v: %v",
+ bind, err)
+ }
+ f := os.NewFile(uintptr(fd), bind)
+ defer f.Close()
+ return net.FileListener(f)
+ } else if strings.HasPrefix(bind, "einhorn@") {
+ fd, err := strconv.Atoi(bind[8:])
+ if err != nil {
+ return nil, fmt.Errorf(
+ "error while parsing einhorn %v: %v", bind, err)
+ }
+ return einhornBind(fd)
+ }
+
+ return nil, fmt.Errorf("error while parsing bind arg %v", bind)
+}
+
+// Socket parses and binds to the specified address. If Socket encounters an
+// error while parsing or binding to the given socket it will exit by calling
+// log.Fatal.
+func Socket(bind string) net.Listener {
+ l, err := listenTo(bind)
+ if err != nil {
+ log.Fatal(err)
+ }
+ return l
+}
+
+// Default parses and binds to the default socket as given to us by the flag
+// module. If there was an error parsing or binding to that socket, Default will
+// exit by calling `log.Fatal`.
+func Default() net.Listener {
+ return Socket(bind)
+}
+
+// I'm not sure why you'd ever want to call Ready() more than once, but we may
+// as well be safe against it...
+var ready sync.Once
+
+// Ready notifies the environment (for now, just Einhorn) that the process is
+// ready to receive traffic. Should be called at the last possible moment to
+// maximize the chances that a faulty process exits before signaling that it's
+// ready.
+func Ready() {
+ ready.Do(func() {
+ einhornAck()
+ })
+}
diff --git a/vendor/github.com/zenazn/goji/bind/einhorn.go b/vendor/github.com/zenazn/goji/bind/einhorn.go
new file mode 100644
index 0000000..e695c0e
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/bind/einhorn.go
@@ -0,0 +1,91 @@
+// +build !windows
+
+package bind
+
+import (
+ "fmt"
+ "log"
+ "net"
+ "os"
+ "strconv"
+ "syscall"
+)
+
+const tooBigErr = "bind: einhorn@%d not found (einhorn only passed %d fds)"
+const bindErr = "bind: could not bind einhorn@%d: not running under einhorn"
+const einhornErr = "bind: einhorn environment initialization error"
+const ackErr = "bind: error ACKing to einhorn: %v"
+
+var einhornNumFds int
+
+func envInt(val string) (int, error) {
+ return strconv.Atoi(os.Getenv(val))
+}
+
+// Unfortunately this can't be a normal init function, because their execution
+// order is undefined, and we need to run before the init() in bind.go.
+func einhornInit() {
+ mpid, err := envInt("EINHORN_MASTER_PID")
+ if err != nil || mpid != os.Getppid() {
+ return
+ }
+
+ einhornNumFds, err = envInt("EINHORN_FD_COUNT")
+ if err != nil {
+ einhornNumFds = 0
+ return
+ }
+
+ // Prevent einhorn's fds from leaking to our children
+ for i := 0; i < einhornNumFds; i++ {
+ syscall.CloseOnExec(einhornFdMap(i))
+ }
+}
+
+func usingEinhorn() bool {
+ return einhornNumFds > 0
+}
+
+func einhornFdMap(n int) int {
+ name := fmt.Sprintf("EINHORN_FD_%d", n)
+ fno, err := envInt(name)
+ if err != nil {
+ log.Fatal(einhornErr)
+ }
+ return fno
+}
+
+func einhornBind(n int) (net.Listener, error) {
+ if !usingEinhorn() {
+ return nil, fmt.Errorf(bindErr, n)
+ }
+ if n >= einhornNumFds || n < 0 {
+ return nil, fmt.Errorf(tooBigErr, n, einhornNumFds)
+ }
+
+ fno := einhornFdMap(n)
+ f := os.NewFile(uintptr(fno), fmt.Sprintf("einhorn@%d", n))
+ defer f.Close()
+ return net.FileListener(f)
+}
+
+// Fun story: this is actually YAML, not JSON.
+const ackMsg = `{"command": "worker:ack", "pid": %d}` + "\n"
+
+func einhornAck() {
+ if !usingEinhorn() {
+ return
+ }
+ log.Print("bind: ACKing to einhorn")
+
+ ctl, err := net.Dial("unix", os.Getenv("EINHORN_SOCK_PATH"))
+ if err != nil {
+ log.Fatalf(ackErr, err)
+ }
+ defer ctl.Close()
+
+ _, err = fmt.Fprintf(ctl, ackMsg, os.Getpid())
+ if err != nil {
+ log.Fatalf(ackErr, err)
+ }
+}
diff --git a/vendor/github.com/zenazn/goji/bind/einhorn_stub.go b/vendor/github.com/zenazn/goji/bind/einhorn_stub.go
new file mode 100644
index 0000000..093707f
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/bind/einhorn_stub.go
@@ -0,0 +1,12 @@
+// +build windows
+
+package bind
+
+import (
+ "net"
+)
+
+func einhornInit() {}
+func einhornAck() {}
+func einhornBind(fd int) (net.Listener, error) { return nil, nil }
+func usingEinhorn() bool { return false }
diff --git a/vendor/github.com/zenazn/goji/bind/systemd.go b/vendor/github.com/zenazn/goji/bind/systemd.go
new file mode 100644
index 0000000..e7cd8e4
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/bind/systemd.go
@@ -0,0 +1,36 @@
+// +build !windows
+
+package bind
+
+import (
+ "os"
+ "syscall"
+)
+
+const systemdMinFd = 3
+
+var systemdNumFds int
+
+// Unfortunately this can't be a normal init function, because their execution
+// order is undefined, and we need to run before the init() in bind.go.
+func systemdInit() {
+ pid, err := envInt("LISTEN_PID")
+ if err != nil || pid != os.Getpid() {
+ return
+ }
+
+ systemdNumFds, err = envInt("LISTEN_FDS")
+ if err != nil {
+ systemdNumFds = 0
+ return
+ }
+
+ // Prevent fds from leaking to our children
+ for i := 0; i < systemdNumFds; i++ {
+ syscall.CloseOnExec(systemdMinFd + i)
+ }
+}
+
+func usingSystemd() bool {
+ return systemdNumFds > 0
+}
diff --git a/vendor/github.com/zenazn/goji/bind/systemd_stub.go b/vendor/github.com/zenazn/goji/bind/systemd_stub.go
new file mode 100644
index 0000000..4ad4d20
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/bind/systemd_stub.go
@@ -0,0 +1,6 @@
+// +build windows
+
+package bind
+
+func systemdInit() {}
+func usingSystemd() bool { return false }
diff --git a/vendor/github.com/zenazn/goji/default.go b/vendor/github.com/zenazn/goji/default.go
new file mode 100644
index 0000000..540e792
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/default.go
@@ -0,0 +1,102 @@
+package goji
+
+import (
+ "github.com/zenazn/goji/web"
+ "github.com/zenazn/goji/web/middleware"
+)
+
+// The default web.Mux.
+var DefaultMux *web.Mux
+
+func init() {
+ DefaultMux = web.New()
+
+ DefaultMux.Use(middleware.RequestID)
+ DefaultMux.Use(middleware.Logger)
+ DefaultMux.Use(middleware.Recoverer)
+ DefaultMux.Use(middleware.AutomaticOptions)
+}
+
+// Use appends the given middleware to the default Mux's middleware stack. See
+// the documentation for web.Mux.Use for more information.
+func Use(middleware web.MiddlewareType) {
+ DefaultMux.Use(middleware)
+}
+
+// Insert the given middleware into the default Mux's middleware stack. See the
+// documentation for web.Mux.Insert for more information.
+func Insert(middleware, before web.MiddlewareType) error {
+ return DefaultMux.Insert(middleware, before)
+}
+
+// Abandon removes the given middleware from the default Mux's middleware stack.
+// See the documentation for web.Mux.Abandon for more information.
+func Abandon(middleware web.MiddlewareType) error {
+ return DefaultMux.Abandon(middleware)
+}
+
+// Handle adds a route to the default Mux. See the documentation for web.Mux for
+// more information about what types this function accepts.
+func Handle(pattern web.PatternType, handler web.HandlerType) {
+ DefaultMux.Handle(pattern, handler)
+}
+
+// Connect adds a CONNECT route to the default Mux. See the documentation for
+// web.Mux for more information about what types this function accepts.
+func Connect(pattern web.PatternType, handler web.HandlerType) {
+ DefaultMux.Connect(pattern, handler)
+}
+
+// Delete adds a DELETE route to the default Mux. See the documentation for
+// web.Mux for more information about what types this function accepts.
+func Delete(pattern web.PatternType, handler web.HandlerType) {
+ DefaultMux.Delete(pattern, handler)
+}
+
+// Get adds a GET route to the default Mux. See the documentation for web.Mux for
+// more information about what types this function accepts.
+func Get(pattern web.PatternType, handler web.HandlerType) {
+ DefaultMux.Get(pattern, handler)
+}
+
+// Head adds a HEAD route to the default Mux. See the documentation for web.Mux
+// for more information about what types this function accepts.
+func Head(pattern web.PatternType, handler web.HandlerType) {
+ DefaultMux.Head(pattern, handler)
+}
+
+// Options adds a OPTIONS route to the default Mux. See the documentation for
+// web.Mux for more information about what types this function accepts.
+func Options(pattern web.PatternType, handler web.HandlerType) {
+ DefaultMux.Options(pattern, handler)
+}
+
+// Patch adds a PATCH route to the default Mux. See the documentation for web.Mux
+// for more information about what types this function accepts.
+func Patch(pattern web.PatternType, handler web.HandlerType) {
+ DefaultMux.Patch(pattern, handler)
+}
+
+// Post adds a POST route to the default Mux. See the documentation for web.Mux
+// for more information about what types this function accepts.
+func Post(pattern web.PatternType, handler web.HandlerType) {
+ DefaultMux.Post(pattern, handler)
+}
+
+// Put adds a PUT route to the default Mux. See the documentation for web.Mux for
+// more information about what types this function accepts.
+func Put(pattern web.PatternType, handler web.HandlerType) {
+ DefaultMux.Put(pattern, handler)
+}
+
+// Trace adds a TRACE route to the default Mux. See the documentation for
+// web.Mux for more information about what types this function accepts.
+func Trace(pattern web.PatternType, handler web.HandlerType) {
+ DefaultMux.Trace(pattern, handler)
+}
+
+// NotFound sets the NotFound handler for the default Mux. See the documentation
+// for web.Mux.NotFound for more information.
+func NotFound(handler web.HandlerType) {
+ DefaultMux.NotFound(handler)
+}
diff --git a/vendor/github.com/zenazn/goji/example/main.go b/vendor/github.com/zenazn/goji/example/main.go
new file mode 100644
index 0000000..b2bcf6f
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/example/main.go
@@ -0,0 +1,177 @@
+// Command example is a sample application built with Goji. Its goal is to give
+// you a taste for what Goji looks like in the real world by artificially using
+// all of its features.
+//
+// In particular, this is a complete working site for gritter.com, a site where
+// users can post 140-character "greets". Any resemblance to real websites,
+// alive or dead, is purely coincidental.
+package main
+
+import (
+ "fmt"
+ "io"
+ "net/http"
+ "regexp"
+ "strconv"
+ "time"
+
+ "github.com/goji/param"
+ "github.com/zenazn/goji"
+ "github.com/zenazn/goji/web"
+ "github.com/zenazn/goji/web/middleware"
+)
+
+// Note: the code below cuts a lot of corners to make the example app simple.
+
+func main() {
+ // Add routes to the global handler
+ goji.Get("/", Root)
+ // Fully backwards compatible with net/http's Handlers
+ goji.Get("/greets", http.RedirectHandler("/", 301))
+ // Use your favorite HTTP verbs
+ goji.Post("/greets", NewGreet)
+ // Use Sinatra-style patterns in your URLs
+ goji.Get("/users/:name", GetUser)
+ // Goji also supports regular expressions with named capture groups.
+ goji.Get(regexp.MustCompile(`^/greets/(?P<id>\d+)$`), GetGreet)
+
+ // Middleware can be used to inject behavior into your app. The
+ // middleware for this application are defined in middleware.go, but you
+ // can put them wherever you like.
+ goji.Use(PlainText)
+
+ // If the patterns ends with "/*", the path is treated as a prefix, and
+ // can be used to implement sub-routes.
+ admin := web.New()
+ goji.Handle("/admin/*", admin)
+
+ // The standard SubRouter middleware helps make writing sub-routers
+ // easy. Ordinarily, Goji does not manipulate the request's URL.Path,
+ // meaning you'd have to repeat "/admin/" in each of the following
+ // routes. This middleware allows you to cut down on the repetition by
+ // eliminating the shared, already-matched prefix.
+ admin.Use(middleware.SubRouter)
+ // You can also easily attach extra middleware to sub-routers that are
+ // not present on the parent router. This one, for instance, presents a
+ // password prompt to users of the admin endpoints.
+ admin.Use(SuperSecure)
+
+ admin.Get("/", AdminRoot)
+ admin.Get("/finances", AdminFinances)
+
+ // Goji's routing, like Sinatra's, is exact: no effort is made to
+ // normalize trailing slashes.
+ goji.Get("/admin", http.RedirectHandler("/admin/", 301))
+
+ // Use a custom 404 handler
+ goji.NotFound(NotFound)
+
+ // Sometimes requests take a long time.
+ goji.Get("/waitforit", WaitForIt)
+
+ // Call Serve() at the bottom of your main() function, and it'll take
+ // care of everything else for you, including binding to a socket (with
+ // automatic support for systemd and Einhorn) and supporting graceful
+ // shutdown on SIGINT. Serve() is appropriate for both development and
+ // production.
+ goji.Serve()
+}
+
+// Root route (GET "/"). Print a list of greets.
+func Root(w http.ResponseWriter, r *http.Request) {
+ // In the real world you'd probably use a template or something.
+ io.WriteString(w, "Gritter\n======\n\n")
+ for i := len(Greets) - 1; i >= 0; i-- {
+ Greets[i].Write(w)
+ }
+}
+
+// NewGreet creates a new greet (POST "/greets"). Creates a greet and redirects
+// you to the created greet.
+//
+// To post a new greet, try this at a shell:
+// $ now=$(date +'%Y-%m-%dT%H:%M:%SZ')
+// $ curl -i -d "user=carl&message=Hello+World&time=$now" localhost:8000/greets
+func NewGreet(w http.ResponseWriter, r *http.Request) {
+ var greet Greet
+
+ // Parse the POST body into the Greet struct. The format is the same as
+ // is emitted by (e.g.) jQuery.param.
+ r.ParseForm()
+ err := param.Parse(r.Form, &greet)
+
+ if err != nil || len(greet.Message) > 140 {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ return
+ }
+
+ // We make no effort to prevent races against other insertions.
+ Greets = append(Greets, greet)
+ url := fmt.Sprintf("/greets/%d", len(Greets)-1)
+ http.Redirect(w, r, url, http.StatusCreated)
+}
+
+// GetUser finds a given user and her greets (GET "/user/:name")
+func GetUser(c web.C, w http.ResponseWriter, r *http.Request) {
+ io.WriteString(w, "Gritter\n======\n\n")
+ handle := c.URLParams["name"]
+ user, ok := Users[handle]
+ if !ok {
+ http.Error(w, http.StatusText(404), 404)
+ return
+ }
+
+ user.Write(w, handle)
+
+ io.WriteString(w, "\nGreets:\n")
+ for i := len(Greets) - 1; i >= 0; i-- {
+ if Greets[i].User == handle {
+ Greets[i].Write(w)
+ }
+ }
+}
+
+// GetGreet finds a particular greet by ID (GET "/greets/\d+"). Does no bounds
+// checking, so will probably panic.
+func GetGreet(c web.C, w http.ResponseWriter, r *http.Request) {
+ id, err := strconv.Atoi(c.URLParams["id"])
+ if err != nil {
+ http.Error(w, http.StatusText(404), 404)
+ return
+ }
+ // This will panic if id is too big. Try it out!
+ greet := Greets[id]
+
+ io.WriteString(w, "Gritter\n======\n\n")
+ greet.Write(w)
+}
+
+// WaitForIt is a particularly slow handler (GET "/waitforit"). Try loading this
+// endpoint and initiating a graceful shutdown (Ctrl-C) or Einhorn reload. The
+// old server will stop accepting new connections and will attempt to kill
+// outstanding idle (keep-alive) connections, but will patiently stick around
+// for this endpoint to finish. How kind of it!
+func WaitForIt(w http.ResponseWriter, r *http.Request) {
+ io.WriteString(w, "This is going to be legend... (wait for it)\n")
+ if fl, ok := w.(http.Flusher); ok {
+ fl.Flush()
+ }
+ time.Sleep(15 * time.Second)
+ io.WriteString(w, "...dary! Legendary!\n")
+}
+
+// AdminRoot is root (GET "/admin/root"). Much secret. Very administrate. Wow.
+func AdminRoot(w http.ResponseWriter, r *http.Request) {
+ io.WriteString(w, "Gritter\n======\n\nSuper secret admin page!\n")
+}
+
+// AdminFinances would answer the question 'How are we doing?'
+// (GET "/admin/finances")
+func AdminFinances(w http.ResponseWriter, r *http.Request) {
+ io.WriteString(w, "Gritter\n======\n\nWe're broke! :(\n")
+}
+
+// NotFound is a 404 handler.
+func NotFound(w http.ResponseWriter, r *http.Request) {
+ http.Error(w, "Umm... have you tried turning it off and on again?", 404)
+}
diff --git a/vendor/github.com/zenazn/goji/example/middleware.go b/vendor/github.com/zenazn/goji/example/middleware.go
new file mode 100644
index 0000000..9652ebb
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/example/middleware.go
@@ -0,0 +1,47 @@
+package main
+
+import (
+ "encoding/base64"
+ "net/http"
+ "strings"
+
+ "github.com/zenazn/goji/web"
+)
+
+// PlainText sets the content-type of responses to text/plain.
+func PlainText(h http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "text/plain")
+ h.ServeHTTP(w, r)
+ }
+ return http.HandlerFunc(fn)
+}
+
+// Nobody will ever guess this!
+const Password = "admin:admin"
+
+// SuperSecure is HTTP Basic Auth middleware for super-secret admin page. Shhhh!
+func SuperSecure(c *web.C, h http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ auth := r.Header.Get("Authorization")
+ if !strings.HasPrefix(auth, "Basic ") {
+ pleaseAuth(w)
+ return
+ }
+
+ password, err := base64.StdEncoding.DecodeString(auth[6:])
+ if err != nil || string(password) != Password {
+ pleaseAuth(w)
+ return
+ }
+
+ h.ServeHTTP(w, r)
+ }
+ return http.HandlerFunc(fn)
+}
+
+func pleaseAuth(w http.ResponseWriter) {
+ w.Header().Set("WWW-Authenticate", `Basic realm="Gritter"`)
+ w.WriteHeader(http.StatusUnauthorized)
+ w.Write([]byte("Go away!\n"))
+}
diff --git a/vendor/github.com/zenazn/goji/example/models.go b/vendor/github.com/zenazn/goji/example/models.go
new file mode 100644
index 0000000..4c34c08
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/example/models.go
@@ -0,0 +1,49 @@
+package main
+
+import (
+ "fmt"
+ "io"
+ "time"
+)
+
+// A Greet is a 140-character micro-blogpost that has no resemblance whatsoever
+// to the noise a bird makes.
+type Greet struct {
+ User string `param:"user"`
+ Message string `param:"message"`
+ Time time.Time `param:"time"`
+}
+
+// Store all our greets in a big list in memory, because, let's be honest, who's
+// actually going to use a service that only allows you to post 140-character
+// messages?
+var Greets = []Greet{
+ {"carl", "Welcome to Gritter!", time.Now()},
+ {"alice", "Wanna know a secret?", time.Now()},
+ {"bob", "Okay!", time.Now()},
+ {"eve", "I'm listening...", time.Now()},
+}
+
+// Write out a representation of the greet
+func (g Greet) Write(w io.Writer) {
+ fmt.Fprintf(w, "%s\n@%s at %s\n---\n", g.Message, g.User,
+ g.Time.Format(time.UnixDate))
+}
+
+// A User is a person. It may even be someone you know. Or a rabbit. Hard to say
+// from here.
+type User struct {
+ Name, Bio string
+}
+
+// All the users we know about! There aren't very many...
+var Users = map[string]User{
+ "alice": {"Alice in Wonderland", "Eating mushrooms"},
+ "bob": {"Bob the Builder", "Making children dumber"},
+ "carl": {"Carl Jackson", "Duct tape aficionado"},
+}
+
+// Write out the user
+func (u User) Write(w io.Writer, handle string) {
+ fmt.Fprintf(w, "%s (@%s)\n%s\n", u.Name, handle, u.Bio)
+}
diff --git a/vendor/github.com/zenazn/goji/goji.go b/vendor/github.com/zenazn/goji/goji.go
new file mode 100644
index 0000000..ab278cd
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/goji.go
@@ -0,0 +1,36 @@
+/*
+Package goji provides an out-of-box web server with reasonable defaults.
+
+Example:
+ package main
+
+ import (
+ "fmt"
+ "net/http"
+
+ "github.com/zenazn/goji"
+ "github.com/zenazn/goji/web"
+ )
+
+ func hello(c web.C, w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, "Hello, %s!", c.URLParams["name"])
+ }
+
+ func main() {
+ goji.Get("/hello/:name", hello)
+ goji.Serve()
+ }
+
+This package exists purely as a convenience to programmers who want to get
+started as quickly as possible. It draws almost all of its code from goji's
+subpackages, the most interesting of which is goji/web, and where most of the
+documentation for the web framework lives.
+
+A side effect of this package's ease-of-use is the fact that it is opinionated.
+If you don't like (or have outgrown) its opinions, it should be straightforward
+to use the APIs of goji's subpackages to reimplement things to your liking. Both
+methods of using this library are equally well supported.
+
+Goji requires Go 1.2 or newer.
+*/
+package goji
diff --git a/vendor/github.com/zenazn/goji/graceful/clone.go b/vendor/github.com/zenazn/goji/graceful/clone.go
new file mode 100644
index 0000000..a9027e5
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/graceful/clone.go
@@ -0,0 +1,11 @@
+// +build !go1.6
+
+package graceful
+
+import "crypto/tls"
+
+// see clone16.go
+func cloneTLSConfig(cfg *tls.Config) *tls.Config {
+ c := *cfg
+ return &c
+}
diff --git a/vendor/github.com/zenazn/goji/graceful/clone16.go b/vendor/github.com/zenazn/goji/graceful/clone16.go
new file mode 100644
index 0000000..810b3a2
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/graceful/clone16.go
@@ -0,0 +1,34 @@
+// +build go1.6
+
+package graceful
+
+import "crypto/tls"
+
+// cloneTLSConfig was taken from the Go standard library's net/http package. We
+// need it because tls.Config objects now contain a sync.Once.
+func cloneTLSConfig(cfg *tls.Config) *tls.Config {
+ if cfg == nil {
+ return &tls.Config{}
+ }
+ return &tls.Config{
+ Rand: cfg.Rand,
+ Time: cfg.Time,
+ Certificates: cfg.Certificates,
+ NameToCertificate: cfg.NameToCertificate,
+ GetCertificate: cfg.GetCertificate,
+ RootCAs: cfg.RootCAs,
+ NextProtos: cfg.NextProtos,
+ ServerName: cfg.ServerName,
+ ClientAuth: cfg.ClientAuth,
+ ClientCAs: cfg.ClientCAs,
+ InsecureSkipVerify: cfg.InsecureSkipVerify,
+ CipherSuites: cfg.CipherSuites,
+ PreferServerCipherSuites: cfg.PreferServerCipherSuites,
+ SessionTicketsDisabled: cfg.SessionTicketsDisabled,
+ SessionTicketKey: cfg.SessionTicketKey,
+ ClientSessionCache: cfg.ClientSessionCache,
+ MinVersion: cfg.MinVersion,
+ MaxVersion: cfg.MaxVersion,
+ CurvePreferences: cfg.CurvePreferences,
+ }
+}
diff --git a/vendor/github.com/zenazn/goji/graceful/einhorn.go b/vendor/github.com/zenazn/goji/graceful/einhorn.go
new file mode 100644
index 0000000..082d1c4
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/graceful/einhorn.go
@@ -0,0 +1,21 @@
+// +build !windows
+
+package graceful
+
+import (
+ "os"
+ "strconv"
+ "syscall"
+)
+
+func init() {
+ // This is a little unfortunate: goji/bind already knows whether we're
+ // running under einhorn, but we don't want to introduce a dependency
+ // between the two packages. Since the check is short enough, inlining
+ // it here seems "fine."
+ mpid, err := strconv.Atoi(os.Getenv("EINHORN_MASTER_PID"))
+ if err != nil || mpid != os.Getppid() {
+ return
+ }
+ stdSignals = append(stdSignals, syscall.SIGUSR2)
+}
diff --git a/vendor/github.com/zenazn/goji/graceful/graceful.go b/vendor/github.com/zenazn/goji/graceful/graceful.go
new file mode 100644
index 0000000..ff9b186
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/graceful/graceful.go
@@ -0,0 +1,62 @@
+/*
+Package graceful implements graceful shutdown for HTTP servers by closing idle
+connections after receiving a signal. By default, this package listens for
+interrupts (i.e., SIGINT), but when it detects that it is running under Einhorn
+it will additionally listen for SIGUSR2 as well, giving your application
+automatic support for graceful restarts/code upgrades.
+*/
+package graceful
+
+import (
+ "net"
+ "runtime"
+ "sync/atomic"
+
+ "github.com/zenazn/goji/graceful/listener"
+)
+
+// WrapListener wraps an arbitrary net.Listener for use with graceful shutdowns.
+// In the background, it uses the listener sub-package to Wrap the listener in
+// Deadline mode. If another mode of operation is desired, you should call
+// listener.Wrap yourself: this function is smart enough to not double-wrap
+// listeners.
+func WrapListener(l net.Listener) net.Listener {
+ if lt, ok := l.(*listener.T); ok {
+ appendListener(lt)
+ return lt
+ }
+
+ lt := listener.Wrap(l, listener.Deadline)
+ appendListener(lt)
+ return lt
+}
+
+func appendListener(l *listener.T) {
+ mu.Lock()
+ defer mu.Unlock()
+
+ listeners = append(listeners, l)
+}
+
+const errClosing = "use of closed network connection"
+
+// During graceful shutdown, calls to Accept will start returning errors. This
+// is inconvenient, since we know these sorts of errors are peaceful, so we
+// silently swallow them.
+func peacefulError(err error) error {
+ if atomic.LoadInt32(&closing) == 0 {
+ return err
+ }
+ // Unfortunately Go doesn't really give us a better way to select errors
+ // than this, so *shrug*.
+ if oe, ok := err.(*net.OpError); ok {
+ errOp := "accept"
+ if runtime.GOOS == "windows" {
+ errOp = "AcceptEx"
+ }
+ if oe.Op == errOp && oe.Err.Error() == errClosing {
+ return nil
+ }
+ }
+ return err
+}
diff --git a/vendor/github.com/zenazn/goji/graceful/listener/conn.go b/vendor/github.com/zenazn/goji/graceful/listener/conn.go
new file mode 100644
index 0000000..7b34b47
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/graceful/listener/conn.go
@@ -0,0 +1,151 @@
+package listener
+
+import (
+ "errors"
+ "io"
+ "net"
+ "sync"
+ "time"
+)
+
+type conn struct {
+ net.Conn
+
+ shard *shard
+ mode mode
+
+ mu sync.Mutex // Protects the state machine below
+ busy bool // connection is in use (i.e., not idle)
+ closed bool // connection is closed
+ disowned bool // if true, this connection is no longer under our management
+}
+
+// This intentionally looks a lot like the one in package net.
+var errClosing = errors.New("use of closed network connection")
+
+func (c *conn) init() error {
+ c.shard.wg.Add(1)
+ if shouldExit := c.shard.track(c); shouldExit {
+ c.Close()
+ return errClosing
+ }
+ return nil
+}
+
+func (c *conn) Read(b []byte) (n int, err error) {
+ defer func() {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if c.disowned {
+ return
+ }
+
+ // This protects against a Close/Read race. We're not really
+ // concerned about the general case (it's fundamentally racy),
+ // but are mostly trying to prevent a race between a new request
+ // getting read off the wire in one thread while the connection
+ // is being gracefully shut down in another.
+ if c.closed && err == nil {
+ n = 0
+ err = errClosing
+ return
+ }
+
+ if c.mode != Manual && !c.busy && !c.closed {
+ c.busy = true
+ c.shard.markInUse(c)
+ }
+ }()
+
+ return c.Conn.Read(b)
+}
+
+func (c *conn) Close() error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if c.disowned {
+ return c.Conn.Close()
+ } else if c.closed {
+ return errClosing
+ }
+
+ c.closed = true
+ c.shard.disown(c)
+ defer c.shard.wg.Done()
+
+ return c.Conn.Close()
+}
+
+func (c *conn) SetReadDeadline(t time.Time) error {
+ c.mu.Lock()
+ if !c.disowned && c.mode == Deadline {
+ defer c.markIdle()
+ }
+ c.mu.Unlock()
+ return c.Conn.SetReadDeadline(t)
+}
+
+func (c *conn) ReadFrom(r io.Reader) (int64, error) {
+ return io.Copy(c.Conn, r)
+}
+
+func (c *conn) markIdle() {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if !c.busy {
+ return
+ }
+ c.busy = false
+
+ if exit := c.shard.markIdle(c); exit && !c.closed && !c.disowned {
+ c.closed = true
+ c.shard.disown(c)
+ defer c.shard.wg.Done()
+ c.Conn.Close()
+ return
+ }
+}
+
+func (c *conn) markInUse() {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if !c.busy && !c.closed && !c.disowned {
+ c.busy = true
+ c.shard.markInUse(c)
+ }
+}
+
+func (c *conn) closeIfIdle() error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if !c.busy && !c.closed && !c.disowned {
+ c.closed = true
+ c.shard.disown(c)
+ defer c.shard.wg.Done()
+ return c.Conn.Close()
+ }
+
+ return nil
+}
+
+var errAlreadyDisowned = errors.New("listener: conn already disowned")
+
+func (c *conn) disown() error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if c.disowned {
+ return errAlreadyDisowned
+ }
+
+ c.shard.disown(c)
+ c.disowned = true
+ c.shard.wg.Done()
+
+ return nil
+}
diff --git a/vendor/github.com/zenazn/goji/graceful/listener/listener.go b/vendor/github.com/zenazn/goji/graceful/listener/listener.go
new file mode 100644
index 0000000..6c9c477
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/graceful/listener/listener.go
@@ -0,0 +1,178 @@
+/*
+Package listener provides a way to incorporate graceful shutdown to any
+net.Listener.
+
+This package provides low-level primitives, not a high-level API. If you're
+looking for a package that provides graceful shutdown for HTTP servers, I
+recommend this package's parent package, github.com/zenazn/goji/graceful.
+*/
+package listener
+
+import (
+ "errors"
+ "net"
+ "runtime"
+ "sync"
+ "sync/atomic"
+)
+
+type mode int8
+
+const (
+ // Manual mode is completely manual: users must use use MarkIdle and
+ // MarkInUse to indicate when connections are busy servicing requests or
+ // are eligible for termination.
+ Manual mode = iota
+ // Automatic mode is what most users probably want: calling Read on a
+ // connection will mark it as in use, but users must manually call
+ // MarkIdle to indicate when connections may be safely closed.
+ Automatic
+ // Deadline mode is like automatic mode, except that calling
+ // SetReadDeadline on a connection will also mark it as being idle. This
+ // is useful for many servers like net/http, where SetReadDeadline is
+ // used to implement read timeouts on new requests.
+ Deadline
+)
+
+// Wrap a net.Listener, returning a net.Listener which supports idle connection
+// tracking and shutdown. Listeners can be placed in to one of three modes,
+// exported as variables from this package: most users will probably want the
+// "Automatic" mode.
+func Wrap(l net.Listener, m mode) *T {
+ t := &T{
+ l: l,
+ mode: m,
+ // To keep the expected contention rate constant we'd have to
+ // grow this as numcpu**2. In practice, CPU counts don't
+ // generally grow without bound, and contention is probably
+ // going to be small enough that nobody cares anyways.
+ shards: make([]shard, 2*runtime.NumCPU()),
+ }
+ for i := range t.shards {
+ t.shards[i].init(t)
+ }
+ return t
+}
+
+// T is the type of this package's graceful listeners.
+type T struct {
+ mu sync.Mutex
+ l net.Listener
+
+ // TODO(carl): a count of currently outstanding connections.
+ connCount uint64
+ shards []shard
+
+ mode mode
+}
+
+var _ net.Listener = &T{}
+
+// Accept waits for and returns the next connection to the listener. The
+// returned net.Conn's idleness is tracked, and idle connections can be closed
+// from the associated T.
+func (t *T) Accept() (net.Conn, error) {
+ c, err := t.l.Accept()
+ if err != nil {
+ return nil, err
+ }
+
+ connID := atomic.AddUint64(&t.connCount, 1)
+ shard := &t.shards[int(connID)%len(t.shards)]
+ wc := &conn{
+ Conn: c,
+ shard: shard,
+ mode: t.mode,
+ }
+
+ if err = wc.init(); err != nil {
+ return nil, err
+ }
+ return wc, nil
+}
+
+// Addr returns the wrapped listener's network address.
+func (t *T) Addr() net.Addr {
+ return t.l.Addr()
+}
+
+// Close closes the wrapped listener.
+func (t *T) Close() error {
+ return t.l.Close()
+}
+
+// CloseIdle closes all connections that are currently marked as being idle. It,
+// however, makes no attempt to wait for in-use connections to die, or to close
+// connections which become idle in the future. Call this function if you're
+// interested in shedding useless connections, but otherwise wish to continue
+// serving requests.
+func (t *T) CloseIdle() error {
+ for i := range t.shards {
+ t.shards[i].closeConns(false, false)
+ }
+ // Not sure if returning errors is actually useful here :/
+ return nil
+}
+
+// Drain immediately closes all idle connections, prevents new connections from
+// being accepted, and waits for all outstanding connections to finish.
+//
+// Once a listener has been drained, there is no way to re-enable it. You
+// probably want to Close the listener before draining it, otherwise new
+// connections will be accepted and immediately closed.
+func (t *T) Drain() error {
+ for i := range t.shards {
+ t.shards[i].closeConns(false, true)
+ }
+ for i := range t.shards {
+ t.shards[i].wait()
+ }
+ return nil
+}
+
+// DrainAll closes all connections currently tracked by this listener (both idle
+// and in-use connections), and prevents new connections from being accepted.
+// Disowned connections are not closed.
+func (t *T) DrainAll() error {
+ for i := range t.shards {
+ t.shards[i].closeConns(true, true)
+ }
+ for i := range t.shards {
+ t.shards[i].wait()
+ }
+ return nil
+}
+
+var errNotManaged = errors.New("listener: passed net.Conn is not managed by this package")
+
+// Disown causes a connection to no longer be tracked by the listener. The
+// passed connection must have been returned by a call to Accept from this
+// listener.
+func Disown(c net.Conn) error {
+ if cn, ok := c.(*conn); ok {
+ return cn.disown()
+ }
+ return errNotManaged
+}
+
+// MarkIdle marks the given connection as being idle, and therefore eligible for
+// closing at any time. The passed connection must have been returned by a call
+// to Accept from this listener.
+func MarkIdle(c net.Conn) error {
+ if cn, ok := c.(*conn); ok {
+ cn.markIdle()
+ return nil
+ }
+ return errNotManaged
+}
+
+// MarkInUse marks this connection as being in use, removing it from the set of
+// connections which are eligible for closing. The passed connection must have
+// been returned by a call to Accept from this listener.
+func MarkInUse(c net.Conn) error {
+ if cn, ok := c.(*conn); ok {
+ cn.markInUse()
+ return nil
+ }
+ return errNotManaged
+}
diff --git a/vendor/github.com/zenazn/goji/graceful/listener/shard.go b/vendor/github.com/zenazn/goji/graceful/listener/shard.go
new file mode 100644
index 0000000..a9addad
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/graceful/listener/shard.go
@@ -0,0 +1,98 @@
+package listener
+
+import "sync"
+
+type shard struct {
+ l *T
+
+ mu sync.Mutex
+ idle map[*conn]struct{}
+ all map[*conn]struct{}
+ wg sync.WaitGroup
+ drain bool
+}
+
+// We pretty aggressively preallocate set entries in the hopes that we never
+// have to allocate memory with the lock held. This is definitely a premature
+// optimization and is probably misguided, but luckily it costs us essentially
+// nothing.
+const prealloc = 2048
+
+func (s *shard) init(l *T) {
+ s.l = l
+ s.idle = make(map[*conn]struct{}, prealloc)
+ s.all = make(map[*conn]struct{}, prealloc)
+}
+
+func (s *shard) track(c *conn) (shouldClose bool) {
+ s.mu.Lock()
+ if s.drain {
+ s.mu.Unlock()
+ return true
+ }
+ s.all[c] = struct{}{}
+ s.idle[c] = struct{}{}
+ s.mu.Unlock()
+ return false
+}
+
+func (s *shard) disown(c *conn) {
+ s.mu.Lock()
+ delete(s.all, c)
+ delete(s.idle, c)
+ s.mu.Unlock()
+}
+
+func (s *shard) markIdle(c *conn) (shouldClose bool) {
+ s.mu.Lock()
+ if s.drain {
+ s.mu.Unlock()
+ return true
+ }
+ s.idle[c] = struct{}{}
+ s.mu.Unlock()
+ return false
+}
+
+func (s *shard) markInUse(c *conn) {
+ s.mu.Lock()
+ delete(s.idle, c)
+ s.mu.Unlock()
+}
+
+func (s *shard) closeConns(all, drain bool) {
+ s.mu.Lock()
+ if drain {
+ s.drain = true
+ }
+ set := make(map[*conn]struct{}, len(s.all))
+ if all {
+ for c := range s.all {
+ set[c] = struct{}{}
+ }
+ } else {
+ for c := range s.idle {
+ set[c] = struct{}{}
+ }
+ }
+ // We have to drop the shard lock here to avoid deadlock: we cannot
+ // acquire the shard lock after the connection lock, and the closeIfIdle
+ // call below will grab a connection lock.
+ s.mu.Unlock()
+
+ for c := range set {
+ // This might return an error (from Close), but I don't think we
+ // can do anything about it, so let's just pretend it didn't
+ // happen. (I also expect that most errors returned in this way
+ // are going to be pretty boring)
+ if all {
+ c.Close()
+ } else {
+ c.closeIfIdle()
+ }
+ }
+}
+
+func (s *shard) wait() {
+ s.wg.Wait()
+}
diff --git a/vendor/github.com/zenazn/goji/graceful/middleware.go b/vendor/github.com/zenazn/goji/graceful/middleware.go
new file mode 100644
index 0000000..94edfe3
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/graceful/middleware.go
@@ -0,0 +1,103 @@
+// +build !go1.3
+
+package graceful
+
+import (
+ "bufio"
+ "io"
+ "net"
+ "net/http"
+ "sync/atomic"
+
+ "github.com/zenazn/goji/graceful/listener"
+)
+
+// Middleware provides functionality similar to net/http.Server's
+// SetKeepAlivesEnabled in Go 1.3, but in Go 1.2.
+func middleware(h http.Handler) http.Handler {
+ if h == nil {
+ return nil
+ }
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ _, 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 {
+ h.ServeHTTP(&fancyWriter{bw}, r)
+ } else {
+ h.ServeHTTP(&bw, r)
+ }
+ if !bw.headerWritten {
+ bw.maybeClose()
+ }
+ })
+}
+
+type basicWriter struct {
+ http.ResponseWriter
+ headerWritten bool
+}
+
+func (b *basicWriter) maybeClose() {
+ b.headerWritten = true
+ if atomic.LoadInt32(&closing) != 0 {
+ b.ResponseWriter.Header().Set("Connection", "close")
+ }
+}
+
+func (b *basicWriter) WriteHeader(code int) {
+ b.maybeClose()
+ b.ResponseWriter.WriteHeader(code)
+}
+
+func (b *basicWriter) Write(buf []byte) (int, error) {
+ if !b.headerWritten {
+ b.maybeClose()
+ }
+ return b.ResponseWriter.Write(buf)
+}
+
+func (b *basicWriter) Unwrap() http.ResponseWriter {
+ return b.ResponseWriter
+}
+
+// Optimize for the common case of a ResponseWriter that supports all three of
+// CloseNotifier, Flusher, and Hijacker.
+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() (c net.Conn, b *bufio.ReadWriter, e error) {
+ hj := f.basicWriter.ResponseWriter.(http.Hijacker)
+ c, b, e = hj.Hijack()
+
+ if e == nil {
+ e = listener.Disown(c)
+ }
+
+ return
+}
+func (f *fancyWriter) ReadFrom(r io.Reader) (int64, error) {
+ rf := f.basicWriter.ResponseWriter.(io.ReaderFrom)
+ if !f.basicWriter.headerWritten {
+ f.basicWriter.maybeClose()
+ }
+ return rf.ReadFrom(r)
+}
+
+var _ http.CloseNotifier = &fancyWriter{}
+var _ http.Flusher = &fancyWriter{}
+var _ http.Hijacker = &fancyWriter{}
+var _ io.ReaderFrom = &fancyWriter{}
diff --git a/vendor/github.com/zenazn/goji/graceful/serve.go b/vendor/github.com/zenazn/goji/graceful/serve.go
new file mode 100644
index 0000000..edb2a53
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/graceful/serve.go
@@ -0,0 +1,33 @@
+// +build !go1.3
+
+package graceful
+
+import (
+ "net"
+ "net/http"
+ "time"
+
+ "github.com/zenazn/goji/graceful/listener"
+)
+
+// About 200 years, also known as "forever"
+const forever time.Duration = 200 * 365 * 24 * time.Hour
+
+// Serve behaves like the method on net/http.Server with the same name.
+func (srv *Server) Serve(l net.Listener) error {
+ // Spawn a shadow http.Server to do the actual servering. We do this
+ // because we need to sketch on some of the parameters you passed in,
+ // and it's nice to keep our sketching to ourselves.
+ shadow := *(*http.Server)(srv)
+
+ if shadow.ReadTimeout == 0 {
+ shadow.ReadTimeout = forever
+ }
+ shadow.Handler = middleware(shadow.Handler)
+
+ wrap := listener.Wrap(l, listener.Deadline)
+ appendListener(wrap)
+
+ err := shadow.Serve(wrap)
+ return peacefulError(err)
+}
diff --git a/vendor/github.com/zenazn/goji/graceful/serve13.go b/vendor/github.com/zenazn/goji/graceful/serve13.go
new file mode 100644
index 0000000..68cac04
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/graceful/serve13.go
@@ -0,0 +1,76 @@
+// +build go1.3
+
+package graceful
+
+import (
+ "log"
+ "net"
+ "net/http"
+
+ "github.com/zenazn/goji/graceful/listener"
+)
+
+// This is a slightly hacky shim to disable keepalives when shutting a server
+// down. We could have added extra functionality in listener or signal.go to
+// deal with this case, but this seems simpler.
+type gracefulServer struct {
+ net.Listener
+ s *http.Server
+}
+
+func (g gracefulServer) Close() error {
+ g.s.SetKeepAlivesEnabled(false)
+ return g.Listener.Close()
+}
+
+// A chaining http.ConnState wrapper
+type connState func(net.Conn, http.ConnState)
+
+func (c connState) Wrap(nc net.Conn, s http.ConnState) {
+ // There are a few other states defined, most notably StateActive.
+ // Unfortunately it doesn't look like it's possible to make use of
+ // StateActive to implement graceful shutdown, since StateActive is set
+ // after a complete request has been read off the wire with an intent to
+ // process it. If we were to race a graceful shutdown against a
+ // connection that was just read off the wire (but not yet in
+ // StateActive), we would accidentally close the connection out from
+ // underneath an active request.
+ //
+ // We already needed to work around this for Go 1.2 by shimming out a
+ // full net.Conn object, so we can just fall back to the old behavior
+ // there.
+ //
+ // I started a golang-nuts thread about this here:
+ // https://groups.google.com/forum/#!topic/golang-nuts/Xi8yjBGWfCQ
+ // I'd be very eager to find a better way to do this, so reach out to me
+ // if you have any ideas.
+ switch s {
+ case http.StateIdle:
+ if err := listener.MarkIdle(nc); err != nil {
+ log.Printf("error marking conn as idle: %v", err)
+ }
+ case http.StateHijacked:
+ if err := listener.Disown(nc); err != nil {
+ log.Printf("error disowning hijacked conn: %v", err)
+ }
+ }
+ if c != nil {
+ c(nc, s)
+ }
+}
+
+// Serve behaves like the method on net/http.Server with the same name.
+func (srv *Server) Serve(l net.Listener) error {
+ // Spawn a shadow http.Server to do the actual servering. We do this
+ // because we need to sketch on some of the parameters you passed in,
+ // and it's nice to keep our sketching to ourselves.
+ shadow := *(*http.Server)(srv)
+ shadow.ConnState = connState(shadow.ConnState).Wrap
+
+ l = gracefulServer{l, &shadow}
+ wrap := listener.Wrap(l, listener.Automatic)
+ appendListener(wrap)
+
+ err := shadow.Serve(wrap)
+ return peacefulError(err)
+}
diff --git a/vendor/github.com/zenazn/goji/graceful/server.go b/vendor/github.com/zenazn/goji/graceful/server.go
new file mode 100644
index 0000000..ae9a5fb
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/graceful/server.go
@@ -0,0 +1,108 @@
+package graceful
+
+import (
+ "crypto/tls"
+ "net"
+ "net/http"
+ "time"
+)
+
+// Most of the code here is lifted straight from net/http
+
+// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
+// connections. It's used by ListenAndServe and ListenAndServeTLS so
+// dead TCP connections (e.g. closing laptop mid-download) eventually
+// go away.
+type tcpKeepAliveListener struct {
+ *net.TCPListener
+}
+
+func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
+ tc, err := ln.AcceptTCP()
+ if err != nil {
+ return
+ }
+ tc.SetKeepAlive(true)
+ tc.SetKeepAlivePeriod(3 * time.Minute)
+ return tc, nil
+}
+
+// A Server is exactly the same as an http.Server, but provides more graceful
+// implementations of its methods.
+type Server http.Server
+
+// ListenAndServe behaves like the method on net/http.Server with the same name.
+func (srv *Server) ListenAndServe() error {
+ addr := srv.Addr
+ if addr == "" {
+ addr = ":http"
+ }
+ ln, err := net.Listen("tcp", addr)
+ if err != nil {
+ return err
+ }
+ return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
+}
+
+// ListenAndServeTLS behaves like the method on net/http.Server with the same
+// name. Unlike the method of the same name on http.Server, this function
+// defaults to enforcing TLS 1.0 or higher in order to address the POODLE
+// vulnerability. Users who wish to enable SSLv3 must do so by supplying a
+// TLSConfig explicitly.
+func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
+ addr := srv.Addr
+ if addr == "" {
+ addr = ":https"
+ }
+ config := &tls.Config{
+ MinVersion: tls.VersionTLS10,
+ }
+ if srv.TLSConfig != nil {
+ config = cloneTLSConfig(srv.TLSConfig)
+ }
+ if config.NextProtos == nil {
+ config.NextProtos = []string{"http/1.1"}
+ }
+
+ var err error
+ config.Certificates = make([]tls.Certificate, 1)
+ config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
+ if err != nil {
+ return err
+ }
+
+ ln, err := net.Listen("tcp", addr)
+ if err != nil {
+ return err
+ }
+
+ tlsListener := tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, config)
+ return srv.Serve(tlsListener)
+}
+
+// ListenAndServe behaves exactly like the net/http function of the same name.
+func ListenAndServe(addr string, handler http.Handler) error {
+ server := &Server{Addr: addr, Handler: handler}
+ return server.ListenAndServe()
+}
+
+// ListenAndServeTLS behaves almost exactly like the net/http function of the
+// same name. Unlike net/http, however, this function defaults to enforcing TLS
+// 1.0 or higher in order to address the POODLE vulnerability. Users who wish to
+// enable SSLv3 must do so by explicitly instantiating a server with an
+// appropriately configured TLSConfig property.
+func ListenAndServeTLS(addr, certfile, keyfile string, handler http.Handler) error {
+ server := &Server{Addr: addr, Handler: handler}
+ return server.ListenAndServeTLS(certfile, keyfile)
+}
+
+// Serve mostly behaves like the net/http function of the same name, except that
+// if the passed listener is a net.TCPListener, TCP keep-alives are enabled on
+// accepted connections.
+func Serve(l net.Listener, handler http.Handler) error {
+ if tl, ok := l.(*net.TCPListener); ok {
+ l = tcpKeepAliveListener{tl}
+ }
+ server := &Server{Handler: handler}
+ return server.Serve(l)
+}
diff --git a/vendor/github.com/zenazn/goji/graceful/signal.go b/vendor/github.com/zenazn/goji/graceful/signal.go
new file mode 100644
index 0000000..60612b8
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/graceful/signal.go
@@ -0,0 +1,197 @@
+package graceful
+
+import (
+ "os"
+ "os/signal"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/zenazn/goji/graceful/listener"
+)
+
+var mu sync.Mutex // protects everything that follows
+var listeners = make([]*listener.T, 0)
+var prehooks = make([]func(), 0)
+var posthooks = make([]func(), 0)
+var closing int32
+var doubleKick, timeout time.Duration
+
+var wait = make(chan struct{})
+var stdSignals = []os.Signal{os.Interrupt}
+var sigchan = make(chan os.Signal, 1)
+
+// HandleSignals installs signal handlers for a set of standard signals. By
+// default, this set only includes keyboard interrupts, however when the package
+// detects that it is running under Einhorn, a SIGUSR2 handler is installed as
+// well.
+func HandleSignals() {
+ AddSignal(stdSignals...)
+}
+
+// AddSignal adds the given signal to the set of signals that trigger a graceful
+// shutdown.
+func AddSignal(sig ...os.Signal) {
+ signal.Notify(sigchan, sig...)
+}
+
+// ResetSignals resets the list of signals that trigger a graceful shutdown.
+func ResetSignals() {
+ signal.Stop(sigchan)
+}
+
+// PreHook registers a function to be called before any of this package's normal
+// shutdown actions. All listeners will be called in the order they were added,
+// from a single goroutine.
+func PreHook(f func()) {
+ mu.Lock()
+ defer mu.Unlock()
+
+ prehooks = append(prehooks, f)
+}
+
+// PostHook registers a function to be called after all of this package's normal
+// shutdown actions. All listeners will be called in the order they were added,
+// from a single goroutine, and are guaranteed to be called after all listening
+// connections have been closed, but before Wait() returns.
+//
+// If you've Hijacked any connections that must be gracefully shut down in some
+// other way (since this library disowns all hijacked connections), it's
+// reasonable to use a PostHook to signal and wait for them.
+func PostHook(f func()) {
+ mu.Lock()
+ defer mu.Unlock()
+
+ posthooks = append(posthooks, f)
+}
+
+// Shutdown manually triggers a shutdown from your application. Like Wait,
+// blocks until all connections have gracefully shut down.
+func Shutdown() {
+ shutdown(false)
+}
+
+// ShutdownNow triggers an immediate shutdown from your application. All
+// connections (not just those that are idle) are immediately closed, even if
+// they are in the middle of serving a request.
+func ShutdownNow() {
+ shutdown(true)
+}
+
+// DoubleKickWindow sets the length of the window during which two back-to-back
+// signals are treated as an especially urgent or forceful request to exit
+// (i.e., ShutdownNow instead of Shutdown). Signals delivered more than this
+// duration apart are treated as separate requests to exit gracefully as usual.
+//
+// Setting DoubleKickWindow to 0 disables the feature.
+func DoubleKickWindow(d time.Duration) {
+ if d < 0 {
+ return
+ }
+ mu.Lock()
+ defer mu.Unlock()
+
+ doubleKick = d
+}
+
+// Timeout sets the maximum amount of time package graceful will wait for
+// connections to gracefully shut down after receiving a signal. After this
+// timeout, connections will be forcefully shut down (similar to calling
+// ShutdownNow).
+//
+// Setting Timeout to 0 disables the feature.
+func Timeout(d time.Duration) {
+ if d < 0 {
+ return
+ }
+ mu.Lock()
+ defer mu.Unlock()
+
+ timeout = d
+}
+
+// Wait for all connections to gracefully shut down. This is commonly called at
+// the bottom of the main() function to prevent the program from exiting
+// prematurely.
+func Wait() {
+ <-wait
+}
+
+func init() {
+ go sigLoop()
+}
+func sigLoop() {
+ var last time.Time
+ for {
+ <-sigchan
+ now := time.Now()
+ mu.Lock()
+ force := doubleKick != 0 && now.Sub(last) < doubleKick
+ if t := timeout; t != 0 && !force {
+ go func() {
+ time.Sleep(t)
+ shutdown(true)
+ }()
+ }
+ mu.Unlock()
+ go shutdown(force)
+ last = now
+ }
+}
+
+var preOnce, closeOnce, forceOnce, postOnce, notifyOnce sync.Once
+
+func shutdown(force bool) {
+ preOnce.Do(func() {
+ mu.Lock()
+ defer mu.Unlock()
+ for _, f := range prehooks {
+ f()
+ }
+ })
+
+ if force {
+ forceOnce.Do(func() {
+ closeListeners(force)
+ })
+ } else {
+ closeOnce.Do(func() {
+ closeListeners(force)
+ })
+ }
+
+ postOnce.Do(func() {
+ mu.Lock()
+ defer mu.Unlock()
+ for _, f := range posthooks {
+ f()
+ }
+ })
+
+ notifyOnce.Do(func() {
+ close(wait)
+ })
+}
+
+func closeListeners(force bool) {
+ atomic.StoreInt32(&closing, 1)
+
+ var wg sync.WaitGroup
+ defer wg.Wait()
+
+ mu.Lock()
+ defer mu.Unlock()
+ wg.Add(len(listeners))
+
+ for _, l := range listeners {
+ go func(l *listener.T) {
+ defer wg.Done()
+ l.Close()
+ if force {
+ l.DrainAll()
+ } else {
+ l.Drain()
+ }
+ }(l)
+ }
+}
diff --git a/vendor/github.com/zenazn/goji/serve.go b/vendor/github.com/zenazn/goji/serve.go
new file mode 100644
index 0000000..da73a9b
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/serve.go
@@ -0,0 +1,64 @@
+// +build !appengine
+
+package goji
+
+import (
+ "crypto/tls"
+ "flag"
+ "log"
+ "net"
+ "net/http"
+ "time"
+
+ "github.com/zenazn/goji/bind"
+ "github.com/zenazn/goji/graceful"
+)
+
+func init() {
+ bind.WithFlag()
+ if fl := log.Flags(); fl&log.Ltime != 0 {
+ log.SetFlags(fl | log.Lmicroseconds)
+ }
+ graceful.DoubleKickWindow(2 * time.Second)
+}
+
+// Serve starts Goji using reasonable defaults.
+func Serve() {
+ if !flag.Parsed() {
+ flag.Parse()
+ }
+
+ ServeListener(bind.Default())
+}
+
+// Like Serve, but enables TLS using the given config.
+func ServeTLS(config *tls.Config) {
+ if !flag.Parsed() {
+ flag.Parse()
+ }
+
+ ServeListener(tls.NewListener(bind.Default(), config))
+}
+
+// Like Serve, but runs Goji on top of an arbitrary net.Listener.
+func ServeListener(listener net.Listener) {
+ DefaultMux.Compile()
+ // Install our handler at the root of the standard net/http default mux.
+ // This allows packages like expvar to continue working as expected.
+ http.Handle("/", DefaultMux)
+
+ log.Println("Starting Goji on", listener.Addr())
+
+ graceful.HandleSignals()
+ bind.Ready()
+ graceful.PreHook(func() { log.Printf("Goji received signal, gracefully stopping") })
+ graceful.PostHook(func() { log.Printf("Goji stopped") })
+
+ err := graceful.Serve(listener, http.DefaultServeMux)
+
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ graceful.Wait()
+}
diff --git a/vendor/github.com/zenazn/goji/serve_appengine.go b/vendor/github.com/zenazn/goji/serve_appengine.go
new file mode 100644
index 0000000..88dc7a8
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/serve_appengine.go
@@ -0,0 +1,23 @@
+// +build appengine
+
+package goji
+
+import (
+ "log"
+ "net/http"
+)
+
+func init() {
+ if fl := log.Flags(); fl&log.Ltime != 0 {
+ log.SetFlags(fl | log.Lmicroseconds)
+ }
+}
+
+// Serve starts Goji using reasonable defaults.
+func Serve() {
+ DefaultMux.Compile()
+ // Install our handler at the root of the standard net/http default mux.
+ // This is required for App Engine, and also allows packages like expvar
+ // to continue working as expected.
+ http.Handle("/", DefaultMux)
+}
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{}