summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/gorilla/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/gorilla/handlers')
-rw-r--r--vendor/github.com/gorilla/handlers/canonical_test.go127
-rw-r--r--vendor/github.com/gorilla/handlers/compress_test.go154
-rw-r--r--vendor/github.com/gorilla/handlers/cors_test.go336
-rw-r--r--vendor/github.com/gorilla/handlers/handlers_test.go354
-rw-r--r--vendor/github.com/gorilla/handlers/proxy_headers_test.go100
-rw-r--r--vendor/github.com/gorilla/handlers/recovery_test.go44
6 files changed, 1115 insertions, 0 deletions
diff --git a/vendor/github.com/gorilla/handlers/canonical_test.go b/vendor/github.com/gorilla/handlers/canonical_test.go
new file mode 100644
index 000000000..615e4b056
--- /dev/null
+++ b/vendor/github.com/gorilla/handlers/canonical_test.go
@@ -0,0 +1,127 @@
+package handlers
+
+import (
+ "bufio"
+ "bytes"
+ "log"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "strings"
+ "testing"
+)
+
+func TestCleanHost(t *testing.T) {
+ tests := []struct {
+ in, want string
+ }{
+ {"www.google.com", "www.google.com"},
+ {"www.google.com foo", "www.google.com"},
+ {"www.google.com/foo", "www.google.com"},
+ {" first character is a space", ""},
+ }
+ for _, tt := range tests {
+ got := cleanHost(tt.in)
+ if tt.want != got {
+ t.Errorf("cleanHost(%q) = %q, want %q", tt.in, got, tt.want)
+ }
+ }
+}
+
+func TestCanonicalHost(t *testing.T) {
+ gorilla := "http://www.gorillatoolkit.org"
+
+ rr := httptest.NewRecorder()
+ r := newRequest("GET", "http://www.example.com/")
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ // Test a re-direct: should return a 302 Found.
+ CanonicalHost(gorilla, http.StatusFound)(testHandler).ServeHTTP(rr, r)
+
+ if rr.Code != http.StatusFound {
+ t.Fatalf("bad status: got %v want %v", rr.Code, http.StatusFound)
+ }
+
+ if rr.Header().Get("Location") != gorilla+r.URL.Path {
+ t.Fatalf("bad re-direct: got %q want %q", rr.Header().Get("Location"), gorilla+r.URL.Path)
+ }
+
+}
+
+func TestKeepsQueryString(t *testing.T) {
+ google := "https://www.google.com"
+
+ rr := httptest.NewRecorder()
+ querystring := url.Values{"q": {"golang"}, "format": {"json"}}.Encode()
+ r := newRequest("GET", "http://www.example.com/search?"+querystring)
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+ CanonicalHost(google, http.StatusFound)(testHandler).ServeHTTP(rr, r)
+
+ want := google + r.URL.Path + "?" + querystring
+ if rr.Header().Get("Location") != want {
+ t.Fatalf("bad re-direct: got %q want %q", rr.Header().Get("Location"), want)
+ }
+}
+
+func TestBadDomain(t *testing.T) {
+ rr := httptest.NewRecorder()
+ r := newRequest("GET", "http://www.example.com/")
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ // Test a bad domain - should return 200 OK.
+ CanonicalHost("%", http.StatusFound)(testHandler).ServeHTTP(rr, r)
+
+ if rr.Code != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", rr.Code, http.StatusOK)
+ }
+}
+
+func TestEmptyHost(t *testing.T) {
+ rr := httptest.NewRecorder()
+ r := newRequest("GET", "http://www.example.com/")
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ // Test a domain that returns an empty url.Host from url.Parse.
+ CanonicalHost("hello.com", http.StatusFound)(testHandler).ServeHTTP(rr, r)
+
+ if rr.Code != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", rr.Code, http.StatusOK)
+ }
+}
+
+func TestHeaderWrites(t *testing.T) {
+ gorilla := "http://www.gorillatoolkit.org"
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(200)
+ })
+
+ // Catch the log output to ensure we don't write multiple headers.
+ var b bytes.Buffer
+ buf := bufio.NewWriter(&b)
+ tl := log.New(buf, "test: ", log.Lshortfile)
+
+ srv := httptest.NewServer(
+ CanonicalHost(gorilla, http.StatusFound)(testHandler))
+ defer srv.Close()
+ srv.Config.ErrorLog = tl
+
+ _, err := http.Get(srv.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = buf.Flush()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // We rely on the error not changing: net/http does not export it.
+ if strings.Contains(b.String(), "multiple response.WriteHeader calls") {
+ t.Fatalf("re-direct did not return early: multiple header writes")
+ }
+}
diff --git a/vendor/github.com/gorilla/handlers/compress_test.go b/vendor/github.com/gorilla/handlers/compress_test.go
new file mode 100644
index 000000000..6f07f440d
--- /dev/null
+++ b/vendor/github.com/gorilla/handlers/compress_test.go
@@ -0,0 +1,154 @@
+// Copyright 2013 The Gorilla Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package handlers
+
+import (
+ "bufio"
+ "io"
+ "net"
+ "net/http"
+ "net/http/httptest"
+ "strconv"
+ "testing"
+)
+
+var contentType = "text/plain; charset=utf-8"
+
+func compressedRequest(w *httptest.ResponseRecorder, compression string) {
+ CompressHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Length", strconv.Itoa(9*1024))
+ w.Header().Set("Content-Type", contentType)
+ for i := 0; i < 1024; i++ {
+ io.WriteString(w, "Gorilla!\n")
+ }
+ })).ServeHTTP(w, &http.Request{
+ Method: "GET",
+ Header: http.Header{
+ "Accept-Encoding": []string{compression},
+ },
+ })
+
+}
+
+func TestCompressHandlerNoCompression(t *testing.T) {
+ w := httptest.NewRecorder()
+ compressedRequest(w, "")
+ if enc := w.HeaderMap.Get("Content-Encoding"); enc != "" {
+ t.Errorf("wrong content encoding, got %q want %q", enc, "")
+ }
+ if ct := w.HeaderMap.Get("Content-Type"); ct != contentType {
+ t.Errorf("wrong content type, got %q want %q", ct, contentType)
+ }
+ if w.Body.Len() != 1024*9 {
+ t.Errorf("wrong len, got %d want %d", w.Body.Len(), 1024*9)
+ }
+ if l := w.HeaderMap.Get("Content-Length"); l != "9216" {
+ t.Errorf("wrong content-length. got %q expected %d", l, 1024*9)
+ }
+}
+
+func TestCompressHandlerGzip(t *testing.T) {
+ w := httptest.NewRecorder()
+ compressedRequest(w, "gzip")
+ if w.HeaderMap.Get("Content-Encoding") != "gzip" {
+ t.Errorf("wrong content encoding, got %q want %q", w.HeaderMap.Get("Content-Encoding"), "gzip")
+ }
+ if w.HeaderMap.Get("Content-Type") != "text/plain; charset=utf-8" {
+ t.Errorf("wrong content type, got %s want %s", w.HeaderMap.Get("Content-Type"), "text/plain; charset=utf-8")
+ }
+ if w.Body.Len() != 72 {
+ t.Errorf("wrong len, got %d want %d", w.Body.Len(), 72)
+ }
+ if l := w.HeaderMap.Get("Content-Length"); l != "" {
+ t.Errorf("wrong content-length. got %q expected %q", l, "")
+ }
+}
+
+func TestCompressHandlerDeflate(t *testing.T) {
+ w := httptest.NewRecorder()
+ compressedRequest(w, "deflate")
+ if w.HeaderMap.Get("Content-Encoding") != "deflate" {
+ t.Fatalf("wrong content encoding, got %q want %q", w.HeaderMap.Get("Content-Encoding"), "deflate")
+ }
+ if w.HeaderMap.Get("Content-Type") != "text/plain; charset=utf-8" {
+ t.Fatalf("wrong content type, got %s want %s", w.HeaderMap.Get("Content-Type"), "text/plain; charset=utf-8")
+ }
+ if w.Body.Len() != 54 {
+ t.Fatalf("wrong len, got %d want %d", w.Body.Len(), 54)
+ }
+}
+
+func TestCompressHandlerGzipDeflate(t *testing.T) {
+ w := httptest.NewRecorder()
+ compressedRequest(w, "gzip, deflate ")
+ if w.HeaderMap.Get("Content-Encoding") != "gzip" {
+ t.Fatalf("wrong content encoding, got %q want %q", w.HeaderMap.Get("Content-Encoding"), "gzip")
+ }
+ if w.HeaderMap.Get("Content-Type") != "text/plain; charset=utf-8" {
+ t.Fatalf("wrong content type, got %s want %s", w.HeaderMap.Get("Content-Type"), "text/plain; charset=utf-8")
+ }
+}
+
+type fullyFeaturedResponseWriter struct{}
+
+// Header/Write/WriteHeader implement the http.ResponseWriter interface.
+func (fullyFeaturedResponseWriter) Header() http.Header {
+ return http.Header{}
+}
+func (fullyFeaturedResponseWriter) Write([]byte) (int, error) {
+ return 0, nil
+}
+func (fullyFeaturedResponseWriter) WriteHeader(int) {}
+
+// Flush implements the http.Flusher interface.
+func (fullyFeaturedResponseWriter) Flush() {}
+
+// Hijack implements the http.Hijacker interface.
+func (fullyFeaturedResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return nil, nil, nil
+}
+
+// CloseNotify implements the http.CloseNotifier interface.
+func (fullyFeaturedResponseWriter) CloseNotify() <-chan bool {
+ return nil
+}
+
+func TestCompressHandlerPreserveInterfaces(t *testing.T) {
+ // Compile time validation fullyFeaturedResponseWriter implements all the
+ // interfaces we're asserting in the test case below.
+ var (
+ _ http.Flusher = fullyFeaturedResponseWriter{}
+ _ http.CloseNotifier = fullyFeaturedResponseWriter{}
+ _ http.Hijacker = fullyFeaturedResponseWriter{}
+ )
+ var h http.Handler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
+ comp := r.Header.Get("Accept-Encoding")
+ if _, ok := rw.(*compressResponseWriter); !ok {
+ t.Fatalf("ResponseWriter wasn't wrapped by compressResponseWriter, got %T type", rw)
+ }
+ if _, ok := rw.(http.Flusher); !ok {
+ t.Errorf("ResponseWriter lost http.Flusher interface for %q", comp)
+ }
+ if _, ok := rw.(http.CloseNotifier); !ok {
+ t.Errorf("ResponseWriter lost http.CloseNotifier interface for %q", comp)
+ }
+ if _, ok := rw.(http.Hijacker); !ok {
+ t.Errorf("ResponseWriter lost http.Hijacker interface for %q", comp)
+ }
+ })
+ h = CompressHandler(h)
+ var (
+ rw fullyFeaturedResponseWriter
+ )
+ r, err := http.NewRequest("GET", "/", nil)
+ if err != nil {
+ t.Fatalf("Failed to create test request: %v", err)
+ }
+ r.Header.Set("Accept-Encoding", "gzip")
+ h.ServeHTTP(rw, r)
+
+ r.Header.Set("Accept-Encoding", "deflate")
+ h.ServeHTTP(rw, r)
+}
diff --git a/vendor/github.com/gorilla/handlers/cors_test.go b/vendor/github.com/gorilla/handlers/cors_test.go
new file mode 100644
index 000000000..c63913eee
--- /dev/null
+++ b/vendor/github.com/gorilla/handlers/cors_test.go
@@ -0,0 +1,336 @@
+package handlers
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "strings"
+ "testing"
+)
+
+func TestDefaultCORSHandlerReturnsOk(t *testing.T) {
+ r := newRequest("GET", "http://www.example.com/")
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS()(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusFound)
+ }
+}
+
+func TestDefaultCORSHandlerReturnsOkWithOrigin(t *testing.T) {
+ r := newRequest("GET", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS()(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusFound)
+ }
+}
+
+func TestCORSHandlerIgnoreOptionsFallsThrough(t *testing.T) {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusTeapot)
+ })
+
+ CORS(IgnoreOptions())(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusTeapot {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusTeapot)
+ }
+}
+
+func TestCORSHandlerSetsExposedHeaders(t *testing.T) {
+ // Test default configuration.
+ r := newRequest("GET", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS(ExposedHeaders([]string{"X-CORS-TEST"}))(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
+ }
+
+ header := rr.HeaderMap.Get(corsExposeHeadersHeader)
+ if header != "X-Cors-Test" {
+ t.Fatal("bad header: expected X-Cors-Test header, got empty header for method.")
+ }
+}
+
+func TestCORSHandlerUnsetRequestMethodForPreflightBadRequest(t *testing.T) {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS(AllowedMethods([]string{"DELETE"}))(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusBadRequest {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusBadRequest)
+ }
+}
+
+func TestCORSHandlerInvalidRequestMethodForPreflightMethodNotAllowed(t *testing.T) {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+ r.Header.Set(corsRequestMethodHeader, "DELETE")
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS()(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusMethodNotAllowed {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusMethodNotAllowed)
+ }
+}
+
+func TestCORSHandlerOptionsRequestMustNotBePassedToNextHandler(t *testing.T) {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+ r.Header.Set(corsRequestMethodHeader, "GET")
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ t.Fatal("Options request must not be passed to next handler")
+ })
+
+ CORS()(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
+ }
+}
+
+func TestCORSHandlerAllowedMethodForPreflight(t *testing.T) {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+ r.Header.Set(corsRequestMethodHeader, "DELETE")
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS(AllowedMethods([]string{"DELETE"}))(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
+ }
+
+ header := rr.HeaderMap.Get(corsAllowMethodsHeader)
+ if header != "DELETE" {
+ t.Fatalf("bad header: expected DELETE method header, got empty header.")
+ }
+}
+
+func TestCORSHandlerAllowMethodsNotSetForSimpleRequestPreflight(t *testing.T) {
+ for _, method := range defaultCorsMethods {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+ r.Header.Set(corsRequestMethodHeader, method)
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS()(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
+ }
+
+ header := rr.HeaderMap.Get(corsAllowMethodsHeader)
+ if header != "" {
+ t.Fatalf("bad header: expected empty method header, got %s.", header)
+ }
+ }
+}
+
+func TestCORSHandlerAllowedHeaderNotSetForSimpleRequestPreflight(t *testing.T) {
+ for _, simpleHeader := range defaultCorsHeaders {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+ r.Header.Set(corsRequestMethodHeader, "GET")
+ r.Header.Set(corsRequestHeadersHeader, simpleHeader)
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS()(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
+ }
+
+ header := rr.HeaderMap.Get(corsAllowHeadersHeader)
+ if header != "" {
+ t.Fatalf("bad header: expected empty header, got %s.", header)
+ }
+ }
+}
+
+func TestCORSHandlerAllowedHeaderForPreflight(t *testing.T) {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+ r.Header.Set(corsRequestMethodHeader, "POST")
+ r.Header.Set(corsRequestHeadersHeader, "Content-Type")
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS(AllowedHeaders([]string{"Content-Type"}))(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
+ }
+
+ header := rr.HeaderMap.Get(corsAllowHeadersHeader)
+ if header != "Content-Type" {
+ t.Fatalf("bad header: expected Content-Type header, got empty header.")
+ }
+}
+
+func TestCORSHandlerInvalidHeaderForPreflightForbidden(t *testing.T) {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+ r.Header.Set(corsRequestMethodHeader, "POST")
+ r.Header.Set(corsRequestHeadersHeader, "Content-Type")
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS()(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusForbidden {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusForbidden)
+ }
+}
+
+func TestCORSHandlerMaxAgeForPreflight(t *testing.T) {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+ r.Header.Set(corsRequestMethodHeader, "POST")
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS(MaxAge(3500))(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
+ }
+
+ header := rr.HeaderMap.Get(corsMaxAgeHeader)
+ if header != "600" {
+ t.Fatalf("bad header: expected %s to be %s, got %s.", corsMaxAgeHeader, "600", header)
+ }
+}
+
+func TestCORSHandlerAllowedCredentials(t *testing.T) {
+ r := newRequest("GET", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS(AllowCredentials())(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
+ }
+
+ header := rr.HeaderMap.Get(corsAllowCredentialsHeader)
+ if header != "true" {
+ t.Fatalf("bad header: expected %s to be %s, got %s.", corsAllowCredentialsHeader, "true", header)
+ }
+}
+
+func TestCORSHandlerMultipleAllowOriginsSetsVaryHeader(t *testing.T) {
+ r := newRequest("GET", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS(AllowedOrigins([]string{r.URL.String(), "http://google.com"}))(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
+ }
+
+ header := rr.HeaderMap.Get(corsVaryHeader)
+ if header != corsOriginHeader {
+ t.Fatalf("bad header: expected %s to be %s, got %s.", corsVaryHeader, corsOriginHeader, header)
+ }
+}
+
+func TestCORSWithMultipleHandlers(t *testing.T) {
+ var lastHandledBy string
+ corsMiddleware := CORS()
+
+ testHandler1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ lastHandledBy = "testHandler1"
+ })
+ testHandler2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ lastHandledBy = "testHandler2"
+ })
+
+ r1 := newRequest("GET", "http://www.example.com/")
+ rr1 := httptest.NewRecorder()
+ handler1 := corsMiddleware(testHandler1)
+
+ corsMiddleware(testHandler2)
+
+ handler1.ServeHTTP(rr1, r1)
+ if lastHandledBy != "testHandler1" {
+ t.Fatalf("bad CORS() registration: Handler served should be Handler registered")
+ }
+}
+
+func TestCORSHandlerWithCustomValidator(t *testing.T) {
+ r := newRequest("GET", "http://a.example.com")
+ r.Header.Set("Origin", r.URL.String())
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ originValidator := func(origin string) bool {
+ if strings.HasSuffix(origin, ".example.com") {
+ return true
+ }
+ return false
+ }
+
+ CORS(AllowedOriginValidator(originValidator))(testHandler).ServeHTTP(rr, r)
+ header := rr.HeaderMap.Get(corsAllowOriginHeader)
+ if header != r.URL.String() {
+ t.Fatalf("bad header: expected %s to be %s, got %s.", corsAllowOriginHeader, r.URL.String(), header)
+ }
+
+}
diff --git a/vendor/github.com/gorilla/handlers/handlers_test.go b/vendor/github.com/gorilla/handlers/handlers_test.go
new file mode 100644
index 000000000..6ea7c7fa6
--- /dev/null
+++ b/vendor/github.com/gorilla/handlers/handlers_test.go
@@ -0,0 +1,354 @@
+// Copyright 2013 The Gorilla Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package handlers
+
+import (
+ "bytes"
+ "net"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "strings"
+ "testing"
+ "time"
+)
+
+const (
+ ok = "ok\n"
+ notAllowed = "Method not allowed\n"
+)
+
+var okHandler = http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ w.Write([]byte(ok))
+})
+
+func newRequest(method, url string) *http.Request {
+ req, err := http.NewRequest(method, url, nil)
+ if err != nil {
+ panic(err)
+ }
+ return req
+}
+
+func TestMethodHandler(t *testing.T) {
+ tests := []struct {
+ req *http.Request
+ handler http.Handler
+ code int
+ allow string // Contents of the Allow header
+ body string
+ }{
+ // No handlers
+ {newRequest("GET", "/foo"), MethodHandler{}, http.StatusMethodNotAllowed, "", notAllowed},
+ {newRequest("OPTIONS", "/foo"), MethodHandler{}, http.StatusOK, "", ""},
+
+ // A single handler
+ {newRequest("GET", "/foo"), MethodHandler{"GET": okHandler}, http.StatusOK, "", ok},
+ {newRequest("POST", "/foo"), MethodHandler{"GET": okHandler}, http.StatusMethodNotAllowed, "GET", notAllowed},
+
+ // Multiple handlers
+ {newRequest("GET", "/foo"), MethodHandler{"GET": okHandler, "POST": okHandler}, http.StatusOK, "", ok},
+ {newRequest("POST", "/foo"), MethodHandler{"GET": okHandler, "POST": okHandler}, http.StatusOK, "", ok},
+ {newRequest("DELETE", "/foo"), MethodHandler{"GET": okHandler, "POST": okHandler}, http.StatusMethodNotAllowed, "GET, POST", notAllowed},
+ {newRequest("OPTIONS", "/foo"), MethodHandler{"GET": okHandler, "POST": okHandler}, http.StatusOK, "GET, POST", ""},
+
+ // Override OPTIONS
+ {newRequest("OPTIONS", "/foo"), MethodHandler{"OPTIONS": okHandler}, http.StatusOK, "", ok},
+ }
+
+ for i, test := range tests {
+ rec := httptest.NewRecorder()
+ test.handler.ServeHTTP(rec, test.req)
+ if rec.Code != test.code {
+ t.Fatalf("%d: wrong code, got %d want %d", i, rec.Code, test.code)
+ }
+ if allow := rec.HeaderMap.Get("Allow"); allow != test.allow {
+ t.Fatalf("%d: wrong Allow, got %s want %s", i, allow, test.allow)
+ }
+ if body := rec.Body.String(); body != test.body {
+ t.Fatalf("%d: wrong body, got %q want %q", i, body, test.body)
+ }
+ }
+}
+
+func TestWriteLog(t *testing.T) {
+ loc, err := time.LoadLocation("Europe/Warsaw")
+ if err != nil {
+ panic(err)
+ }
+ ts := time.Date(1983, 05, 26, 3, 30, 45, 0, loc)
+
+ // A typical request with an OK response
+ req := newRequest("GET", "http://example.com")
+ req.RemoteAddr = "192.168.100.5"
+
+ buf := new(bytes.Buffer)
+ writeLog(buf, req, *req.URL, ts, http.StatusOK, 100)
+ log := buf.String()
+
+ expected := "192.168.100.5 - - [26/May/1983:03:30:45 +0200] \"GET / HTTP/1.1\" 200 100\n"
+ if log != expected {
+ t.Fatalf("wrong log, got %q want %q", log, expected)
+ }
+
+ // CONNECT request over http/2.0
+ req = &http.Request{
+ Method: "CONNECT",
+ Proto: "HTTP/2.0",
+ ProtoMajor: 2,
+ ProtoMinor: 0,
+ URL: &url.URL{Host: "www.example.com:443"},
+ Host: "www.example.com:443",
+ RemoteAddr: "192.168.100.5",
+ }
+
+ buf = new(bytes.Buffer)
+ writeLog(buf, req, *req.URL, ts, http.StatusOK, 100)
+ log = buf.String()
+
+ expected = "192.168.100.5 - - [26/May/1983:03:30:45 +0200] \"CONNECT www.example.com:443 HTTP/2.0\" 200 100\n"
+ if log != expected {
+ t.Fatalf("wrong log, got %q want %q", log, expected)
+ }
+
+ // Request with an unauthorized user
+ req = newRequest("GET", "http://example.com")
+ req.RemoteAddr = "192.168.100.5"
+ req.URL.User = url.User("kamil")
+
+ buf.Reset()
+ writeLog(buf, req, *req.URL, ts, http.StatusUnauthorized, 500)
+ log = buf.String()
+
+ expected = "192.168.100.5 - kamil [26/May/1983:03:30:45 +0200] \"GET / HTTP/1.1\" 401 500\n"
+ if log != expected {
+ t.Fatalf("wrong log, got %q want %q", log, expected)
+ }
+
+ // Request with url encoded parameters
+ req = newRequest("GET", "http://example.com/test?abc=hello%20world&a=b%3F")
+ req.RemoteAddr = "192.168.100.5"
+
+ buf.Reset()
+ writeLog(buf, req, *req.URL, ts, http.StatusOK, 100)
+ log = buf.String()
+
+ expected = "192.168.100.5 - - [26/May/1983:03:30:45 +0200] \"GET /test?abc=hello%20world&a=b%3F HTTP/1.1\" 200 100\n"
+ if log != expected {
+ t.Fatalf("wrong log, got %q want %q", log, expected)
+ }
+}
+
+func TestWriteCombinedLog(t *testing.T) {
+ loc, err := time.LoadLocation("Europe/Warsaw")
+ if err != nil {
+ panic(err)
+ }
+ ts := time.Date(1983, 05, 26, 3, 30, 45, 0, loc)
+
+ // A typical request with an OK response
+ req := newRequest("GET", "http://example.com")
+ req.RemoteAddr = "192.168.100.5"
+ req.Header.Set("Referer", "http://example.com")
+ req.Header.Set(
+ "User-Agent",
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.33 "+
+ "(KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33",
+ )
+
+ buf := new(bytes.Buffer)
+ writeCombinedLog(buf, req, *req.URL, ts, http.StatusOK, 100)
+ log := buf.String()
+
+ expected := "192.168.100.5 - - [26/May/1983:03:30:45 +0200] \"GET / HTTP/1.1\" 200 100 \"http://example.com\" " +
+ "\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) " +
+ "AppleWebKit/537.33 (KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33\"\n"
+ if log != expected {
+ t.Fatalf("wrong log, got %q want %q", log, expected)
+ }
+
+ // CONNECT request over http/2.0
+ req1 := &http.Request{
+ Method: "CONNECT",
+ Host: "www.example.com:443",
+ Proto: "HTTP/2.0",
+ ProtoMajor: 2,
+ ProtoMinor: 0,
+ RemoteAddr: "192.168.100.5",
+ Header: http.Header{},
+ URL: &url.URL{Host: "www.example.com:443"},
+ }
+ req1.Header.Set("Referer", "http://example.com")
+ req1.Header.Set(
+ "User-Agent",
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.33 "+
+ "(KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33",
+ )
+
+ buf = new(bytes.Buffer)
+ writeCombinedLog(buf, req1, *req1.URL, ts, http.StatusOK, 100)
+ log = buf.String()
+
+ expected = "192.168.100.5 - - [26/May/1983:03:30:45 +0200] \"CONNECT www.example.com:443 HTTP/2.0\" 200 100 \"http://example.com\" " +
+ "\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) " +
+ "AppleWebKit/537.33 (KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33\"\n"
+ if log != expected {
+ t.Fatalf("wrong log, got %q want %q", log, expected)
+ }
+
+ // Request with an unauthorized user
+ req.URL.User = url.User("kamil")
+
+ buf.Reset()
+ writeCombinedLog(buf, req, *req.URL, ts, http.StatusUnauthorized, 500)
+ log = buf.String()
+
+ expected = "192.168.100.5 - kamil [26/May/1983:03:30:45 +0200] \"GET / HTTP/1.1\" 401 500 \"http://example.com\" " +
+ "\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) " +
+ "AppleWebKit/537.33 (KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33\"\n"
+ if log != expected {
+ t.Fatalf("wrong log, got %q want %q", log, expected)
+ }
+
+ // Test with remote ipv6 address
+ req.RemoteAddr = "::1"
+
+ buf.Reset()
+ writeCombinedLog(buf, req, *req.URL, ts, http.StatusOK, 100)
+ log = buf.String()
+
+ expected = "::1 - kamil [26/May/1983:03:30:45 +0200] \"GET / HTTP/1.1\" 200 100 \"http://example.com\" " +
+ "\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) " +
+ "AppleWebKit/537.33 (KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33\"\n"
+ if log != expected {
+ t.Fatalf("wrong log, got %q want %q", log, expected)
+ }
+
+ // Test remote ipv6 addr, with port
+ req.RemoteAddr = net.JoinHostPort("::1", "65000")
+
+ buf.Reset()
+ writeCombinedLog(buf, req, *req.URL, ts, http.StatusOK, 100)
+ log = buf.String()
+
+ expected = "::1 - kamil [26/May/1983:03:30:45 +0200] \"GET / HTTP/1.1\" 200 100 \"http://example.com\" " +
+ "\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) " +
+ "AppleWebKit/537.33 (KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33\"\n"
+ if log != expected {
+ t.Fatalf("wrong log, got %q want %q", log, expected)
+ }
+}
+
+func TestLogPathRewrites(t *testing.T) {
+ var buf bytes.Buffer
+
+ handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ req.URL.Path = "/" // simulate http.StripPrefix and friends
+ w.WriteHeader(200)
+ })
+ logger := LoggingHandler(&buf, handler)
+
+ logger.ServeHTTP(httptest.NewRecorder(), newRequest("GET", "/subdir/asdf"))
+
+ if !strings.Contains(buf.String(), "GET /subdir/asdf HTTP") {
+ t.Fatalf("Got log %#v, wanted substring %#v", buf.String(), "GET /subdir/asdf HTTP")
+ }
+}
+
+func BenchmarkWriteLog(b *testing.B) {
+ loc, err := time.LoadLocation("Europe/Warsaw")
+ if err != nil {
+ b.Fatalf(err.Error())
+ }
+ ts := time.Date(1983, 05, 26, 3, 30, 45, 0, loc)
+
+ req := newRequest("GET", "http://example.com")
+ req.RemoteAddr = "192.168.100.5"
+
+ b.ResetTimer()
+
+ buf := &bytes.Buffer{}
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ writeLog(buf, req, *req.URL, ts, http.StatusUnauthorized, 500)
+ }
+}
+
+func TestContentTypeHandler(t *testing.T) {
+ tests := []struct {
+ Method string
+ AllowContentTypes []string
+ ContentType string
+ Code int
+ }{
+ {"POST", []string{"application/json"}, "application/json", http.StatusOK},
+ {"POST", []string{"application/json", "application/xml"}, "application/json", http.StatusOK},
+ {"POST", []string{"application/json"}, "application/json; charset=utf-8", http.StatusOK},
+ {"POST", []string{"application/json"}, "application/json+xxx", http.StatusUnsupportedMediaType},
+ {"POST", []string{"application/json"}, "text/plain", http.StatusUnsupportedMediaType},
+ {"GET", []string{"application/json"}, "", http.StatusOK},
+ {"GET", []string{}, "", http.StatusOK},
+ }
+ for _, test := range tests {
+ r, err := http.NewRequest(test.Method, "/", nil)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+
+ h := ContentTypeHandler(okHandler, test.AllowContentTypes...)
+ r.Header.Set("Content-Type", test.ContentType)
+ w := httptest.NewRecorder()
+ h.ServeHTTP(w, r)
+ if w.Code != test.Code {
+ t.Errorf("expected %d, got %d", test.Code, w.Code)
+ }
+ }
+}
+
+func TestHTTPMethodOverride(t *testing.T) {
+ var tests = []struct {
+ Method string
+ OverrideMethod string
+ ExpectedMethod string
+ }{
+ {"POST", "PUT", "PUT"},
+ {"POST", "PATCH", "PATCH"},
+ {"POST", "DELETE", "DELETE"},
+ {"PUT", "DELETE", "PUT"},
+ {"GET", "GET", "GET"},
+ {"HEAD", "HEAD", "HEAD"},
+ {"GET", "PUT", "GET"},
+ {"HEAD", "DELETE", "HEAD"},
+ }
+
+ for _, test := range tests {
+ h := HTTPMethodOverrideHandler(okHandler)
+ reqs := make([]*http.Request, 0, 2)
+
+ rHeader, err := http.NewRequest(test.Method, "/", nil)
+ if err != nil {
+ t.Error(err)
+ }
+ rHeader.Header.Set(HTTPMethodOverrideHeader, test.OverrideMethod)
+ reqs = append(reqs, rHeader)
+
+ f := url.Values{HTTPMethodOverrideFormKey: []string{test.OverrideMethod}}
+ rForm, err := http.NewRequest(test.Method, "/", strings.NewReader(f.Encode()))
+ if err != nil {
+ t.Error(err)
+ }
+ rForm.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+ reqs = append(reqs, rForm)
+
+ for _, r := range reqs {
+ w := httptest.NewRecorder()
+ h.ServeHTTP(w, r)
+ if r.Method != test.ExpectedMethod {
+ t.Errorf("Expected %s, got %s", test.ExpectedMethod, r.Method)
+ }
+ }
+ }
+}
diff --git a/vendor/github.com/gorilla/handlers/proxy_headers_test.go b/vendor/github.com/gorilla/handlers/proxy_headers_test.go
new file mode 100644
index 000000000..85282ef7d
--- /dev/null
+++ b/vendor/github.com/gorilla/handlers/proxy_headers_test.go
@@ -0,0 +1,100 @@
+package handlers
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "testing"
+)
+
+type headerTable struct {
+ key string // header key
+ val string // header val
+ expected string // expected result
+}
+
+func TestGetIP(t *testing.T) {
+ headers := []headerTable{
+ {xForwardedFor, "8.8.8.8", "8.8.8.8"}, // Single address
+ {xForwardedFor, "8.8.8.8, 8.8.4.4", "8.8.8.8"}, // Multiple
+ {xForwardedFor, "[2001:db8:cafe::17]:4711", "[2001:db8:cafe::17]:4711"}, // IPv6 address
+ {xForwardedFor, "", ""}, // None
+ {xRealIP, "8.8.8.8", "8.8.8.8"}, // Single address
+ {xRealIP, "8.8.8.8, 8.8.4.4", "8.8.8.8, 8.8.4.4"}, // Multiple
+ {xRealIP, "[2001:db8:cafe::17]:4711", "[2001:db8:cafe::17]:4711"}, // IPv6 address
+ {xRealIP, "", ""}, // None
+ {forwarded, `for="_gazonk"`, "_gazonk"}, // Hostname
+ {forwarded, `For="[2001:db8:cafe::17]:4711`, `[2001:db8:cafe::17]:4711`}, // IPv6 address
+ {forwarded, `for=192.0.2.60;proto=http;by=203.0.113.43`, `192.0.2.60`}, // Multiple params
+ {forwarded, `for=192.0.2.43, for=198.51.100.17`, "192.0.2.43"}, // Multiple params
+ {forwarded, `for="workstation.local",for=198.51.100.17`, "workstation.local"}, // Hostname
+ }
+
+ for _, v := range headers {
+ req := &http.Request{
+ Header: http.Header{
+ v.key: []string{v.val},
+ }}
+ res := getIP(req)
+ if res != v.expected {
+ t.Fatalf("wrong header for %s: got %s want %s", v.key, res,
+ v.expected)
+ }
+ }
+}
+
+func TestGetScheme(t *testing.T) {
+ headers := []headerTable{
+ {xForwardedProto, "https", "https"},
+ {xForwardedProto, "http", "http"},
+ {xForwardedProto, "HTTP", "http"},
+ {forwarded, `For="[2001:db8:cafe::17]:4711`, ""}, // No proto
+ {forwarded, `for=192.0.2.43, for=198.51.100.17;proto=https`, "https"}, // Multiple params before proto
+ {forwarded, `for=172.32.10.15; proto=https;by=127.0.0.1`, "https"}, // Space before proto
+ {forwarded, `for=192.0.2.60;proto=http;by=203.0.113.43`, "http"}, // Multiple params
+ }
+
+ for _, v := range headers {
+ req := &http.Request{
+ Header: http.Header{
+ v.key: []string{v.val},
+ },
+ }
+ res := getScheme(req)
+ if res != v.expected {
+ t.Fatalf("wrong header for %s: got %s want %s", v.key, res,
+ v.expected)
+ }
+ }
+}
+
+// Test the middleware end-to-end
+func TestProxyHeaders(t *testing.T) {
+ rr := httptest.NewRecorder()
+ r := newRequest("GET", "/")
+
+ r.Header.Set(xForwardedFor, "8.8.8.8")
+ r.Header.Set(xForwardedProto, "https")
+
+ var addr string
+ var proto string
+ ProxyHeaders(http.HandlerFunc(
+ func(w http.ResponseWriter, r *http.Request) {
+ addr = r.RemoteAddr
+ proto = r.URL.Scheme
+ })).ServeHTTP(rr, r)
+
+ if rr.Code != http.StatusOK {
+ t.Fatalf("bad status: got %d want %d", rr.Code, http.StatusOK)
+ }
+
+ if addr != r.Header.Get(xForwardedFor) {
+ t.Fatalf("wrong address: got %s want %s", addr,
+ r.Header.Get(xForwardedFor))
+ }
+
+ if proto != r.Header.Get(xForwardedProto) {
+ t.Fatalf("wrong address: got %s want %s", proto,
+ r.Header.Get(xForwardedProto))
+ }
+
+}
diff --git a/vendor/github.com/gorilla/handlers/recovery_test.go b/vendor/github.com/gorilla/handlers/recovery_test.go
new file mode 100644
index 000000000..1ae0e5805
--- /dev/null
+++ b/vendor/github.com/gorilla/handlers/recovery_test.go
@@ -0,0 +1,44 @@
+package handlers
+
+import (
+ "bytes"
+ "log"
+ "net/http"
+ "net/http/httptest"
+ "strings"
+ "testing"
+)
+
+func TestRecoveryLoggerWithDefaultOptions(t *testing.T) {
+ var buf bytes.Buffer
+ log.SetOutput(&buf)
+
+ handler := RecoveryHandler()
+ handlerFunc := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ panic("Unexpected error!")
+ })
+
+ recovery := handler(handlerFunc)
+ recovery.ServeHTTP(httptest.NewRecorder(), newRequest("GET", "/subdir/asdf"))
+
+ if !strings.Contains(buf.String(), "Unexpected error!") {
+ t.Fatalf("Got log %#v, wanted substring %#v", buf.String(), "Unexpected error!")
+ }
+}
+
+func TestRecoveryLoggerWithCustomLogger(t *testing.T) {
+ var buf bytes.Buffer
+ var logger = log.New(&buf, "", log.LstdFlags)
+
+ handler := RecoveryHandler(RecoveryLogger(logger), PrintRecoveryStack(false))
+ handlerFunc := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ panic("Unexpected error!")
+ })
+
+ recovery := handler(handlerFunc)
+ recovery.ServeHTTP(httptest.NewRecorder(), newRequest("GET", "/subdir/asdf"))
+
+ if !strings.Contains(buf.String(), "Unexpected error!") {
+ t.Fatalf("Got log %#v, wanted substring %#v", buf.String(), "Unexpected error!")
+ }
+}