func ExampleAddChain() { c := xhandler.Chain{} close := xhandler.CloseHandler cors := cors.Default().Handler timeout := xhandler.TimeoutHandler(2 * time.Second) auth := func(next xhandler.HandlerC) xhandler.HandlerC { return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { if v := ctx.Value("Authorization"); v == nil { http.Error(w, "Not authorized", http.StatusUnauthorized) return } next.ServeHTTPC(ctx, w, r) }) } c.Add(close, cors, timeout) mux := http.NewServeMux() // Use c.Handler to terminate the chain with your final handler mux.Handle("/", c.Handler(xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, req *http.Request) { fmt.Fprintf(w, "Welcome to the home page!") }))) // Create a new chain from an existing one, and add route-specific middleware to it protected := c.With(auth) mux.Handle("/admin", protected.Handler(xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, req *http.Request) { fmt.Fprintf(w, "protected endpoint!") }))) }
func main() { router := xmux.New() router.GET("/unoconv/health", xhandler.HandlerFuncC(healthHandler)) router.POST("/unoconv/:filetype", xhandler.HandlerFuncC(unoconvHandler)) log.Fatal(http.ListenAndServe(":3000", mw.Handler(router))) }
func router(a *server) http.Handler { mux := xmux.New() c := xhandler.Chain{} c.Use(mwLogger) c.Use(mwAuthenticationCheck(a.key)) mux.GET("/sites", c.HandlerCF(xhandler.HandlerFuncC(a.handleAllSites))) mux.GET("/sites/:id", c.HandlerCF(xhandler.HandlerFuncC(a.handleSingleSite))) mux.GET("/torrents", c.HandlerCF(xhandler.HandlerFuncC(a.handleTorrents))) mux.POST("/download/:hash", c.HandlerCF(xhandler.HandlerFuncC(a.handleDownload))) return xhandler.New(context.Background(), mux) }
// Callback handles the oidc/oauth2 callback after a login attempt from the user. // If the idenity provider returned a proof for valid login, the userid is stored in the session. // This includes the model lookup and a possible creation for new users. // The users last login timestamp is updated. func (c *AuthController) Callback(successURL string) xhandler.HandlerC { return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { log.Info("Handler: Callback") user, err := c.Provider.Callback(w, r) if err != nil { log.Printf("Error occurred: %s", err) http.Error(w, "Bad Request", http.StatusBadRequest) return } if user == nil { log.Printf("Error occurred uid is nil") http.Error(w, "Bad Request", http.StatusBadRequest) return } uuid := c.ProviderName + ":" + user["id"] u, err := c.loginUser(uuid, user["name"]) if err != nil { log.Warnf("Could not create new user: %s", err) http.Error(w, "Bad Request", http.StatusBadRequest) return } session := ctx.Value("session").(*sessions.Session) session.Values["user"] = u.ID session.Save(r, w) http.Redirect(w, r, successURL, http.StatusFound) }) }
// Login handles login requests and delegates to the oidc provider. func (c *AuthController) Login() xhandler.HandlerC { return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { log.Info("Handler: Login") c.Provider.NewAuth(w, r) return }) }
func TestNewHandlerWrongAudience(t *testing.T) { c := Config{ Secret: "5d63GMY5fRsBRdB7cDsMoLlNX9vWxNSq", Issuer: "dmiss", Audiences: []string{"aud1", "aud2"}, } h := NewHandler(c) xh := h(xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) })) tok, err := generateToken() if err != nil { t.Fatalf("generateToken() - error encoding claim: %s", err) } fullPath := "/?access_token=" + tok w := httptest.NewRecorder() r, _ := http.NewRequest("GET", fullPath, nil) xh.ServeHTTPC(context.Background(), w, r) if want, got := http.StatusForbidden, w.Code; want != got { t.Errorf("TestNewHandlerWrongAudience http code: want %d got %d", want, got) } }
// ToHandler - Converts function to middleware. func ToHandler(fn func(ctx context.Context, w http.ResponseWriter, r *http.Request, next xhandler.HandlerC)) Handler { return func(next xhandler.HandlerC) xhandler.HandlerC { return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { fn(ctx, w, r, next) }) } }
// HandleFunc regiester a standard http.HandlerFunc 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) HandleFunc(method, path string, handler http.HandlerFunc) { mux.HandleC(method, path, xhandler.HandlerFuncC(func(_ context.Context, w http.ResponseWriter, r *http.Request) { handler(w, r) }), ) }
func TestMuxLookup(t *testing.T) { routed := false wantHandler := xhandler.HandlerFuncC(func(_ context.Context, _ http.ResponseWriter, _ *http.Request) { routed = true }) mux := New() // try empty router first handler, _, tsr := mux.Lookup("GET", "/nope") assert.Nil(t, handler, "Got handle for unregistered pattern: %v", handler) assert.False(t, tsr, "Got wrong TSR recommendation!") // insert route and try again mux.GET("/user/:name", wantHandler) handler, params, tsr := mux.Lookup("GET", "/user/gopher") if assert.NotNil(t, handler) { handler.ServeHTTPC(nil, nil, nil) assert.True(t, routed, "Routing failed!") } assert.Equal(t, newParams("name", "gopher"), params) handler, _, tsr = mux.Lookup("GET", "/user/gopher/") assert.Nil(t, handler, "Got handle for unregistered pattern: %v", handler) assert.True(t, tsr, "Got no TSR recommendation!") handler, _, tsr = mux.Lookup("GET", "/nope") assert.Nil(t, handler, "Got handle for unregistered pattern: %v", handler) assert.False(t, tsr, "Got wrong TSR recommendation!") }
func middlewareByName(opts Options) (Handler, error) { descriptors := Descriptors() sort.Sort(byName(descriptors)) return func(next xhandler.HandlerC) xhandler.HandlerC { return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { name, err := opts.String(ctx, optMiddlewareName) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } reskey, _ := opts.String(ctx, optMiddlewareDestination) for _, desc := range descriptors { if desc.Name == name { ctx = components.WithTemplateKey(ctx, reskey, desc) break } } next.ServeHTTPC(ctx, w, r) }) }, nil }
func NewHandler(c Config) func(xhandler.HandlerC) xhandler.HandlerC { return func(next xhandler.HandlerC) xhandler.HandlerC { return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { var auth bool // Skip verification of path is in skip list. for _, skipPath := range c.Skip { if r.URL.Path == skipPath { auth = true break } } if !auth && c.Secret != "" { // Check token credentials. auth = checkToken(c, r) } // Check basic auth if no authorization based on token. if !auth && c.BasicUser != "" && c.BasicPass != "" { auth = checkBasicAuth(c, w, r) } if auth { next.ServeHTTPC(ctx, w, r) } else { http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden) } }) } }
func ExampleNewHandler() { c := xhandler.Chain{} // Install the metric handler with dogstatsd backend client and some env tags flushInterval := 5 * time.Second tags := []string{"role:my-service"} statsdWriter, err := net.Dial("udp", "127.0.0.1:8126") if err != nil { log.Fatal(err) } c.UseC(xstats.NewHandler(dogstatsd.New(statsdWriter, flushInterval), tags)) // Here is your handler h := c.Handler(xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { // Get the xstats request's instance from the context. You can safely assume it will // be always there, if the handler is removed, xstats.FromContext will return a nop // instance. m := xstats.FromContext(ctx) // Count something m.Count("requests", 1, "route:index") })) http.Handle("/", h) if err := http.ListenAndServe(":8080", nil); err != nil { log.Fatal(err) } }
func TestMuxPanicHandler(t *testing.T) { mux := New() panicHandled := false mux.PanicHandler = func(ctx context.Context, w http.ResponseWriter, r *http.Request, p interface{}) { panicHandled = true } mux.HandleC("PUT", "/user/:name", xhandler.HandlerFuncC(func(_ context.Context, _ http.ResponseWriter, _ *http.Request) { panic("oops!") })) w := new(mockResponseWriter) req, _ := http.NewRequest("PUT", "/user/gopher", nil) defer func() { if rcv := recover(); rcv != nil { t.Fatal("handling panic failed") } }() mux.ServeHTTPC(context.Background(), w, req) assert.True(t, panicHandled, "simulating failed") }
// MethodHandler returns a handler setting the request's method as a field // to the current context's logger using the passed name as field name. func MethodHandler(name string) func(next xhandler.HandlerC) xhandler.HandlerC { return func(next xhandler.HandlerC) xhandler.HandlerC { return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { FromContext(ctx).SetField(name, r.Method) next.ServeHTTPC(ctx, w, r) }) } }
// JSONWrapper sets the content-type of the response to json. func JSONWrapper() func(next xhandler.HandlerC) xhandler.HandlerC { return func(next xhandler.HandlerC) xhandler.HandlerC { return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/vnd.api+json") next.ServeHTTPC(ctx, w, r) }) } }
func main() { c := xhandler.Chain{} c.Use(recoverMiddleware) c.Use(normalLoggingMiddleware) c.Use(log15LoggingMiddleware) c.Use(logrusLoggingMiddleware) simpleHandler := xhandler.HandlerFuncC(simple) accountHandler := xhandler.HandlerFuncC(account) noteHandler := xhandler.HandlerFuncC(note) mux := bone.New() mux.Get("/account/:id", c.Handler(accountHandler)) mux.Get("/note/:id", c.Handler(noteHandler)) mux.Get("/simple", c.Handler(simpleHandler)) http.ListenAndServe(":8080", mux) }
func ExampleMux_NewGroup() { mux := xmux.New() api := mux.NewGroup("/api") api.GET("/users/:name", xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "GET /api/users/%s", xmux.Param(ctx, "name")) })) api.POST("/users/:name", xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "POST /api/users/%s", xmux.Param(ctx, "name")) })) if err := http.ListenAndServe(":8080", xhandler.New(context.Background(), mux)); err != nil { log.Fatal(err) } }
func serveFiles(path string, prefix string) xhandler.HandlerC { fileserver := http.FileServer(http.Dir(path)) handler := http.StripPrefix(prefix, fileserver) return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { log.Infof("Serving: %s", r.RequestURI) handler.ServeHTTP(w, r) }) }
func routeTracing(route Route, handler xhandler.HandlerC) xhandler.HandlerC { rs := route.String() return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { tr := trace.New(rs, fmt.Sprintf("%s %s", r.Method, r.URL.Path)) ctx = trace.NewContext(ctx, tr) handler.ServeHTTPC(ctx, w, r) tr.Finish() }) }
// UserAgentHandler returns a handler setting the request's client's user-agent as // a field to the current context's logger using the passed name as field name. func UserAgentHandler(name string) func(next xhandler.HandlerC) xhandler.HandlerC { return func(next xhandler.HandlerC) xhandler.HandlerC { return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { if ua := r.Header.Get("User-Agent"); ua != "" { FromContext(ctx).SetField(name, ua) } next.ServeHTTPC(ctx, w, r) }) } }
// RemoteAddrHandler returns a handler setting the request's remote address as a field // to the current context's logger using the passed name as field name. func RemoteAddrHandler(name string) func(next xhandler.HandlerC) xhandler.HandlerC { return func(next xhandler.HandlerC) xhandler.HandlerC { return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { if host, _, err := net.SplitHostPort(r.RemoteAddr); err == nil { FromContext(ctx).SetField(name, host) } next.ServeHTTPC(ctx, w, r) }) } }
// Logout handles logout requests and invalidates the users session. func (c *AuthController) Logout(loginURL string) xhandler.HandlerC { return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { log.Info("Handler: Logout") session := ctx.Value("session").(*sessions.Session) delete(session.Values, "user") session.Save(r, w) http.Redirect(w, r, loginURL, http.StatusFound) }) }
func TestRouteGroupAPI(t *testing.T) { var get, head, options, post, put, patch, delete bool mux := New() group := mux.NewGroup("/foo") // creates /foo group group.GET("/GET", xhandler.HandlerFuncC(func(_ context.Context, _ http.ResponseWriter, _ *http.Request) { get = true })) group.HEAD("/GET", xhandler.HandlerFuncC(func(_ context.Context, _ http.ResponseWriter, _ *http.Request) { head = true })) group.OPTIONS("/GET", xhandler.HandlerFuncC(func(_ context.Context, _ http.ResponseWriter, _ *http.Request) { options = true })) group.POST("/POST", xhandler.HandlerFuncC(func(_ context.Context, _ http.ResponseWriter, _ *http.Request) { post = true })) group.PUT("/PUT", xhandler.HandlerFuncC(func(_ context.Context, _ http.ResponseWriter, _ *http.Request) { put = true })) group.PATCH("/PATCH", xhandler.HandlerFuncC(func(_ context.Context, _ http.ResponseWriter, _ *http.Request) { patch = true })) group.DELETE("/DELETE", xhandler.HandlerFuncC(func(_ context.Context, _ http.ResponseWriter, _ *http.Request) { delete = true })) w := new(mockResponseWriter) r, _ := http.NewRequest("GET", "/foo/GET", nil) mux.ServeHTTPC(context.Background(), w, r) assert.True(t, get, "routing /foo/GET failed") r, _ = http.NewRequest("HEAD", "/foo/GET", nil) mux.ServeHTTPC(context.Background(), w, r) assert.True(t, head, "routing /foo/GET failed") r, _ = http.NewRequest("OPTIONS", "/foo/GET", nil) mux.ServeHTTPC(context.Background(), w, r) assert.True(t, options, "routing /foo/GET failed") r, _ = http.NewRequest("POST", "/foo/POST", nil) mux.ServeHTTPC(context.Background(), w, r) assert.True(t, post, "routing /foo/POST failed") r, _ = http.NewRequest("PUT", "/foo/PUT", nil) mux.ServeHTTPC(context.Background(), w, r) assert.True(t, put, "routing /foo/PUT failed") r, _ = http.NewRequest("PATCH", "/foo/PATCH", nil) mux.ServeHTTPC(context.Background(), w, r) assert.True(t, patch, "routing /foo/PATCH failed") r, _ = http.NewRequest("DELETE", "/foo/DELETE", nil) mux.ServeHTTPC(context.Background(), w, r) assert.True(t, delete, "routing /foo/DELETE failed") }
// tracingMiddleware - Tracing for middlewares. func tracingMiddleware(md *middlewares.Middleware, handler middlewares.Handler) middlewares.Handler { return func(next xhandler.HandlerC) xhandler.HandlerC { h := handler(next) return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { tr, _ := trace.FromContext(ctx) tr.LazyPrintf("%s", md.Name) h.ServeHTTPC(ctx, w, r) }) } }
// RefererHandler returns a handler setting the request's referer header as // a field to the current context's logger using the passed name as field name. func RefererHandler(name string) func(next xhandler.HandlerC) xhandler.HandlerC { return func(next xhandler.HandlerC) xhandler.HandlerC { return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { if ref := r.Header.Get("Referer"); ref != "" { FromContext(ctx).SetField(name, ref) } next.ServeHTTPC(ctx, w, r) }) } }
func TestURLHandler(t *testing.T) { r := &http.Request{ URL: &url.URL{Path: "/path", RawQuery: "foo=bar"}, } h := URLHandler("url")(xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { l := FromContext(ctx).(*logger) assert.Equal(t, F{"url": "/path?foo=bar"}, F(l.fields)) })) h = NewHandler(Config{})(h) h.ServeHTTPC(context.Background(), nil, r) }
func TestMethodHandler(t *testing.T) { r := &http.Request{ Method: "POST", } h := MethodHandler("method")(xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { l := FromContext(ctx).(*logger) assert.Equal(t, F{"method": "POST"}, F(l.fields)) })) h = NewHandler(Config{})(h) h.ServeHTTPC(context.Background(), nil, r) }
func TestRemoteAddrHandlerIPv6(t *testing.T) { r := &http.Request{ RemoteAddr: "[2001:db8:a0b:12f0::1]:1234", } h := RemoteAddrHandler("ip")(xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { l := FromContext(ctx).(*logger) assert.Equal(t, F{"ip": "2001:db8:a0b:12f0::1"}, F(l.fields)) })) h = NewHandler(Config{})(h) h.ServeHTTPC(context.Background(), nil, r) }
func TestHandler(t *testing.T) { s := &fakeSender{} n := xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { xs, ok := FromContext(ctx).(*xstats) assert.True(t, ok) assert.Equal(t, s, xs.s) assert.Equal(t, []string{"envtag"}, xs.tags) }) h := NewHandler(s, []string{"envtag"})(n) h.ServeHTTPC(context.Background(), nil, nil) }
// CompileInContext - Compiles component from context. // Stores result in context to be retrieved with `components.FromContext`. func CompileInContext(next xhandler.HandlerC) xhandler.HandlerC { return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { compiled, err := compiler.Compile(ctx) if err != nil { helpers.WriteError(w, r, http.StatusExpectationFailed, fmt.Sprintf("compile error: %v", err)) return } ctx = components.NewCompiledContext(ctx, compiled) next.ServeHTTPC(ctx, w, r) }) }