// Handle takes the next handler as an argument and wraps it in this middleware. func (m *Middle) Handle(next httpware.Handler) httpware.Handler { return httpware.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error { q := r.URL.Query() s := q.Get(m.startQuery) l := q.Get(m.limitQuery) page := Page{} var err error if s == "" { page.Start = 0 } else { page.Start, err = strconv.Atoi(s) if err != nil { return httpware.NewErr("invalid query parameter", http.StatusBadRequest).WithField(m.startQuery, "must be an integer") } if page.Start < 0 { return httpware.NewErr("invalid query parameter", http.StatusBadRequest).WithField(m.startQuery, "must not be negative") } } if l == "" { page.Limit = m.limitDefault } else { page.Limit, err = strconv.Atoi(l) if err != nil { return httpware.NewErr("invalid query parameter", http.StatusBadRequest).WithField(m.limitQuery, "must not be an integer") } if page.Limit <= 0 { return httpware.NewErr("invalid query parameter", http.StatusBadRequest).WithField(m.limitQuery, "must not be greater than zero") } } return next.ServeHTTPCtx(context.WithValue(ctx, httpware.PageKey, page), w, r) }) }
// Handle takes the next handler as an argument and wraps it in this middleware. func (m *Middle) Handle(next httpware.Handler) httpware.Handler { return httpware.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error { ctx = context.WithValue(ctx, httpware.RequestContentTypeKey, GetContentMatch(r.Header.Get("Content-Type"))) ct := GetContentMatch(r.Header.Get("Accept")) ctx = context.WithValue(ctx, httpware.ResponseContentTypeKey, ct) w.Header().Set("Content-Type", ct.Value) return next.ServeHTTPCtx(ctx, w, r) }) }
// Handle takes the next handler as an argument and wraps it in this middleware. func (m *Middle) Handle(next httpware.Handler) httpware.Handler { return httpware.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error { w.Header().Set("Access-Control-Allow-Origin", m.allowOrigin) w.Header().Set("Access-Control-Allow-Credentials", m.allowCredentials) if m.shouldExposeHeaders { w.Header().Set("Access-Control-Expose-Headers", m.exposeHeaders) } return next.ServeHTTPCtx(ctx, w, r) }) }
func TestResponse(t *testing.T) { c := httpware.Compose( httpware.DefaultErrHandler, New(Defaults), ) s := httptest.NewServer( c.Then( httpware.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error { ct := ResponseTypeFromCtx(ctx) switch r.URL.Path { case "/test-json": if ct.Key != httpware.JSON { t.Fatal("expected json type") } return nil case "/test-xml": if ct.Key != httpware.XML { t.Fatal("expected xml type") } return nil } t.Fatal("this point should never have been reached") return nil }), ), ) hc := http.Client{} req, err := http.NewRequest("GET", s.URL+"/test-json", nil) if err != nil { t.Fatal(err) } req.Header.Set("Accept", "application/json") _, err = hc.Do(req) if err != nil { t.Fatal(err) } req, err = http.NewRequest("GET", s.URL+"/test-xml", nil) if err != nil { t.Fatal(err) } req.Header.Set("Accept", "application/xml") _, err = hc.Do(req) if err != nil { t.Fatal(err) } }
// Handle takes the next handler as an argument and wraps it in this middleware. func (m *Middle) Handle(next httpware.Handler) httpware.Handler { return httpware.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error { remote := strings.Split(r.RemoteAddr, ":") if len(remote) != 2 { return next.ServeHTTPCtx(ctx, w, r) } if m.increment(remote[0]) { defer m.decrement(remote[0]) return next.ServeHTTPCtx(ctx, w, r) } // Send a 429 response (Too Many Requests). m.retryHeader(w) return httpware.NewErr("exceeded request rate limit", 429) }) }
// Handle takes the next handler as an argument and wraps it in this middleware. func (m *Middle) Handle(next httpware.Handler) httpware.Handler { return httpware.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error { token, err := request.ParseFromRequest( r, request.AuthorizationHeaderExtractor, func(token *jwt.Token) (interface{}, error) { return m.conf.Secret, nil }, ) if err == nil && token.Valid { newCtx := context.WithValue(ctx, httpware.TokenKey, token) return next.ServeHTTPCtx(newCtx, w, r) } // No soup for you. return httpware.NewErr("invalid token", http.StatusUnauthorized) }) }
// Handle takes the next handler as an argument and wraps it in this middleware. func (m *Middle) Handle(next httpware.Handler) httpware.Handler { return httpware.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error { // Log panics. defer func() { if rcv := recover(); rcv != nil { m.conf.Logger.WithField("error", rcv).Error("handler panic detected") // Pass on the panic. panic(rcv) } }() // Always log the method and path. entry := m.conf.Logger.WithFields(logrus.Fields{ "method": r.Method, "path": r.URL.Path, }) // Conditional logging... if m.conf.Referer { entry = entry.WithField("referrer", r.Referer()) } if m.conf.RemoteAddr { entry = entry.WithField("remoteAddr", r.RemoteAddr) } for _, h := range m.conf.Headers { entry = entry.WithField(h, r.Header.Get(h)) } if m.conf.Start { entry.Info("new request") } // Call downstream handlers. err := next.ServeHTTPCtx(ctx, w, r) if m.conf.End { // Add any errors to the log entry. statusCode := 0 if err != nil { if httpErr, ok := err.(httpware.Err); ok { entry = entry.WithFields(logrus.Fields{ "statusCode": httpErr.StatusCode, "message": httpErr.Message, }) entry = entry.WithFields(httpErr.Fields) statusCode = httpErr.StatusCode } else { entry = entry.WithField("error", map[string]interface{}{ "statusCode": http.StatusInternalServerError, "message": err, }, ) statusCode = http.StatusInternalServerError } } // Log with the right level and pass on the error. if statusCode >= 500 { entry.Error("request resulted in server error") } else { if statusCode >= 400 { if !m.conf.Ignore4XX { entry.Info("request resulted in client error") } } else if !m.conf.IgnoreUnder400 { entry.Info("request successful") } } } return err }) }