summaryrefslogtreecommitdiff
path: root/vendor/github.com/gorilla/handlers/handlers.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/gorilla/handlers/handlers.go')
-rw-r--r--vendor/github.com/gorilla/handlers/handlers.go287
1 files changed, 28 insertions, 259 deletions
diff --git a/vendor/github.com/gorilla/handlers/handlers.go b/vendor/github.com/gorilla/handlers/handlers.go
index c3c20e5b9..0509482ad 100644
--- a/vendor/github.com/gorilla/handlers/handlers.go
+++ b/vendor/github.com/gorilla/handlers/handlers.go
@@ -7,27 +7,22 @@ package handlers
import (
"bufio"
"fmt"
- "io"
"net"
"net/http"
- "net/url"
"sort"
- "strconv"
"strings"
- "time"
- "unicode/utf8"
)
-// MethodHandler is an http.Handler that dispatches to a handler whose key in the MethodHandler's
-// map matches the name of the HTTP request's method, eg: GET
+// MethodHandler is an http.Handler that dispatches to a handler whose key in the
+// MethodHandler's map matches the name of the HTTP request's method, eg: GET
//
-// If the request's method is OPTIONS and OPTIONS is not a key in the map then the handler
-// responds with a status of 200 and sets the Allow header to a comma-separated list of
-// available methods.
+// If the request's method is OPTIONS and OPTIONS is not a key in the map then
+// the handler responds with a status of 200 and sets the Allow header to a
+// comma-separated list of available methods.
//
-// If the request's method doesn't match any of its keys the handler responds with
-// a status of 405, Method not allowed and sets the Allow header to a comma-separated list
-// of available methods.
+// If the request's method doesn't match any of its keys the handler responds
+// with a status of HTTP 405 "Method Not Allowed" and sets the Allow header to a
+// comma-separated list of available methods.
type MethodHandler map[string]http.Handler
func (h MethodHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
@@ -48,74 +43,15 @@ func (h MethodHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
}
}
-// loggingHandler is the http.Handler implementation for LoggingHandlerTo and its friends
-type loggingHandler struct {
- writer io.Writer
- handler http.Handler
-}
-
-// combinedLoggingHandler is the http.Handler implementation for LoggingHandlerTo and its friends
-type combinedLoggingHandler struct {
- writer io.Writer
- handler http.Handler
-}
-
-func (h loggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
- t := time.Now()
- logger := makeLogger(w)
- url := *req.URL
- h.handler.ServeHTTP(logger, req)
- writeLog(h.writer, req, url, t, logger.Status(), logger.Size())
-}
-
-func (h combinedLoggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
- t := time.Now()
- logger := makeLogger(w)
- url := *req.URL
- h.handler.ServeHTTP(logger, req)
- writeCombinedLog(h.writer, req, url, t, logger.Status(), logger.Size())
-}
-
-func makeLogger(w http.ResponseWriter) loggingResponseWriter {
- var logger loggingResponseWriter = &responseLogger{w: w}
- if _, ok := w.(http.Hijacker); ok {
- logger = &hijackLogger{responseLogger{w: w}}
- }
- h, ok1 := logger.(http.Hijacker)
- c, ok2 := w.(http.CloseNotifier)
- if ok1 && ok2 {
- return hijackCloseNotifier{logger, h, c}
- }
- if ok2 {
- return &closeNotifyWriter{logger, c}
- }
- return logger
-}
-
-type loggingResponseWriter interface {
- http.ResponseWriter
- http.Flusher
- Status() int
- Size() int
-}
-
-// responseLogger is wrapper of http.ResponseWriter that keeps track of its HTTP status
-// code and body size
+// responseLogger is wrapper of http.ResponseWriter that keeps track of its HTTP
+// status code and body size
type responseLogger struct {
w http.ResponseWriter
status int
size int
}
-func (l *responseLogger) Header() http.Header {
- return l.w.Header()
-}
-
func (l *responseLogger) Write(b []byte) (int, error) {
- if l.status == 0 {
- // The status will be StatusOK if WriteHeader has not been called yet
- l.status = http.StatusOK
- }
size, err := l.w.Write(b)
l.size += size
return size, err
@@ -134,187 +70,18 @@ func (l *responseLogger) Size() int {
return l.size
}
-func (l *responseLogger) Flush() {
- f, ok := l.w.(http.Flusher)
- if ok {
- f.Flush()
- }
-}
-
-type hijackLogger struct {
- responseLogger
-}
-
-func (l *hijackLogger) Hijack() (net.Conn, *bufio.ReadWriter, error) {
- h := l.responseLogger.w.(http.Hijacker)
- conn, rw, err := h.Hijack()
- if err == nil && l.responseLogger.status == 0 {
- // The status will be StatusSwitchingProtocols if there was no error and WriteHeader has not been called yet
- l.responseLogger.status = http.StatusSwitchingProtocols
+func (l *responseLogger) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ conn, rw, err := l.w.(http.Hijacker).Hijack()
+ if err == nil && l.status == 0 {
+ // The status will be StatusSwitchingProtocols if there was no error and
+ // WriteHeader has not been called yet
+ l.status = http.StatusSwitchingProtocols
}
return conn, rw, err
}
-type closeNotifyWriter struct {
- loggingResponseWriter
- http.CloseNotifier
-}
-
-type hijackCloseNotifier struct {
- loggingResponseWriter
- http.Hijacker
- http.CloseNotifier
-}
-
-const lowerhex = "0123456789abcdef"
-
-func appendQuoted(buf []byte, s string) []byte {
- var runeTmp [utf8.UTFMax]byte
- for width := 0; len(s) > 0; s = s[width:] {
- r := rune(s[0])
- width = 1
- if r >= utf8.RuneSelf {
- r, width = utf8.DecodeRuneInString(s)
- }
- if width == 1 && r == utf8.RuneError {
- buf = append(buf, `\x`...)
- buf = append(buf, lowerhex[s[0]>>4])
- buf = append(buf, lowerhex[s[0]&0xF])
- continue
- }
- if r == rune('"') || r == '\\' { // always backslashed
- buf = append(buf, '\\')
- buf = append(buf, byte(r))
- continue
- }
- if strconv.IsPrint(r) {
- n := utf8.EncodeRune(runeTmp[:], r)
- buf = append(buf, runeTmp[:n]...)
- continue
- }
- switch r {
- case '\a':
- buf = append(buf, `\a`...)
- case '\b':
- buf = append(buf, `\b`...)
- case '\f':
- buf = append(buf, `\f`...)
- case '\n':
- buf = append(buf, `\n`...)
- case '\r':
- buf = append(buf, `\r`...)
- case '\t':
- buf = append(buf, `\t`...)
- case '\v':
- buf = append(buf, `\v`...)
- default:
- switch {
- case r < ' ':
- buf = append(buf, `\x`...)
- buf = append(buf, lowerhex[s[0]>>4])
- buf = append(buf, lowerhex[s[0]&0xF])
- case r > utf8.MaxRune:
- r = 0xFFFD
- fallthrough
- case r < 0x10000:
- buf = append(buf, `\u`...)
- for s := 12; s >= 0; s -= 4 {
- buf = append(buf, lowerhex[r>>uint(s)&0xF])
- }
- default:
- buf = append(buf, `\U`...)
- for s := 28; s >= 0; s -= 4 {
- buf = append(buf, lowerhex[r>>uint(s)&0xF])
- }
- }
- }
- }
- return buf
-
-}
-
-// buildCommonLogLine builds a log entry for req in Apache Common Log Format.
-// ts is the timestamp with which the entry should be logged.
-// status and size are used to provide the response HTTP status and size.
-func buildCommonLogLine(req *http.Request, url url.URL, ts time.Time, status int, size int) []byte {
- username := "-"
- if url.User != nil {
- if name := url.User.Username(); name != "" {
- username = name
- }
- }
-
- host, _, err := net.SplitHostPort(req.RemoteAddr)
-
- if err != nil {
- host = req.RemoteAddr
- }
-
- uri := url.RequestURI()
-
- buf := make([]byte, 0, 3*(len(host)+len(username)+len(req.Method)+len(uri)+len(req.Proto)+50)/2)
- buf = append(buf, host...)
- buf = append(buf, " - "...)
- buf = append(buf, username...)
- buf = append(buf, " ["...)
- buf = append(buf, ts.Format("02/Jan/2006:15:04:05 -0700")...)
- buf = append(buf, `] "`...)
- buf = append(buf, req.Method...)
- buf = append(buf, " "...)
- buf = appendQuoted(buf, uri)
- buf = append(buf, " "...)
- buf = append(buf, req.Proto...)
- buf = append(buf, `" `...)
- buf = append(buf, strconv.Itoa(status)...)
- buf = append(buf, " "...)
- buf = append(buf, strconv.Itoa(size)...)
- return buf
-}
-
-// writeLog writes a log entry for req to w in Apache Common Log Format.
-// ts is the timestamp with which the entry should be logged.
-// status and size are used to provide the response HTTP status and size.
-func writeLog(w io.Writer, req *http.Request, url url.URL, ts time.Time, status, size int) {
- buf := buildCommonLogLine(req, url, ts, status, size)
- buf = append(buf, '\n')
- w.Write(buf)
-}
-
-// writeCombinedLog writes a log entry for req to w in Apache Combined Log Format.
-// ts is the timestamp with which the entry should be logged.
-// status and size are used to provide the response HTTP status and size.
-func writeCombinedLog(w io.Writer, req *http.Request, url url.URL, ts time.Time, status, size int) {
- buf := buildCommonLogLine(req, url, ts, status, size)
- buf = append(buf, ` "`...)
- buf = appendQuoted(buf, req.Referer())
- buf = append(buf, `" "`...)
- buf = appendQuoted(buf, req.UserAgent())
- buf = append(buf, '"', '\n')
- w.Write(buf)
-}
-
-// CombinedLoggingHandler return a http.Handler that wraps h and logs requests to out in
-// Apache Combined Log Format.
-//
-// See http://httpd.apache.org/docs/2.2/logs.html#combined for a description of this format.
-//
-// LoggingHandler always sets the ident field of the log to -
-func CombinedLoggingHandler(out io.Writer, h http.Handler) http.Handler {
- return combinedLoggingHandler{out, h}
-}
-
-// LoggingHandler return a http.Handler that wraps h and logs requests to out in
-// Apache Common Log Format (CLF).
-//
-// See http://httpd.apache.org/docs/2.2/logs.html#common for a description of this format.
-//
-// LoggingHandler always sets the ident field of the log to -
-func LoggingHandler(out io.Writer, h http.Handler) http.Handler {
- return loggingHandler{out, h}
-}
-
-// isContentType validates the Content-Type header
-// is contentType. That is, its type and subtype match.
+// isContentType validates the Content-Type header matches the supplied
+// contentType. That is, its type and subtype match.
func isContentType(h http.Header, contentType string) bool {
ct := h.Get("Content-Type")
if i := strings.IndexRune(ct, ';'); i != -1 {
@@ -323,9 +90,9 @@ func isContentType(h http.Header, contentType string) bool {
return ct == contentType
}
-// ContentTypeHandler wraps and returns a http.Handler, validating the request content type
-// is acompatible with the contentTypes list.
-// It writes a HTTP 415 error if that fails.
+// ContentTypeHandler wraps and returns a http.Handler, validating the request
+// content type is compatible with the contentTypes list. It writes a HTTP 415
+// error if that fails.
//
// Only PUT, POST, and PATCH requests are considered.
func ContentTypeHandler(h http.Handler, contentTypes ...string) http.Handler {
@@ -354,12 +121,14 @@ const (
HTTPMethodOverrideFormKey = "_method"
)
-// HTTPMethodOverrideHandler wraps and returns a http.Handler which checks for the X-HTTP-Method-Override header
-// or the _method form key, and overrides (if valid) request.Method with its value.
+// HTTPMethodOverrideHandler wraps and returns a http.Handler which checks for
+// the X-HTTP-Method-Override header or the _method form key, and overrides (if
+// valid) request.Method with its value.
//
-// This is especially useful for http clients that don't support many http verbs.
-// It isn't secure to override e.g a GET to a POST, so only POST requests are considered.
-// Likewise, the override method can only be a "write" method: PUT, PATCH or DELETE.
+// This is especially useful for HTTP clients that don't support many http verbs.
+// It isn't secure to override e.g a GET to a POST, so only POST requests are
+// considered. Likewise, the override method can only be a "write" method: PUT,
+// PATCH or DELETE.
//
// Form method takes precedence over header method.
func HTTPMethodOverrideHandler(h http.Handler) http.Handler {