github.com/grafana/pyroscope@v1.18.0/pkg/api/register_options.go (about) 1 package api 2 3 import ( 4 "net/http" 5 "strings" 6 7 "github.com/go-kit/log" 8 "github.com/go-kit/log/level" 9 "github.com/gorilla/mux" 10 "github.com/grafana/dskit/middleware" 11 12 "github.com/grafana/pyroscope/pkg/util/body" 13 "github.com/grafana/pyroscope/pkg/util/delayhandler" 14 "github.com/grafana/pyroscope/pkg/util/gziphandler" 15 "github.com/grafana/pyroscope/pkg/validation" 16 ) 17 18 type registerMiddleware struct { 19 middleware.Interface 20 name string 21 } 22 23 type registerParams struct { 24 methods []string 25 middlewares []registerMiddleware 26 isPrefix bool 27 } 28 29 func (r *registerParams) logFields(path string) []interface{} { 30 gzip := false 31 auth := false 32 for _, m := range r.middlewares { 33 if m.name == "gzip" { 34 gzip = true 35 } 36 if m.name == "auth" { 37 auth = true 38 } 39 } 40 methods := strings.Join(r.methods, ",") 41 if len(r.methods) == 0 { 42 methods = "all" 43 } 44 45 pathField := "path" 46 if r.isPrefix { 47 pathField = "prefix" 48 } 49 50 return []interface{}{ 51 "methods", methods, 52 pathField, path, 53 "auth", auth, 54 "gzip", gzip, 55 } 56 } 57 58 type RegisterOption func(*registerParams) 59 60 func applyRegisterOptions(opts ...RegisterOption) *registerParams { 61 result := ®isterParams{} 62 for _, opt := range opts { 63 opt(result) 64 } 65 return result 66 } 67 68 func WithMethod(method string) RegisterOption { 69 return func(r *registerParams) { 70 r.methods = append(r.methods, method) 71 } 72 } 73 74 func WithPrefix() RegisterOption { 75 return func(r *registerParams) { 76 r.isPrefix = true 77 } 78 } 79 80 func (a *API) WithAuthMiddleware() RegisterOption { 81 return func(r *registerParams) { 82 r.middlewares = append(r.middlewares, registerMiddleware{a.httpAuthMiddleware, "auth"}) 83 } 84 } 85 86 func WithGzipMiddleware() RegisterOption { 87 return func(r *registerParams) { 88 r.middlewares = append(r.middlewares, registerMiddleware{middleware.Func(gziphandler.GzipHandler), "gzip"}) 89 } 90 } 91 92 func (a *API) WithArtificialDelayMiddleware(limits delayhandler.Limits) RegisterOption { 93 return func(r *registerParams) { 94 r.middlewares = append(r.middlewares, registerMiddleware{middleware.Func(delayhandler.NewHTTP(limits)), "artificial_delay"}) 95 } 96 } 97 98 func (a *API) WithBodySizeLimitMiddleware(limits body.Limits) RegisterOption { 99 return func(r *registerParams) { 100 r.middlewares = append(r.middlewares, registerMiddleware{middleware.Func(body.NewSizeLimitHandler(limits)), "body_size_limit"}) 101 } 102 } 103 104 func (a *API) registerOptionsTenantPath() []RegisterOption { 105 return []RegisterOption{ 106 a.WithAuthMiddleware(), 107 WithGzipMiddleware(), 108 WithMethod("GET"), 109 } 110 } 111 112 func (a *API) registerOptionsReadPath() []RegisterOption { 113 return a.registerOptionsTenantPath() 114 } 115 116 func (a *API) registerOptionsWritePath(limits *validation.Overrides) []RegisterOption { 117 return []RegisterOption{ 118 a.WithAuthMiddleware(), 119 a.WithArtificialDelayMiddleware(limits), // This middleware relies on the auth middleware, to determine the user's override 120 a.WithBodySizeLimitMiddleware(limits), 121 WithGzipMiddleware(), 122 WithMethod("POST"), 123 } 124 } 125 126 func (a *API) registerOptionsPublicAccess() []RegisterOption { 127 return []RegisterOption{ 128 WithGzipMiddleware(), 129 WithMethod("GET"), 130 } 131 } 132 133 func (a *API) registerOptionsPrefixPublicAccess() []RegisterOption { 134 return []RegisterOption{ 135 WithGzipMiddleware(), 136 WithMethod("GET"), 137 WithPrefix(), 138 } 139 } 140 141 func (a *API) registerOptionsRingPage() []RegisterOption { 142 return []RegisterOption{ 143 WithGzipMiddleware(), 144 WithMethod("GET"), 145 WithMethod("POST"), 146 } 147 } 148 149 func registerRoute(logger log.Logger, mux *mux.Router, path string, handler http.Handler, registerOpts ...RegisterOption) { 150 opts := applyRegisterOptions(registerOpts...) 151 152 level.Debug(logger).Log(append([]interface{}{ 153 "msg", "api: registering route"}, opts.logFields(path)...)...) 154 155 // handle path prefixing 156 route := mux.Path(path) 157 if opts.isPrefix { 158 route = mux.PathPrefix(path) 159 } 160 161 // limit the route to the given methods 162 if len(opts.methods) > 0 { 163 route = route.Methods(opts.methods...) 164 } 165 166 // registering the middlewares in reverse order (similar like middleware.Merge) 167 for idx := range opts.middlewares { 168 mw := opts.middlewares[len(opts.middlewares)-idx-1] 169 handler = mw.Wrap(handler) 170 } 171 172 route.Handler(handler) 173 }