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 := &registerParams{}
    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  }