aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/codegangsta
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/codegangsta
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/codegangsta')
-rw-r--r--vendor/github.com/codegangsta/inject/LICENSE20
-rw-r--r--vendor/github.com/codegangsta/inject/inject.go187
-rw-r--r--vendor/github.com/codegangsta/negroni/LICENSE21
-rw-r--r--vendor/github.com/codegangsta/negroni/doc.go25
-rw-r--r--vendor/github.com/codegangsta/negroni/logger.go35
-rw-r--r--vendor/github.com/codegangsta/negroni/negroni.go133
-rw-r--r--vendor/github.com/codegangsta/negroni/recovery.go65
-rw-r--r--vendor/github.com/codegangsta/negroni/response_writer.go113
-rw-r--r--vendor/github.com/codegangsta/negroni/static.go88
9 files changed, 687 insertions, 0 deletions
diff --git a/vendor/github.com/codegangsta/inject/LICENSE b/vendor/github.com/codegangsta/inject/LICENSE
new file mode 100644
index 0000000..eb68a0e
--- /dev/null
+++ b/vendor/github.com/codegangsta/inject/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Jeremy Saenz
+
+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/codegangsta/inject/inject.go b/vendor/github.com/codegangsta/inject/inject.go
new file mode 100644
index 0000000..3ff713c
--- /dev/null
+++ b/vendor/github.com/codegangsta/inject/inject.go
@@ -0,0 +1,187 @@
+// Package inject provides utilities for mapping and injecting dependencies in various ways.
+package inject
+
+import (
+ "fmt"
+ "reflect"
+)
+
+// Injector represents an interface for mapping and injecting dependencies into structs
+// and function arguments.
+type Injector interface {
+ Applicator
+ Invoker
+ TypeMapper
+ // SetParent sets the parent of the injector. If the injector cannot find a
+ // dependency in its Type map it will check its parent before returning an
+ // error.
+ SetParent(Injector)
+}
+
+// Applicator represents an interface for mapping dependencies to a struct.
+type Applicator interface {
+ // Maps dependencies in the Type map to each field in the struct
+ // that is tagged with 'inject'. Returns an error if the injection
+ // fails.
+ Apply(interface{}) error
+}
+
+// Invoker represents an interface for calling functions via reflection.
+type Invoker interface {
+ // Invoke attempts to call the interface{} provided as a function,
+ // providing dependencies for function arguments based on Type. Returns
+ // a slice of reflect.Value representing the returned values of the function.
+ // Returns an error if the injection fails.
+ Invoke(interface{}) ([]reflect.Value, error)
+}
+
+// TypeMapper represents an interface for mapping interface{} values based on type.
+type TypeMapper interface {
+ // Maps the interface{} value based on its immediate type from reflect.TypeOf.
+ Map(interface{}) TypeMapper
+ // Maps the interface{} value based on the pointer of an Interface provided.
+ // This is really only useful for mapping a value as an interface, as interfaces
+ // cannot at this time be referenced directly without a pointer.
+ MapTo(interface{}, interface{}) TypeMapper
+ // Provides a possibility to directly insert a mapping based on type and value.
+ // This makes it possible to directly map type arguments not possible to instantiate
+ // with reflect like unidirectional channels.
+ Set(reflect.Type, reflect.Value) TypeMapper
+ // Returns the Value that is mapped to the current type. Returns a zeroed Value if
+ // the Type has not been mapped.
+ Get(reflect.Type) reflect.Value
+}
+
+type injector struct {
+ values map[reflect.Type]reflect.Value
+ parent Injector
+}
+
+// InterfaceOf dereferences a pointer to an Interface type.
+// It panics if value is not an pointer to an interface.
+func InterfaceOf(value interface{}) reflect.Type {
+ t := reflect.TypeOf(value)
+
+ for t.Kind() == reflect.Ptr {
+ t = t.Elem()
+ }
+
+ if t.Kind() != reflect.Interface {
+ panic("Called inject.InterfaceOf with a value that is not a pointer to an interface. (*MyInterface)(nil)")
+ }
+
+ return t
+}
+
+// New returns a new Injector.
+func New() Injector {
+ return &injector{
+ values: make(map[reflect.Type]reflect.Value),
+ }
+}
+
+// Invoke attempts to call the interface{} provided as a function,
+// providing dependencies for function arguments based on Type.
+// Returns a slice of reflect.Value representing the returned values of the function.
+// Returns an error if the injection fails.
+// It panics if f is not a function
+func (inj *injector) Invoke(f interface{}) ([]reflect.Value, error) {
+ t := reflect.TypeOf(f)
+
+ var in = make([]reflect.Value, t.NumIn()) //Panic if t is not kind of Func
+ for i := 0; i < t.NumIn(); i++ {
+ argType := t.In(i)
+ val := inj.Get(argType)
+ if !val.IsValid() {
+ return nil, fmt.Errorf("Value not found for type %v", argType)
+ }
+
+ in[i] = val
+ }
+
+ return reflect.ValueOf(f).Call(in), nil
+}
+
+// Maps dependencies in the Type map to each field in the struct
+// that is tagged with 'inject'.
+// Returns an error if the injection fails.
+func (inj *injector) Apply(val interface{}) error {
+ v := reflect.ValueOf(val)
+
+ for v.Kind() == reflect.Ptr {
+ v = v.Elem()
+ }
+
+ if v.Kind() != reflect.Struct {
+ return nil // Should not panic here ?
+ }
+
+ t := v.Type()
+
+ for i := 0; i < v.NumField(); i++ {
+ f := v.Field(i)
+ structField := t.Field(i)
+ if f.CanSet() && (structField.Tag == "inject" || structField.Tag.Get("inject") != "") {
+ ft := f.Type()
+ v := inj.Get(ft)
+ if !v.IsValid() {
+ return fmt.Errorf("Value not found for type %v", ft)
+ }
+
+ f.Set(v)
+ }
+
+ }
+
+ return nil
+}
+
+// Maps the concrete value of val to its dynamic type using reflect.TypeOf,
+// It returns the TypeMapper registered in.
+func (i *injector) Map(val interface{}) TypeMapper {
+ i.values[reflect.TypeOf(val)] = reflect.ValueOf(val)
+ return i
+}
+
+func (i *injector) MapTo(val interface{}, ifacePtr interface{}) TypeMapper {
+ i.values[InterfaceOf(ifacePtr)] = reflect.ValueOf(val)
+ return i
+}
+
+// Maps the given reflect.Type to the given reflect.Value and returns
+// the Typemapper the mapping has been registered in.
+func (i *injector) Set(typ reflect.Type, val reflect.Value) TypeMapper {
+ i.values[typ] = val
+ return i
+}
+
+func (i *injector) Get(t reflect.Type) reflect.Value {
+ val := i.values[t]
+
+ if val.IsValid() {
+ return val
+ }
+
+ // no concrete types found, try to find implementors
+ // if t is an interface
+ if t.Kind() == reflect.Interface {
+ for k, v := range i.values {
+ if k.Implements(t) {
+ val = v
+ break
+ }
+ }
+ }
+
+ // Still no type found, try to look it up on the parent
+ if !val.IsValid() && i.parent != nil {
+ val = i.parent.Get(t)
+ }
+
+ return val
+
+}
+
+func (i *injector) SetParent(parent Injector) {
+ i.parent = parent
+}
diff --git a/vendor/github.com/codegangsta/negroni/LICENSE b/vendor/github.com/codegangsta/negroni/LICENSE
new file mode 100644
index 0000000..08b5e20
--- /dev/null
+++ b/vendor/github.com/codegangsta/negroni/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Jeremy Saenz
+
+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/codegangsta/negroni/doc.go b/vendor/github.com/codegangsta/negroni/doc.go
new file mode 100644
index 0000000..add1ed9
--- /dev/null
+++ b/vendor/github.com/codegangsta/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/codegangsta/negroni/logger.go b/vendor/github.com/codegangsta/negroni/logger.go
new file mode 100644
index 0000000..04cd53b
--- /dev/null
+++ b/vendor/github.com/codegangsta/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/codegangsta/negroni/negroni.go b/vendor/github.com/codegangsta/negroni/negroni.go
new file mode 100644
index 0000000..9c7c187
--- /dev/null
+++ b/vendor/github.com/codegangsta/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/codegangsta/negroni/recovery.go b/vendor/github.com/codegangsta/negroni/recovery.go
new file mode 100644
index 0000000..8396cb1
--- /dev/null
+++ b/vendor/github.com/codegangsta/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/codegangsta/negroni/response_writer.go b/vendor/github.com/codegangsta/negroni/response_writer.go
new file mode 100644
index 0000000..bfb83a6
--- /dev/null
+++ b/vendor/github.com/codegangsta/negroni/response_writer.go
@@ -0,0 +1,113 @@
+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 {
+ nrw := &responseWriter{
+ ResponseWriter: rw,
+ }
+
+ if _, ok := rw.(http.CloseNotifier); ok {
+ return &responseWriterCloseNotifer{nrw}
+ }
+
+ return nrw
+}
+
+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) 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 {
+ if !rw.Written() {
+ // The status will be StatusOK if WriteHeader has not been called yet
+ rw.WriteHeader(http.StatusOK)
+ }
+ flusher.Flush()
+ }
+}
+
+type responseWriterCloseNotifer struct {
+ *responseWriter
+}
+
+func (rw *responseWriterCloseNotifer) CloseNotify() <-chan bool {
+ return rw.ResponseWriter.(http.CloseNotifier).CloseNotify()
+}
diff --git a/vendor/github.com/codegangsta/negroni/static.go b/vendor/github.com/codegangsta/negroni/static.go
new file mode 100644
index 0000000..34be967
--- /dev/null
+++ b/vendor/github.com/codegangsta/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)
+}