// PlainText sets the content-type of responses to text/plain. func Json(h http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/json") h.ServeHTTP(w, r) } return http.HandlerFunc(fn) }
func debugMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { t0 := time.Now() h.ServeHTTP(w, r) if shouldDebugHTTP() { ms := 1000 * time.Since(t0).Seconds() // The variable `w` is most likely a *http.response, which we can't do // much with since it's a non exported type. We can however peek into // it with reflection to get at the status code and number of bytes // written. var status, written int64 if rw := reflect.Indirect(reflect.ValueOf(w)); rw.IsValid() && rw.Kind() == reflect.Struct { if rf := rw.FieldByName("status"); rf.IsValid() && rf.Kind() == reflect.Int { status = rf.Int() } if rf := rw.FieldByName("written"); rf.IsValid() && rf.Kind() == reflect.Int64 { written = rf.Int() } } httpl.Debugf("http: %s %q: status %d, %d bytes in %.02f ms", r.Method, r.URL.String(), status, written, ms) } }) }
func withDetailsMiddleware(id protocol.DeviceID, h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("X-Syncthing-Version", Version) w.Header().Set("X-Syncthing-ID", id.String()) h.ServeHTTP(w, r) }) }
func wrapBasicAuth(handler http.Handler, credential string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { token := strings.SplitN(r.Header.Get("Authorization"), " ", 2) if len(token) != 2 || strings.ToLower(token[0]) != "basic" { w.Header().Set("WWW-Authenticate", `Basic realm="GoTTY"`) http.Error(w, "Bad Request", http.StatusUnauthorized) return } payload, err := base64.StdEncoding.DecodeString(token[1]) if err != nil { http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } if credential != string(payload) { w.Header().Set("WWW-Authenticate", `Basic realm="GoTTY"`) http.Error(w, "authorization failed", http.StatusUnauthorized) return } log.Printf("Basic Authentication Succeeded: %s", r.RemoteAddr) handler.ServeHTTP(w, r) }) }
func Green(next http.Handler) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { rw.Header().Set("X-Favorite-Color", "green") next.ServeHTTP(rw, req) fmt.Fprint(rw, " who likes green") }) }
func Logger(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { //startTime := time.Now() h.ServeHTTP(w, r) //log.Printf("[vertigo] %s %s (%v)\n", r.Method, r.URL.Path, time.Since(startTime)) }) }
// ServeHTTP dispatches the handler registered in the matched route. // // When there is a match, the route variables can be retrieved calling // mux.Vars(request). func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { // Clean path to canonical form and redirect. if p := cleanPath(req.URL.Path); p != req.URL.Path { // Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query. // This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue: // http://code.google.com/p/go/issues/detail?id=5252 url := *req.URL url.Path = p p = url.String() w.Header().Set("Location", p) w.WriteHeader(http.StatusMovedPermanently) return } var match RouteMatch var handler http.Handler if r.Match(req, &match) { handler = match.Handler setVars(req, match.Vars) setCurrentRoute(req, match.Route) } if handler == nil { handler = r.NotFoundHandler if handler == nil { handler = http.NotFoundHandler() } } if !r.KeepContext { defer context.Clear(req) } handler.ServeHTTP(w, req) }
// cors responds to incoming requests and adds the appropriate cors headers // TODO: corylanou: add the ability to configure this in our config func cors(inner http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if origin := r.Header.Get("Origin"); origin != "" { w.Header().Set(`Access-Control-Allow-Origin`, origin) w.Header().Set(`Access-Control-Allow-Methods`, strings.Join([]string{ `DELETE`, `GET`, `OPTIONS`, `POST`, `PUT`, }, ", ")) w.Header().Set(`Access-Control-Allow-Headers`, strings.Join([]string{ `Accept`, `Accept-Encoding`, `Authorization`, `Content-Length`, `Content-Type`, `X-CSRF-Token`, `X-HTTP-Method-Override`, }, ", ")) } if r.Method == "OPTIONS" { return } inner.ServeHTTP(w, r) }) }
// Handle regiester a standard http.Handler request handler with the given // path and method. With this adapter, your handler won't have access to the // context and thus won't work with URL parameters. func (mux *Mux) Handle(method, path string, handler http.Handler) { mux.HandleC(method, path, xhandler.HandlerFuncC(func(_ context.Context, w http.ResponseWriter, r *http.Request) { handler.ServeHTTP(w, r) }), ) }
func Log(handler http.Handler) http.Handler { log.Println(handler) return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { log.Printf("%s %s %s &s", r.RemoteAddr, r.Method, r.URL) handler.ServeHTTP(w, r) }) }
func auth(config *Config, next http.Handler) http.Handler { unauthorized := func(w http.ResponseWriter) { send(w, http.StatusUnauthorized, Json{"error": "Unauthorized"}) } return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { if config.Auth != "" { s := strings.SplitN(req.Header.Get("Authorization"), " ", 2) if len(s) != 2 || s[0] != "Basic" { unauthorized(w) return } base, err := base64.StdEncoding.DecodeString(s[1]) if err != nil { unauthorized(w) return } pair := strings.SplitN(string(base), ":", 2) if len(pair) != 2 { unauthorized(w) return } password := pair[1] if config.Auth != password { unauthorized(w) return } } next.ServeHTTP(w, req) }) }
func Wrap(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { m := New(w, r) next.ServeHTTP(m, r) m.Log() }) }
func (c *MasterConfig) authorizationFilter(handler http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { attributes, err := c.AuthorizationAttributeBuilder.GetAttributes(req) if err != nil { forbidden(err.Error(), attributes, w, req) return } if attributes == nil { forbidden("No attributes", attributes, w, req) return } ctx, exists := c.RequestContextMapper.Get(req) if !exists { forbidden("context not found", attributes, w, req) return } allowed, reason, err := c.Authorizer.Authorize(ctx, attributes) if err != nil { forbidden(err.Error(), attributes, w, req) return } if !allowed { forbidden(reason, attributes, w, req) return } handler.ServeHTTP(w, req) }) }
// namespacingFilter adds a filter that adds the namespace of the request to the context. Not all requests will have namespaces, // but any that do will have the appropriate value added. func namespacingFilter(handler http.Handler, contextMapper kapi.RequestContextMapper) http.Handler { infoResolver := &apiserver.RequestInfoResolver{APIPrefixes: sets.NewString("api", "osapi", "oapi", "apis"), GrouplessAPIPrefixes: sets.NewString("api", "osapi", "oapi")} return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { ctx, ok := contextMapper.Get(req) if !ok { http.Error(w, "Unable to find request context", http.StatusInternalServerError) return } if _, exists := kapi.NamespaceFrom(ctx); !exists { if requestInfo, err := infoResolver.GetRequestInfo(req); err == nil { // only set the namespace if the apiRequestInfo was resolved // keep in mind that GetAPIRequestInfo will fail on non-api requests, so don't fail the entire http request on that // kind of failure. // TODO reconsider special casing this. Having the special case hereallow us to fully share the kube // APIRequestInfoResolver without any modification or customization. namespace := requestInfo.Namespace if (requestInfo.Resource == "projects") && (len(requestInfo.Name) > 0) { namespace = requestInfo.Name } ctx = kapi.WithNamespace(ctx, namespace) contextMapper.Update(req, ctx) } } handler.ServeHTTP(w, req) }) }
func Logger(inner http.Handler, name string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() w.Header().Add("Access-Control-Allow-Origin", "http://ayeke.me:3000") var err error defer func() { r := recover() if r != nil { switch t := r.(type) { case string: err = errors.New(t) case error: err = t default: err = errors.New("Unknown error") } http.Error(w, err.Error(), http.StatusInternalServerError) } }() inner.ServeHTTP(w, r) log.Printf( "%s\t%s\t%s\t%s", r.Method, r.RequestURI, name, time.Since(start), ) }) }
// Handler is an adapter which allows the usage of an http.Handler as a // request handle. func (r *Router) Handler(method, path string, handler http.Handler) { r.Handle(method, path, func(w http.ResponseWriter, req *http.Request, _ Params) { handler.ServeHTTP(w, req) }, ) }
// LogrusLogger is a middleware that will log each request recieved, along with // some useful information, to the given logger. func LogrusLogger(logger *logrus.Logger, h http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { start := time.Now() entry := logger.WithFields(logrus.Fields{ "request": r.RequestURI, "method": r.Method, "remote": r.RemoteAddr, }) if id := r.Header.Get(RequestIDKey); id != "" { entry = entry.WithField("request_id", id) } // Wrap the writer so we can track data information. neww := WrapWriter(w) // Dispatch to the underlying handler. entry.Info("started handling request") h.ServeHTTP(neww, r) // Log final information. entry.WithFields(logrus.Fields{ "bytes_written": neww.BytesWritten(), "status": neww.Status(), "text_status": http.StatusText(neww.Status()), "took": time.Since(start), }).Info("completed handling request") } return http.HandlerFunc(fn) }
func WrapBefore(handler http.Handler) HandlerFunc { return func(ctx *Context) { handler.ServeHTTP(ctx.ResponseWriter, ctx.Req()) ctx.Next() } }
// Log adds Generic request logging as a handler, cause thats probably a good idea func Log(handler http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ff := r.Header.Get("X-Forwarded-For") log.Printf("client='%s' forward-for='%s' method='%s' request='%s' agent='%s'", r.RemoteAddr, ff, r.Method, r.URL, r.UserAgent()) handler.ServeHTTP(w, r) }) }
func WrapAfter(handler http.Handler) HandlerFunc { return func(ctx *Context) { ctx.Next() handler.ServeHTTP(ctx.ResponseWriter, ctx.Req()) } }
func secretHandler(secret string, next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { if secret != "" { s := req.Header.Get("X-Hub-Signature") if s == "" { w.WriteHeader(http.StatusForbidden) fmt.Fprintf(w, "X-Hub-Signature required for HMAC verification") return } body, _ := ioutil.ReadAll(req.Body) hash := hmac.New(sha1.New, []byte(secret)) hash.Write(body) expected := "sha1=" + hex.EncodeToString(hash.Sum(nil)) if !hmac.Equal([]byte(expected), []byte(s)) { w.WriteHeader(http.StatusForbidden) fmt.Fprintf(w, "HMAC verification failed") return } req.Body = ioutil.NopCloser(bytes.NewBuffer(body)) } next.ServeHTTP(w, req) }) }
// trackRequests wraps a http.Handler, incrementing and decrementing // the apiserver's WaitGroup and blocking request when the apiserver // is shutting down. // // Note: It is only safe to use trackRequests with API handlers which // are interruptible (i.e. they pay attention to the apiserver tomb) // or are guaranteed to be short-lived. If it's used with long running // API handlers which don't watch the apiserver's tomb, apiserver // shutdown will be blocked until the API handler returns. func (srv *Server) trackRequests(handler http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Care must be taken to not increment the waitgroup count // after the listener has closed. // // First we check to see if the tomb has not yet been killed // because the closure of the listener depends on the tomb being // killed to trigger the defer block in srv.run. select { case <-srv.tomb.Dying(): // This request was accepted before the listener was closed // but after the tomb was killed. As we're in the process of // shutting down, do not consider this request as in progress, // just send a 503 and return. http.Error(w, "apiserver shutdown in progress", 503) default: // If we get here then the tomb was not killed therefore the // listener is still open. It is safe to increment the // wg counter as wg.Wait in srv.run has not yet been called. srv.wg.Add(1) defer srv.wg.Done() handler.ServeHTTP(w, r) } }) }
func SetUser(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { token := r.Header.Get("X-Auth-Token") if token == "" { ctx.SetCurrentUser(r, nil) } else { user, found, err := model.FindUserByToken(token, ctx.M(r)) if err != nil { log.Println(err) w.WriteHeader(http.StatusInternalServerError) return } if found { ctx.SetCurrentUser(r, &user) } else { ctx.SetCurrentUser(r, nil) } } h.ServeHTTP(w, r) }) }
func (c *appContext) authHandler(next http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { // Get a session. We're ignoring the error resulted from decoding an // existing session: Get() always returns a session, even if empty. session, err := cookieStore.Get(r, "mt_logged_in") if err != nil { http.Error(w, http.StatusText(401), 401) return } var u models.User u.UserId = session.Values["user_id"].(int) u.Steam64 = session.Values["steam64"].(int) u.Steam32 = session.Values["steam32"].(int) u.Email = session.Values["email"].(string) u.Name = session.Values["name"].(string) context.Set(r, "user", u) next.ServeHTTP(w, r) } return http.HandlerFunc(fn) }
func NewRequestLogger(handler http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { rw := w.(*ResponseWriter) reqID, _ := ctxhelper.RequestIDFromContext(rw.Context()) componentName, _ := ctxhelper.ComponentNameFromContext(rw.Context()) logger := log.New(log.Ctx{"component": componentName, "req_id": reqID}) rw.ctx = ctxhelper.NewContextLogger(rw.Context(), logger) start := time.Now() var clientIP string clientIPs := strings.Split(req.Header.Get("X-Forwarded-For"), ",") if len(clientIPs) > 0 { clientIP = strings.TrimSpace(clientIPs[len(clientIPs)-1]) } var err error if clientIP == "" { clientIP, _, err = net.SplitHostPort(req.RemoteAddr) if err != nil { Error(w, err) return } } logger.Info("request started", "method", req.Method, "path", req.URL.Path, "client_ip", clientIP) handler.ServeHTTP(rw, req) logger.Info("request completed", "status", rw.Status(), "duration", time.Since(start)) }) }
// Efficient favicon handler, mostly a port of node's Connect library implementation // of the favicon middleware. // https://github.com/senchalabs/connect func FaviconHandler(h http.Handler, path string, maxAge time.Duration) http.HandlerFunc { var buf []byte var hash string return func(w http.ResponseWriter, r *http.Request) { var err error if r.URL.Path == "/favicon.ico" { if buf == nil { // Read from file and cache ghost.LogFn("ghost.favicon : serving from %s", path) buf, err = ioutil.ReadFile(path) if err != nil { ghost.LogFn("ghost.favicon : error reading file : %s", err) http.NotFound(w, r) return } hash = hashContent(buf) } writeHeaders(w.Header(), buf, maxAge, hash) writeBody(w, r, buf) } else { h.ServeHTTP(w, r) } } }
func corsMiddleware(next http.Handler) http.Handler { // Handle CORS headers and CORS OPTIONS request. // CORS OPTIONS request are typically sent by browser during AJAX preflight // when the browser initiate a POST request. // // As the OPTIONS request is unauthorized, this handler must be the first // of the chain (hence added at the end). // // See https://www.w3.org/TR/cors/ for details. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Process OPTIONS requests if r.Method == "OPTIONS" { // Only GET/POST Methods are supported w.Header().Set("Access-Control-Allow-Methods", "GET, POST") // Only this custom header can be set w.Header().Set("Access-Control-Allow-Headers", "X-API-Key") // The request is meant to be cached 10 minutes w.Header().Set("Access-Control-Max-Age", "600") // Indicate that no content will be returned w.WriteHeader(204) return } // For everything else, pass to the next handler next.ServeHTTP(w, r) return }) }
func handlerAccessLog(handler http.Handler) http.Handler { logHandler := func(w http.ResponseWriter, r *http.Request) { log.Printf("%s \"%s %s\"", r.RemoteAddr, r.Method, r.URL) handler.ServeHTTP(w, r) } return http.HandlerFunc(logHandler) }
func logRequests(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { //do stuff with the request here log.Println("Request logged") h.ServeHTTP(w, r) }) }
func metrics(op string, next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var ( start = time.Now() rd = &readerDelegator{ReadCloser: r.Body} rc = &responseRecorder{ResponseWriter: w} ) r.Body = rd next.ServeHTTP(rc, r) d := time.Since(start) labels := map[string]string{ "bucket": r.URL.Query().Get(ent.KeyBucket), "method": strings.ToLower(r.Method), "operation": op, "status": strconv.Itoa(rc.status), } requestBytes.With(labels).Add(float64(rd.BytesRead)) requestDurations.With(labels).Observe(float64(d)) responseBytes.With(labels).Add(float64(rc.size)) }) }