aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com
diff options
context:
space:
mode:
authorChristine Dodrill <me@christine.website>2017-01-10 12:38:33 -0800
committerChristine Dodrill <me@christine.website>2017-01-10 12:38:33 -0800
commit6e292d4d1d65d83cc089e74063cb70ea63bbd795 (patch)
tree2409c6b3f26a4e70499cbbc19f327e01b4a85ca1 /vendor/github.com
parentee89843f5bf60a1e8a3a6bf604ac3f67d25ff72a (diff)
downloadxesite-6e292d4d1d65d83cc089e74063cb70ea63bbd795.tar.xz
xesite-6e292d4d1d65d83cc089e74063cb70ea63bbd795.zip
move vendor to repo root
Diffstat (limited to 'vendor/github.com')
-rw-r--r--vendor/github.com/Xe/asarfs/asarfs.go117
-rw-r--r--vendor/github.com/Xe/asarfs/bench_test.go156
-rw-r--r--vendor/github.com/Xe/asarfs/runtest.go24
-rw-r--r--vendor/github.com/gernest/front/front.go144
-rw-r--r--vendor/github.com/urfave/negroni/doc.go25
-rw-r--r--vendor/github.com/urfave/negroni/logger.go35
-rw-r--r--vendor/github.com/urfave/negroni/negroni.go133
-rw-r--r--vendor/github.com/urfave/negroni/recovery.go65
-rw-r--r--vendor/github.com/urfave/negroni/response_writer.go99
-rw-r--r--vendor/github.com/urfave/negroni/static.go88
10 files changed, 886 insertions, 0 deletions
diff --git a/vendor/github.com/Xe/asarfs/asarfs.go b/vendor/github.com/Xe/asarfs/asarfs.go
new file mode 100644
index 0000000..7d18949
--- /dev/null
+++ b/vendor/github.com/Xe/asarfs/asarfs.go
@@ -0,0 +1,117 @@
+package asarfs
+
+import (
+ "io"
+ "mime"
+ "net/http"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "layeh.com/asar"
+)
+
+// ASARfs serves the contents of an asar archive as an HTTP handler.
+type ASARfs struct {
+ fin *os.File
+ ar *asar.Entry
+ notFound http.Handler
+}
+
+// Close closes the underlying file used for the asar archive.
+func (a *ASARfs) Close() error {
+ return a.fin.Close()
+}
+
+// Open satisfies the http.FileSystem interface for ASARfs.
+func (a *ASARfs) Open(name string) (http.File, error) {
+ if name == "/" {
+ name = "/index.html"
+ }
+
+ e := a.ar.Find(strings.Split(name, "/")[1:]...)
+ if e == nil {
+ return nil, os.ErrNotExist
+ }
+
+ f := &file{
+ Entry: e,
+ r: e.Open(),
+ }
+
+ return f, nil
+}
+
+// ServeHTTP satisfies the http.Handler interface for ASARfs.
+func (a *ASARfs) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ if r.RequestURI == "/" {
+ r.RequestURI = "/index.html"
+ }
+
+ f := a.ar.Find(strings.Split(r.RequestURI, "/")[1:]...)
+ if f == nil {
+ a.notFound.ServeHTTP(w, r)
+ return
+ }
+
+ ext := filepath.Ext(f.Name)
+ mimeType := mime.TypeByExtension(ext)
+
+ w.Header().Add("Content-Type", mimeType)
+ f.WriteTo(w)
+}
+
+// New creates a new ASARfs pointer based on the filepath to the archive and
+// a HTTP handler to hit when a file is not found.
+func New(archivePath string, notFound http.Handler) (*ASARfs, error) {
+ fin, err := os.Open(archivePath)
+ if err != nil {
+ return nil, err
+ }
+
+ root, err := asar.Decode(fin)
+ if err != nil {
+ return nil, err
+ }
+
+ a := &ASARfs{
+ fin: fin,
+ ar: root,
+ notFound: notFound,
+ }
+
+ return a, nil
+}
+
+// file is an internal shim that mimics http.File for an asar entry.
+type file struct {
+ *asar.Entry
+ r io.ReadSeeker
+}
+
+func (f *file) Close() error {
+ f.r = nil
+ return nil
+}
+
+func (f *file) Read(buf []byte) (n int, err error) {
+ return f.r.Read(buf)
+}
+
+func (f *file) Seek(offset int64, whence int) (int64, error) {
+ return f.r.Seek(offset, whence)
+}
+
+func (f *file) Readdir(count int) ([]os.FileInfo, error) {
+ result := []os.FileInfo{}
+
+ for _, e := range f.Entry.Children {
+ result = append(result, e.FileInfo())
+ }
+
+ return result, nil
+}
+
+func (f *file) Stat() (os.FileInfo, error) {
+ return f.Entry.FileInfo(), nil
+}
diff --git a/vendor/github.com/Xe/asarfs/bench_test.go b/vendor/github.com/Xe/asarfs/bench_test.go
new file mode 100644
index 0000000..fd332d5
--- /dev/null
+++ b/vendor/github.com/Xe/asarfs/bench_test.go
@@ -0,0 +1,156 @@
+// +build go1.8
+
+package asarfs
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "math/rand"
+ "net"
+ "net/http"
+ "os"
+ "testing"
+)
+
+func BenchmarkHTTPFileSystem(b *testing.B) {
+ fs := http.FileServer(http.Dir("."))
+
+ l, s, err := setupHandler(fs)
+ if err != nil {
+ b.Fatal(err)
+ }
+ defer l.Close()
+ defer s.Close()
+
+ url := fmt.Sprintf("http://%s", l.Addr())
+
+ for n := 0; n < b.N; n++ {
+ testHandler(url)
+ }
+}
+
+func BenchmarkASARfs(b *testing.B) {
+ fs, err := New("./static.asar", http.HandlerFunc(do404))
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ l, s, err := setupHandler(fs)
+ if err != nil {
+ b.Fatal(err)
+ }
+ defer l.Close()
+ defer s.Close()
+
+ url := fmt.Sprintf("http://%s", l.Addr())
+
+ for n := 0; n < b.N; n++ {
+ testHandler(url)
+ }
+}
+
+func BenchmarkPreloadedASARfs(b *testing.B) {
+ for n := 0; n < b.N; n++ {
+ testHandler(asarfsurl)
+ }
+}
+
+func BenchmarkASARfsHTTPFilesystem(b *testing.B) {
+ fs, err := New("./static.asar", http.HandlerFunc(do404))
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ l, s, err := setupHandler(http.FileServer(fs))
+ if err != nil {
+ b.Fatal(err)
+ }
+ defer l.Close()
+ defer s.Close()
+
+ url := fmt.Sprintf("http://%s", l.Addr())
+
+ for n := 0; n < b.N; n++ {
+ testHandler(url)
+ }
+}
+
+func BenchmarkPreloadedASARfsHTTPFilesystem(b *testing.B) {
+ for n := 0; n < b.N; n++ {
+ testHandler(asarfshttpfsurl)
+ }
+}
+
+func do404(w http.ResponseWriter, r *http.Request) {
+ http.Error(w, "Not found", http.StatusNotFound)
+}
+
+func setupHandler(h http.Handler) (net.Listener, *http.Server, error) {
+ l, err := net.Listen("tcp", ":0")
+ if err != nil {
+ panic(err)
+ }
+ defer l.Close()
+
+ s := &http.Server{
+ Handler: h,
+ }
+ go s.ListenAndServe()
+
+ return l, s, nil
+}
+
+func testHandler(u string) error {
+ num := rand.Intn(9)
+ num++
+ sub := rand.Intn(99)
+
+ fname := fmt.Sprintf("/static/%d/%d%d.json", num, num, sub)
+
+ resp, err := http.Get(u + fname)
+ if err != nil {
+ return err
+ }
+ defer resp.Body.Close()
+
+ _, err = io.Copy(ioutil.Discard, resp.Body)
+ if err != nil {
+ panic(err)
+ }
+
+ return nil
+}
+
+var (
+ asarfsurl string
+ asarfshttpfsurl string
+)
+
+func TestMain(m *testing.M) {
+ go func() {
+ fs, err := New("./static.asar", http.HandlerFunc(do404))
+ if err != nil {
+ }
+
+ l, _, err := setupHandler(fs)
+ if err != nil {
+ }
+
+ asarfsurl = fmt.Sprintf("http://%s", l.Addr().String())
+ }()
+
+ go func() {
+ fs, err := New("./static.asar", http.HandlerFunc(do404))
+ if err != nil {
+ }
+
+ l, _, err := setupHandler(http.FileServer(fs))
+ if err != nil {
+ }
+
+ asarfshttpfsurl = fmt.Sprintf("http://%s", l.Addr().String())
+ }()
+
+ os.Exit(m.Run())
+}
diff --git a/vendor/github.com/Xe/asarfs/runtest.go b/vendor/github.com/Xe/asarfs/runtest.go
new file mode 100644
index 0000000..4b839de
--- /dev/null
+++ b/vendor/github.com/Xe/asarfs/runtest.go
@@ -0,0 +1,24 @@
+// +build ignore
+
+package main
+
+import (
+ "log"
+ "net/http"
+ "os"
+
+ "github.com/Xe/asarfs"
+)
+
+func do404(w http.ResponseWriter, r *http.Request) {
+ http.Error(w, "Not found", http.StatusNotFound)
+}
+
+func main() {
+ fs, err := asarfs.New("./static.asar", http.HandlerFunc(do404))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ http.ListenAndServe(":"+os.Getenv("PORT"), fs)
+}
diff --git a/vendor/github.com/gernest/front/front.go b/vendor/github.com/gernest/front/front.go
new file mode 100644
index 0000000..f4c6f25
--- /dev/null
+++ b/vendor/github.com/gernest/front/front.go
@@ -0,0 +1,144 @@
+// Package front is a frontmatter extraction library.
+package front
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/json"
+ "errors"
+ "io"
+ "strings"
+
+ "gopkg.in/yaml.v2"
+)
+
+var (
+ //ErrIsEmpty is an error indicating no front matter was found
+ ErrIsEmpty = errors.New("front: an empty file")
+
+ //ErrUnknownDelim is returned when the delimiters are not known by the
+ //FrontMatter implementation.
+ ErrUnknownDelim = errors.New("front: unknown delim")
+)
+
+type (
+ //HandlerFunc is an interface for a function that process front matter text.
+ HandlerFunc func(string) (map[string]interface{}, error)
+)
+
+//Matter is all what matters here.
+type Matter struct {
+ handlers map[string]HandlerFunc
+}
+
+//NewMatter creates a new Matter instance
+func NewMatter() *Matter {
+ return &Matter{handlers: make(map[string]HandlerFunc)}
+}
+
+//Handle registers a handler for the given frontmatter delimiter
+func (m *Matter) Handle(delim string, fn HandlerFunc) {
+ m.handlers[delim] = fn
+}
+
+// Parse parses the input and extract the frontmatter
+func (m *Matter) Parse(input io.Reader) (front map[string]interface{}, body string, err error) {
+ return m.parse(input)
+}
+func (m *Matter) parse(input io.Reader) (front map[string]interface{}, body string, err error) {
+ var getFront = func(f string) string {
+ return strings.TrimSpace(f[3:])
+ }
+ f, body, err := m.splitFront(input)
+ if err != nil {
+ return nil, "", err
+ }
+ h := m.handlers[f[:3]]
+ front, err = h(getFront(f))
+ if err != nil {
+ return nil, "", err
+ }
+ return front, body, nil
+
+}
+func sniffDelim(input []byte) (string, error) {
+ if len(input) < 4 {
+ return "", ErrIsEmpty
+ }
+ return string(input[:3]), nil
+}
+
+func (m *Matter) splitFront(input io.Reader) (front, body string, err error) {
+ bufsize := 1024 * 1024
+ buf := make([]byte, bufsize)
+
+ s := bufio.NewScanner(input)
+ // Necessary so we can handle larger than default 4096b buffer
+ s.Buffer(buf, bufsize)
+
+ rst := make([]string, 2)
+ s.Split(m.split)
+ n := 0
+ for s.Scan() {
+ if n == 0 {
+ rst[0] = s.Text()
+ } else if n == 1 {
+ rst[1] = s.Text()
+ }
+ n++
+ }
+ if err = s.Err(); err != nil {
+ return
+ }
+ return rst[0], rst[1], nil
+}
+
+//split implements bufio.SplitFunc for spliting fron matter from the body text.
+func (m *Matter) split(data []byte, atEOF bool) (advance int, token []byte, err error) {
+ if atEOF && len(data) == 0 {
+ return 0, nil, nil
+ }
+ delim, err := sniffDelim(data)
+ if err != nil {
+ return 0, nil, err
+ }
+ if _, ok := m.handlers[delim]; !ok {
+ return 0, nil, ErrUnknownDelim
+ }
+ if x := bytes.Index(data, []byte(delim)); x >= 0 {
+ // check the next delim index
+ if next := bytes.Index(data[x+len(delim):], []byte(delim)); next > 0 {
+ return next + len(delim), dropSpace(data[:next+len(delim)]), nil
+ }
+ return len(data), dropSpace(data[x+len(delim):]), nil
+ }
+ if atEOF {
+ return len(data), data, nil
+ }
+ return 0, nil, nil
+}
+
+func dropSpace(d []byte) []byte {
+ return bytes.TrimSpace(d)
+}
+
+//JSONHandler implements HandlerFunc interface. It extracts front matter data from the given
+// string argument by interpreting it as a json string.
+func JSONHandler(front string) (map[string]interface{}, error) {
+ var rst interface{}
+ err := json.Unmarshal([]byte(front), &rst)
+ if err != nil {
+ return nil, err
+ }
+ return rst.(map[string]interface{}), nil
+}
+
+//YAMLHandler decodes ymal string into a go map[string]interface{}
+func YAMLHandler(front string) (map[string]interface{}, error) {
+ out := make(map[string]interface{})
+ err := yaml.Unmarshal([]byte(front), out)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
diff --git a/vendor/github.com/urfave/negroni/doc.go b/vendor/github.com/urfave/negroni/doc.go
new file mode 100644
index 0000000..add1ed9
--- /dev/null
+++ b/vendor/github.com/urfave/negroni/doc.go
@@ -0,0 +1,25 @@
+// Package negroni is an idiomatic approach to web middleware in Go. It is tiny, non-intrusive, and encourages use of net/http Handlers.
+//
+// If you like the idea of Martini, but you think it contains too much magic, then Negroni is a great fit.
+//
+// For a full guide visit http://github.com/urfave/negroni
+//
+// package main
+//
+// import (
+// "github.com/urfave/negroni"
+// "net/http"
+// "fmt"
+// )
+//
+// func main() {
+// mux := http.NewServeMux()
+// mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
+// fmt.Fprintf(w, "Welcome to the home page!")
+// })
+//
+// n := negroni.Classic()
+// n.UseHandler(mux)
+// n.Run(":3000")
+// }
+package negroni
diff --git a/vendor/github.com/urfave/negroni/logger.go b/vendor/github.com/urfave/negroni/logger.go
new file mode 100644
index 0000000..04cd53b
--- /dev/null
+++ b/vendor/github.com/urfave/negroni/logger.go
@@ -0,0 +1,35 @@
+package negroni
+
+import (
+ "log"
+ "net/http"
+ "os"
+ "time"
+)
+
+// ALogger interface
+type ALogger interface {
+ Println(v ...interface{})
+ Printf(format string, v ...interface{})
+}
+
+// Logger is a middleware handler that logs the request as it goes in and the response as it goes out.
+type Logger struct {
+ // ALogger implements just enough log.Logger interface to be compatible with other implementations
+ ALogger
+}
+
+// NewLogger returns a new Logger instance
+func NewLogger() *Logger {
+ return &Logger{log.New(os.Stdout, "[negroni] ", 0)}
+}
+
+func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
+ start := time.Now()
+ l.Printf("Started %s %s", r.Method, r.URL.Path)
+
+ next(rw, r)
+
+ res := rw.(ResponseWriter)
+ l.Printf("Completed %v %s in %v", res.Status(), http.StatusText(res.Status()), time.Since(start))
+}
diff --git a/vendor/github.com/urfave/negroni/negroni.go b/vendor/github.com/urfave/negroni/negroni.go
new file mode 100644
index 0000000..9c7c187
--- /dev/null
+++ b/vendor/github.com/urfave/negroni/negroni.go
@@ -0,0 +1,133 @@
+package negroni
+
+import (
+ "log"
+ "net/http"
+ "os"
+)
+
+// Handler handler is an interface that objects can implement to be registered to serve as middleware
+// in the Negroni middleware stack.
+// ServeHTTP should yield to the next middleware in the chain by invoking the next http.HandlerFunc
+// passed in.
+//
+// If the Handler writes to the ResponseWriter, the next http.HandlerFunc should not be invoked.
+type Handler interface {
+ ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
+}
+
+// HandlerFunc is an adapter to allow the use of ordinary functions as Negroni handlers.
+// If f is a function with the appropriate signature, HandlerFunc(f) is a Handler object that calls f.
+type HandlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
+
+func (h HandlerFunc) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
+ h(rw, r, next)
+}
+
+type middleware struct {
+ handler Handler
+ next *middleware
+}
+
+func (m middleware) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
+ m.handler.ServeHTTP(rw, r, m.next.ServeHTTP)
+}
+
+// Wrap converts a http.Handler into a negroni.Handler so it can be used as a Negroni
+// middleware. The next http.HandlerFunc is automatically called after the Handler
+// is executed.
+func Wrap(handler http.Handler) Handler {
+ return HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
+ handler.ServeHTTP(rw, r)
+ next(rw, r)
+ })
+}
+
+// Negroni is a stack of Middleware Handlers that can be invoked as an http.Handler.
+// Negroni middleware is evaluated in the order that they are added to the stack using
+// the Use and UseHandler methods.
+type Negroni struct {
+ middleware middleware
+ handlers []Handler
+}
+
+// New returns a new Negroni instance with no middleware preconfigured.
+func New(handlers ...Handler) *Negroni {
+ return &Negroni{
+ handlers: handlers,
+ middleware: build(handlers),
+ }
+}
+
+// Classic returns a new Negroni instance with the default middleware already
+// in the stack.
+//
+// Recovery - Panic Recovery Middleware
+// Logger - Request/Response Logging
+// Static - Static File Serving
+func Classic() *Negroni {
+ return New(NewRecovery(), NewLogger(), NewStatic(http.Dir("public")))
+}
+
+func (n *Negroni) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
+ n.middleware.ServeHTTP(NewResponseWriter(rw), r)
+}
+
+// Use adds a Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
+func (n *Negroni) Use(handler Handler) {
+ if handler == nil {
+ panic("handler cannot be nil")
+ }
+
+ n.handlers = append(n.handlers, handler)
+ n.middleware = build(n.handlers)
+}
+
+// UseFunc adds a Negroni-style handler function onto the middleware stack.
+func (n *Negroni) UseFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)) {
+ n.Use(HandlerFunc(handlerFunc))
+}
+
+// UseHandler adds a http.Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
+func (n *Negroni) UseHandler(handler http.Handler) {
+ n.Use(Wrap(handler))
+}
+
+// UseHandler adds a http.HandlerFunc-style handler function onto the middleware stack.
+func (n *Negroni) UseHandlerFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request)) {
+ n.UseHandler(http.HandlerFunc(handlerFunc))
+}
+
+// Run is a convenience function that runs the negroni stack as an HTTP
+// server. The addr string takes the same format as http.ListenAndServe.
+func (n *Negroni) Run(addr string) {
+ l := log.New(os.Stdout, "[negroni] ", 0)
+ l.Printf("listening on %s", addr)
+ l.Fatal(http.ListenAndServe(addr, n))
+}
+
+// Returns a list of all the handlers in the current Negroni middleware chain.
+func (n *Negroni) Handlers() []Handler {
+ return n.handlers
+}
+
+func build(handlers []Handler) middleware {
+ var next middleware
+
+ if len(handlers) == 0 {
+ return voidMiddleware()
+ } else if len(handlers) > 1 {
+ next = build(handlers[1:])
+ } else {
+ next = voidMiddleware()
+ }
+
+ return middleware{handlers[0], &next}
+}
+
+func voidMiddleware() middleware {
+ return middleware{
+ HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {}),
+ &middleware{},
+ }
+}
diff --git a/vendor/github.com/urfave/negroni/recovery.go b/vendor/github.com/urfave/negroni/recovery.go
new file mode 100644
index 0000000..8396cb1
--- /dev/null
+++ b/vendor/github.com/urfave/negroni/recovery.go
@@ -0,0 +1,65 @@
+package negroni
+
+import (
+ "fmt"
+ "log"
+ "net/http"
+ "os"
+ "runtime"
+ "runtime/debug"
+)
+
+// Recovery is a Negroni middleware that recovers from any panics and writes a 500 if there was one.
+type Recovery struct {
+ Logger ALogger
+ PrintStack bool
+ ErrorHandlerFunc func(interface{})
+ StackAll bool
+ StackSize int
+}
+
+// NewRecovery returns a new instance of Recovery
+func NewRecovery() *Recovery {
+ return &Recovery{
+ Logger: log.New(os.Stdout, "[negroni] ", 0),
+ PrintStack: true,
+ StackAll: false,
+ StackSize: 1024 * 8,
+ }
+}
+
+func (rec *Recovery) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
+ defer func() {
+ if err := recover(); err != nil {
+ if rw.Header().Get("Content-Type") == "" {
+ rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ }
+
+ rw.WriteHeader(http.StatusInternalServerError)
+
+ stack := make([]byte, rec.StackSize)
+ stack = stack[:runtime.Stack(stack, rec.StackAll)]
+
+ f := "PANIC: %s\n%s"
+ rec.Logger.Printf(f, err, stack)
+
+ if rec.PrintStack {
+ fmt.Fprintf(rw, f, err, stack)
+ }
+
+ if rec.ErrorHandlerFunc != nil {
+ func() {
+ defer func() {
+ if err := recover(); err != nil {
+ rec.Logger.Printf("provided ErrorHandlerFunc panic'd: %s, trace:\n%s", err, debug.Stack())
+ rec.Logger.Printf("%s\n", debug.Stack())
+ }
+ }()
+ rec.ErrorHandlerFunc(err)
+ }()
+ }
+ }
+ }()
+
+ next(rw, r)
+}
diff --git a/vendor/github.com/urfave/negroni/response_writer.go b/vendor/github.com/urfave/negroni/response_writer.go
new file mode 100644
index 0000000..f805825
--- /dev/null
+++ b/vendor/github.com/urfave/negroni/response_writer.go
@@ -0,0 +1,99 @@
+package negroni
+
+import (
+ "bufio"
+ "fmt"
+ "net"
+ "net/http"
+)
+
+// ResponseWriter is a wrapper around http.ResponseWriter that provides extra information about
+// the response. It is recommended that middleware handlers use this construct to wrap a responsewriter
+// if the functionality calls for it.
+type ResponseWriter interface {
+ http.ResponseWriter
+ http.Flusher
+ // Status returns the status code of the response or 200 if the response has
+ // not been written (as this is the default response code in net/http)
+ Status() int
+ // Written returns whether or not the ResponseWriter has been written.
+ Written() bool
+ // Size returns the size of the response body.
+ Size() int
+ // Before allows for a function to be called before the ResponseWriter has been written to. This is
+ // useful for setting headers or any other operations that must happen before a response has been written.
+ Before(func(ResponseWriter))
+}
+
+type beforeFunc func(ResponseWriter)
+
+// NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter
+func NewResponseWriter(rw http.ResponseWriter) ResponseWriter {
+ return &responseWriter{
+ ResponseWriter: rw,
+ }
+}
+
+type responseWriter struct {
+ http.ResponseWriter
+ status int
+ size int
+ beforeFuncs []beforeFunc
+}
+
+func (rw *responseWriter) WriteHeader(s int) {
+ rw.status = s
+ rw.callBefore()
+ rw.ResponseWriter.WriteHeader(s)
+}
+
+func (rw *responseWriter) Write(b []byte) (int, error) {
+ if !rw.Written() {
+ // The status will be StatusOK if WriteHeader has not been called yet
+ rw.WriteHeader(http.StatusOK)
+ }
+ size, err := rw.ResponseWriter.Write(b)
+ rw.size += size
+ return size, err
+}
+
+func (rw *responseWriter) Status() int {
+ return rw.status
+}
+
+func (rw *responseWriter) Size() int {
+ return rw.size
+}
+
+func (rw *responseWriter) Written() bool {
+ return rw.status != 0
+}
+
+func (rw *responseWriter) Before(before func(ResponseWriter)) {
+ rw.beforeFuncs = append(rw.beforeFuncs, before)
+}
+
+func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ hijacker, ok := rw.ResponseWriter.(http.Hijacker)
+ if !ok {
+ return nil, nil, fmt.Errorf("the ResponseWriter doesn't support the Hijacker interface")
+ }
+ return hijacker.Hijack()
+}
+
+func (rw *responseWriter) CloseNotify() <-chan bool {
+ return rw.ResponseWriter.(http.CloseNotifier).CloseNotify()
+}
+
+func (rw *responseWriter) callBefore() {
+ for i := len(rw.beforeFuncs) - 1; i >= 0; i-- {
+ rw.beforeFuncs[i](rw)
+ }
+}
+
+func (rw *responseWriter) Flush() {
+ flusher, ok := rw.ResponseWriter.(http.Flusher)
+ if ok {
+ flusher.Flush()
+ }
+}
diff --git a/vendor/github.com/urfave/negroni/static.go b/vendor/github.com/urfave/negroni/static.go
new file mode 100644
index 0000000..34be967
--- /dev/null
+++ b/vendor/github.com/urfave/negroni/static.go
@@ -0,0 +1,88 @@
+package negroni
+
+import (
+ "net/http"
+ "path"
+ "strings"
+)
+
+// Static is a middleware handler that serves static files in the given
+// directory/filesystem. If the file does not exist on the filesystem, it
+// passes along to the next middleware in the chain. If you desire "fileserver"
+// type behavior where it returns a 404 for unfound files, you should consider
+// using http.FileServer from the Go stdlib.
+type Static struct {
+ // Dir is the directory to serve static files from
+ Dir http.FileSystem
+ // Prefix is the optional prefix used to serve the static directory content
+ Prefix string
+ // IndexFile defines which file to serve as index if it exists.
+ IndexFile string
+}
+
+// NewStatic returns a new instance of Static
+func NewStatic(directory http.FileSystem) *Static {
+ return &Static{
+ Dir: directory,
+ Prefix: "",
+ IndexFile: "index.html",
+ }
+}
+
+func (s *Static) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
+ if r.Method != "GET" && r.Method != "HEAD" {
+ next(rw, r)
+ return
+ }
+ file := r.URL.Path
+ // if we have a prefix, filter requests by stripping the prefix
+ if s.Prefix != "" {
+ if !strings.HasPrefix(file, s.Prefix) {
+ next(rw, r)
+ return
+ }
+ file = file[len(s.Prefix):]
+ if file != "" && file[0] != '/' {
+ next(rw, r)
+ return
+ }
+ }
+ f, err := s.Dir.Open(file)
+ if err != nil {
+ // discard the error?
+ next(rw, r)
+ return
+ }
+ defer f.Close()
+
+ fi, err := f.Stat()
+ if err != nil {
+ next(rw, r)
+ return
+ }
+
+ // try to serve index file
+ if fi.IsDir() {
+ // redirect if missing trailing slash
+ if !strings.HasSuffix(r.URL.Path, "/") {
+ http.Redirect(rw, r, r.URL.Path+"/", http.StatusFound)
+ return
+ }
+
+ file = path.Join(file, s.IndexFile)
+ f, err = s.Dir.Open(file)
+ if err != nil {
+ next(rw, r)
+ return
+ }
+ defer f.Close()
+
+ fi, err = f.Stat()
+ if err != nil || fi.IsDir() {
+ next(rw, r)
+ return
+ }
+ }
+
+ http.ServeContent(rw, r, file, fi.ModTime(), f)
+}