diff --git a/pkg/backends/backends_test.go b/pkg/backends/backends_test.go index 387e67eb4..2b69ed2a9 100644 --- a/pkg/backends/backends_test.go +++ b/pkg/backends/backends_test.go @@ -21,12 +21,12 @@ import ( ho "github.com/trickstercache/trickster/v2/pkg/backends/healthcheck/options" bo "github.com/trickstercache/trickster/v2/pkg/backends/options" - "github.com/trickstercache/trickster/v2/pkg/router" + "github.com/trickstercache/trickster/v2/pkg/router/lm" ) func TestBackends(t *testing.T) { - cl, _ := New("test1", bo.New(), nil, router.NewRouter(), nil) + cl, _ := New("test1", bo.New(), nil, lm.NewRouter(), nil) o := Backends{"test1": cl} c := o.Get("test1") @@ -77,11 +77,11 @@ func TestStartHealthChecks(t *testing.T) { // 1: rule / Virtual provider o1 := bo.New() o1.Provider = "rule" - c1, _ := New("test1", o1, nil, router.NewRouter(), nil) + c1, _ := New("test1", o1, nil, lm.NewRouter(), nil) // 2: non-virtual provider with no health check options o2 := bo.New() - c2, _ := New("test2", o2, nil, router.NewRouter(), nil) + c2, _ := New("test2", o2, nil, lm.NewRouter(), nil) b := Backends{"test1": c1} _, err := b.StartHealthChecks(nil) diff --git a/pkg/backends/reverseproxy/routes.go b/pkg/backends/reverseproxy/routes.go index f40eafb05..d611c4332 100644 --- a/pkg/backends/reverseproxy/routes.go +++ b/pkg/backends/reverseproxy/routes.go @@ -48,7 +48,7 @@ func (c *Client) DefaultPathConfigs(o *bo.Options) map[string]*po.Options { "/-" + strings.Join(am, "-"): { Path: "/", HandlerName: "proxy", - Methods: methods.AllHTTPMethods(), + Methods: am, MatchType: matching.PathMatchTypePrefix, MatchTypeName: "prefix", }, diff --git a/pkg/backends/timeseries_backend_test.go b/pkg/backends/timeseries_backend_test.go index 607abf564..81880e6a0 100644 --- a/pkg/backends/timeseries_backend_test.go +++ b/pkg/backends/timeseries_backend_test.go @@ -20,11 +20,11 @@ import ( "testing" bo "github.com/trickstercache/trickster/v2/pkg/backends/options" - "github.com/trickstercache/trickster/v2/pkg/router" + "github.com/trickstercache/trickster/v2/pkg/router/lm" ) func TestNewTimeseriesBackend(t *testing.T) { - tb, _ := NewTimeseriesBackend("test1", bo.New(), nil, router.NewRouter(), nil, nil) + tb, _ := NewTimeseriesBackend("test1", bo.New(), nil, lm.NewRouter(), nil, nil) if tb.Name() != "test1" { t.Error("expected test1 got", tb.Name()) } diff --git a/pkg/config/defaults.go b/pkg/config/defaults.go index f193dcb5a..7db8e111e 100644 --- a/pkg/config/defaults.go +++ b/pkg/config/defaults.go @@ -24,7 +24,7 @@ const ( // DefaultHealthHandlerPath defines the default path for the Health Handler DefaultHealthHandlerPath = "/trickster/health" // DefaultPurgeKeyHandlerPath defines the default path for the Cache Purge (by Key) Handler - DefaultPurgeKeyHandlerPath = "/trickster/purge/key/{backend}/{key}" + DefaultPurgeKeyHandlerPath = "/trickster/purge/key/" // DefaultPurgePathHandlerPath defines the default path for the Cache Purge (by Path) Handler // Requires ?backend={backend}&path={path} DefaultPurgePathHandlerPath = "/trickster/purge/path" diff --git a/pkg/httpserver/httpserver.go b/pkg/httpserver/httpserver.go index de3d995b2..3c66c3931 100644 --- a/pkg/httpserver/httpserver.go +++ b/pkg/httpserver/httpserver.go @@ -41,7 +41,7 @@ import ( "github.com/trickstercache/trickster/v2/pkg/observability/metrics" tr "github.com/trickstercache/trickster/v2/pkg/observability/tracing/registration" "github.com/trickstercache/trickster/v2/pkg/proxy/handlers" - "github.com/trickstercache/trickster/v2/pkg/router" + "github.com/trickstercache/trickster/v2/pkg/router/lm" "github.com/trickstercache/trickster/v2/pkg/routing" ) @@ -130,10 +130,14 @@ func applyConfig(conf, oldConf *config.Config, wg *sync.WaitGroup, logger *tl.Lo } // every config (re)load is a new router - r := router.NewRouter() - mr := http.NewServeMux() + r := lm.NewRouter() + mr := lm.NewRouter() + mr.SetMatchingScheme(0) + + r.RegisterRoute(conf.Main.PingHandlerPath, nil, + []string{http.MethodGet, http.MethodHead}, false, + http.HandlerFunc((handlers.PingHandleFunc(conf)))) - r.HandleFunc(conf.Main.PingHandlerPath, handlers.PingHandleFunc(conf)).Methods(http.MethodGet) var caches = applyCachingConfig(conf, oldConf, logger, oldCaches) rh := handlers.ReloadHandleFunc(Serve, conf, wg, logger, caches, args) @@ -144,7 +148,12 @@ func applyConfig(conf, oldConf *config.Config, wg *sync.WaitGroup, logger *tl.Lo return err } - r.HandleFunc(conf.Main.PurgeKeyHandlerPath, handlers.PurgeKeyHandleFunc(conf, o)).Methods(http.MethodDelete) + if !strings.HasSuffix(conf.Main.PurgeKeyHandlerPath, "/") { + conf.Main.PurgeKeyHandlerPath += "/" + } + r.RegisterRoute(conf.Main.PurgeKeyHandlerPath, nil, + []string{http.MethodDelete}, true, + http.HandlerFunc(handlers.PurgeKeyHandleFunc(conf, o))) if hc != nil { hc.Shutdown() @@ -320,8 +329,9 @@ func validateConfig(conf *config.Config) error { caches[k] = nil } - r := router.NewRouter() - mr := http.NewServeMux() + r := lm.NewRouter() + mr := lm.NewRouter() + mr.SetMatchingScheme(0) logger := tl.ConsoleLogger(conf.Logging.LogLevel) tracers, err := tr.RegisterAll(conf, logger, true) diff --git a/pkg/httpserver/listeners.go b/pkg/httpserver/listeners.go index 89b2f3e7b..9f6887339 100644 --- a/pkg/httpserver/listeners.go +++ b/pkg/httpserver/listeners.go @@ -30,13 +30,15 @@ import ( "github.com/trickstercache/trickster/v2/pkg/proxy/handlers" "github.com/trickstercache/trickster/v2/pkg/proxy/listener" ttls "github.com/trickstercache/trickster/v2/pkg/proxy/tls" + "github.com/trickstercache/trickster/v2/pkg/router" + "github.com/trickstercache/trickster/v2/pkg/router/lm" "github.com/trickstercache/trickster/v2/pkg/routing" ) var lg = listener.NewListenerGroup() func applyListenerConfigs(conf, oldConf *config.Config, - router, reloadHandler http.Handler, metricsRouter *http.ServeMux, + router, reloadHandler http.Handler, metricsRouter router.Router, log *tl.Logger, tracers tracing.Tracers, o backends.Backends, wg *sync.WaitGroup, errorFunc func()) { @@ -137,8 +139,10 @@ func applyListenerConfigs(conf, oldConf *config.Config, (!hasOldMC || (conf.Metrics.ListenAddress != oldConf.Metrics.ListenAddress || conf.Metrics.ListenPort != oldConf.Metrics.ListenPort)) { lg.DrainAndClose("metricsListener", 0) - metricsRouter.Handle("/metrics", metrics.Handler()) - metricsRouter.HandleFunc(conf.Main.ConfigHandlerPath, handlers.ConfigHandleFunc(conf)) + metricsRouter.RegisterRoute("/metrics", []string{""}, + []string{http.MethodGet}, false, metrics.Handler()) + metricsRouter.RegisterRoute(conf.Main.ConfigHandlerPath, []string{""}, + []string{http.MethodGet}, false, http.HandlerFunc(handlers.ConfigHandleFunc(conf))) if conf.Main.PprofServer == "both" || conf.Main.PprofServer == "metrics" { routing.RegisterPprofRoutes("metrics", metricsRouter, log) } @@ -147,12 +151,14 @@ func applyListenerConfigs(conf, oldConf *config.Config, conf.Metrics.ListenAddress, conf.Metrics.ListenPort, conf.Frontend.ConnectionsLimit, nil, metricsRouter, wg, nil, errorFunc, 0, log) } else { - metricsRouter.Handle("/metrics", metrics.Handler()) - metricsRouter.HandleFunc(conf.Main.ConfigHandlerPath, handlers.ConfigHandleFunc(conf)) + metricsRouter.RegisterRoute("/metrics", []string{""}, + []string{http.MethodGet}, false, metrics.Handler()) + metricsRouter.RegisterRoute(conf.Main.ConfigHandlerPath, []string{""}, + []string{http.MethodGet}, false, http.HandlerFunc(handlers.ConfigHandleFunc(conf))) lg.UpdateRouter("metricsListener", metricsRouter) } - rr := http.NewServeMux() // serveMux router for the Reload port + rr := lm.NewRouter() // serveMux router for the Reload port // if the Reload HTTP port is configured, then set up the http listener instance if conf.ReloadConfig != nil && conf.ReloadConfig.ListenPort > 0 && @@ -160,9 +166,13 @@ func applyListenerConfigs(conf, oldConf *config.Config, conf.ReloadConfig.ListenPort != oldConf.ReloadConfig.ListenPort)) { wg.Add(1) lg.DrainAndClose("reloadListener", time.Millisecond*500) - rr.HandleFunc(conf.Main.ConfigHandlerPath, handlers.ConfigHandleFunc(conf)) - rr.Handle(conf.ReloadConfig.HandlerPath, reloadHandler) - rr.HandleFunc(conf.Main.PurgePathHandlerPath, handlers.PurgePathHandlerFunc(conf, &o)) + + rr.RegisterRoute(conf.Main.ConfigHandlerPath, []string{""}, + []string{http.MethodGet}, false, http.HandlerFunc(handlers.ConfigHandleFunc(conf))) + rr.RegisterRoute(conf.ReloadConfig.HandlerPath, []string{""}, + []string{http.MethodGet}, false, reloadHandler) + rr.RegisterRoute(conf.Main.PurgePathHandlerPath, []string{""}, + []string{http.MethodGet}, false, http.HandlerFunc(handlers.PurgePathHandlerFunc(conf, &o))) if conf.Main.PprofServer == "both" || conf.Main.PprofServer == "reload" { routing.RegisterPprofRoutes("reload", rr, log) } @@ -170,9 +180,13 @@ func applyListenerConfigs(conf, oldConf *config.Config, conf.ReloadConfig.ListenAddress, conf.ReloadConfig.ListenPort, conf.Frontend.ConnectionsLimit, nil, rr, wg, nil, errorFunc, 0, log) } else { - rr.HandleFunc(conf.Main.ConfigHandlerPath, handlers.ConfigHandleFunc(conf)) - rr.Handle(conf.ReloadConfig.HandlerPath, reloadHandler) - rr.HandleFunc(conf.Main.PurgePathHandlerPath, handlers.PurgePathHandlerFunc(conf, &o)) + + rr.RegisterRoute(conf.Main.ConfigHandlerPath, []string{""}, + []string{http.MethodGet}, false, http.HandlerFunc(handlers.ConfigHandleFunc(conf))) + rr.RegisterRoute(conf.ReloadConfig.HandlerPath, []string{""}, + []string{http.MethodGet}, false, reloadHandler) + rr.RegisterRoute(conf.Main.PurgePathHandlerPath, []string{""}, + []string{http.MethodGet}, false, http.HandlerFunc(handlers.PurgePathHandlerFunc(conf, &o))) lg.UpdateRouter("reloadListener", rr) } } diff --git a/pkg/proxy/handlers/clickhouse/clickhouse.go b/pkg/proxy/handlers/clickhouse/clickhouse.go index af438c63b..95595ae49 100644 --- a/pkg/proxy/handlers/clickhouse/clickhouse.go +++ b/pkg/proxy/handlers/clickhouse/clickhouse.go @@ -24,7 +24,7 @@ import ( bo "github.com/trickstercache/trickster/v2/pkg/backends/options" co "github.com/trickstercache/trickster/v2/pkg/cache/options" "github.com/trickstercache/trickster/v2/pkg/cache/registration" - "github.com/trickstercache/trickster/v2/pkg/router" + "github.com/trickstercache/trickster/v2/pkg/router/lm" "github.com/trickstercache/trickster/v2/pkg/routing" ) @@ -57,8 +57,8 @@ func NewAcceleratorWithOptions(baseURL string, o *bo.Options, c *co.Options) (ht o.Scheme = u.Scheme o.Host = u.Host o.PathPrefix = u.Path - r := router.NewRouter() - cl, err := clickhouse.NewClient("default", o, router.NewRouter(), cache, nil, nil) + r := lm.NewRouter() + cl, err := clickhouse.NewClient("default", o, lm.NewRouter(), cache, nil, nil) if err != nil { return nil, err } diff --git a/pkg/proxy/handlers/influxdb/influxdb.go b/pkg/proxy/handlers/influxdb/influxdb.go index c79aeace1..94e5d0150 100644 --- a/pkg/proxy/handlers/influxdb/influxdb.go +++ b/pkg/proxy/handlers/influxdb/influxdb.go @@ -24,7 +24,7 @@ import ( bo "github.com/trickstercache/trickster/v2/pkg/backends/options" co "github.com/trickstercache/trickster/v2/pkg/cache/options" "github.com/trickstercache/trickster/v2/pkg/cache/registration" - "github.com/trickstercache/trickster/v2/pkg/router" + "github.com/trickstercache/trickster/v2/pkg/router/lm" "github.com/trickstercache/trickster/v2/pkg/routing" ) @@ -57,8 +57,8 @@ func NewAcceleratorWithOptions(baseURL string, o *bo.Options, c *co.Options) (ht o.Scheme = u.Scheme o.Host = u.Host o.PathPrefix = u.Path - r := router.NewRouter() - cl, err := influxdb.NewClient("default", o, router.NewRouter(), cache, nil, nil) + r := lm.NewRouter() + cl, err := influxdb.NewClient("default", o, lm.NewRouter(), cache, nil, nil) if err != nil { return nil, err } diff --git a/pkg/proxy/handlers/prometheus/prometheus.go b/pkg/proxy/handlers/prometheus/prometheus.go index ac0c70bdc..ce30cdea4 100644 --- a/pkg/proxy/handlers/prometheus/prometheus.go +++ b/pkg/proxy/handlers/prometheus/prometheus.go @@ -24,7 +24,7 @@ import ( "github.com/trickstercache/trickster/v2/pkg/backends/prometheus" co "github.com/trickstercache/trickster/v2/pkg/cache/options" "github.com/trickstercache/trickster/v2/pkg/cache/registration" - "github.com/trickstercache/trickster/v2/pkg/router" + "github.com/trickstercache/trickster/v2/pkg/router/lm" "github.com/trickstercache/trickster/v2/pkg/routing" ) @@ -57,8 +57,8 @@ func NewAcceleratorWithOptions(baseURL string, o *bo.Options, c *co.Options) (ht o.Scheme = u.Scheme o.Host = u.Host o.PathPrefix = u.Path - r := router.NewRouter() - cl, err := prometheus.NewClient("default", o, router.NewRouter(), cache, nil, nil) + r := lm.NewRouter() + cl, err := prometheus.NewClient("default", o, lm.NewRouter(), cache, nil, nil) if err != nil { return nil, err } diff --git a/pkg/proxy/handlers/purge.go b/pkg/proxy/handlers/purge.go index 50fa05921..15491671e 100644 --- a/pkg/proxy/handlers/purge.go +++ b/pkg/proxy/handlers/purge.go @@ -18,6 +18,7 @@ package handlers import ( "net/http" + "strings" "github.com/trickstercache/trickster/v2/pkg/backends" "github.com/trickstercache/trickster/v2/pkg/checksum/md5" @@ -25,14 +26,19 @@ import ( "github.com/trickstercache/trickster/v2/pkg/observability/logging" "github.com/trickstercache/trickster/v2/pkg/proxy/headers" "github.com/trickstercache/trickster/v2/pkg/proxy/request" - "github.com/trickstercache/trickster/v2/pkg/router" ) // PurgeHandleFunc purges an object from a cache based on key. func PurgeKeyHandleFunc(conf *config.Config, from backends.Backends) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, req *http.Request) { - params := router.Vars(req) - purgeFrom, purgeKey := params["backend"], params["key"] + vals := strings.Replace(req.URL.Path, conf.Main.PurgeKeyHandlerPath, "", 1) + parts := strings.Split(vals, "/") + if len(parts) != 2 { + http.NotFound(w, req) + return + } + purgeFrom := parts[0] + purgeKey := parts[1] fromBackend := from.Get(purgeFrom) if fromBackend == nil { w.Header().Set(headers.NameContentType, headers.ValueTextPlain) diff --git a/pkg/proxy/handlers/rpc/rpc.go b/pkg/proxy/handlers/rpc/rpc.go index 2489ac498..13c6bc314 100644 --- a/pkg/proxy/handlers/rpc/rpc.go +++ b/pkg/proxy/handlers/rpc/rpc.go @@ -24,7 +24,7 @@ import ( rpc "github.com/trickstercache/trickster/v2/pkg/backends/reverseproxycache" co "github.com/trickstercache/trickster/v2/pkg/cache/options" "github.com/trickstercache/trickster/v2/pkg/cache/registration" - "github.com/trickstercache/trickster/v2/pkg/router" + "github.com/trickstercache/trickster/v2/pkg/router/lm" "github.com/trickstercache/trickster/v2/pkg/routing" ) @@ -57,7 +57,7 @@ func NewWithOptions(baseURL string, o *bo.Options, c *co.Options) (http.Handler, o.Scheme = u.Scheme o.Host = u.Host o.PathPrefix = u.Path - r := router.NewRouter() + r := lm.NewRouter() cl, err := rpc.NewClient("default", o, r, cache, nil, nil) if err != nil { return nil, err diff --git a/pkg/proxy/headers/headers.go b/pkg/proxy/headers/headers.go index 68595a184..61724efc7 100644 --- a/pkg/proxy/headers/headers.go +++ b/pkg/proxy/headers/headers.go @@ -36,6 +36,8 @@ const ( ValueApplicationFlux = "application/vnd.flux" // ValueChunked represents the HTTP Header Value of "chunked" ValueChunked = "chunked" + // ValueClose represents the HTTP Header Value of "close" + ValueClose = "close" // ValueMaxAge represents the HTTP Header Value of "max-age" ValueMaxAge = "max-age" // ValueMultipartFormData represents the HTTP Header Value of "multipart/form-data" diff --git a/pkg/proxy/listener/listener_test.go b/pkg/proxy/listener/listener_test.go index a3c6e0f93..b935ff591 100644 --- a/pkg/proxy/listener/listener_test.go +++ b/pkg/proxy/listener/listener_test.go @@ -35,7 +35,7 @@ import ( "github.com/trickstercache/trickster/v2/pkg/observability/tracing/exporters/stdout" "github.com/trickstercache/trickster/v2/pkg/proxy/errors" ph "github.com/trickstercache/trickster/v2/pkg/proxy/handlers" - "github.com/trickstercache/trickster/v2/pkg/router" + "github.com/trickstercache/trickster/v2/pkg/router/lm" testutil "github.com/trickstercache/trickster/v2/pkg/testutil" tlstest "github.com/trickstercache/trickster/v2/pkg/testutil/tls" ) @@ -224,7 +224,7 @@ func TestListenerConnectionLimitWorks(t *testing.T) { } go func() { - http.Serve(l, router.NewRouter()) + http.Serve(l, lm.NewRouter()) }() if err != nil { diff --git a/pkg/proxy/paths/options/options.go b/pkg/proxy/paths/options/options.go index e66e0ba1e..8895a62a9 100644 --- a/pkg/proxy/paths/options/options.go +++ b/pkg/proxy/paths/options/options.go @@ -220,7 +220,7 @@ func SetDefaults( p.ReqRewriter = ri } if len(p.Methods) == 0 { - p.Methods = []string{http.MethodGet, http.MethodHead} + p.Methods = []string{http.MethodGet} } p.Custom = make([]string, 0) for _, pm := range pathMembers { @@ -248,7 +248,7 @@ func SetDefaults( p.MatchType = matching.PathMatchTypeExact p.MatchTypeName = p.MatchType.String() } - paths[p.Path+"-"+strings.Join(p.Methods, "-")] = p + paths[p.Path] = p } return nil } diff --git a/pkg/router/lm/lm.go b/pkg/router/lm/lm.go new file mode 100644 index 000000000..e45e8ed99 --- /dev/null +++ b/pkg/router/lm/lm.go @@ -0,0 +1,214 @@ +// package lm represents a simple Longest Match router +package lm + +import ( + "net/http" + "slices" + "sort" + "strings" + + "github.com/trickstercache/trickster/v2/pkg/errors" + "github.com/trickstercache/trickster/v2/pkg/proxy/headers" + "github.com/trickstercache/trickster/v2/pkg/router" +) + +var _ router.Router = &rtr{} + +type rtr struct { + matchScheme router.MatchingScheme + routes router.HostRouteSetLookup +} + +func NewRouter() router.Router { + return &rtr{ + matchScheme: router.DefaultMatchingScheme, + routes: make(router.HostRouteSetLookup), + } +} + +var emptyHost = []string{""} + +func (rt *rtr) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if r.RequestURI == "*" { + if r.ProtoAtLeast(1, 1) { + w.Header().Set(headers.NameConnection, headers.ValueClose) + } + w.WriteHeader(http.StatusBadRequest) + return + } + rt.Handler(r).ServeHTTP(w, r) +} + +func (rt *rtr) RegisterRoute(path string, hosts, methods []string, + isWildcard bool, handler http.Handler) error { + pl := len(path) + if pl == 0 { + return errors.ErrInvalidPath + } + if len(methods) == 0 { + return errors.ErrInvalidMethod + } + if hosts == nil { + hosts = emptyHost + } + for _, h := range hosts { + hrc, ok := rt.routes[h] + if !ok || hrc == nil { + hrc = &router.HostRouteSet{ + ExactMatchRoutes: make(router.RouteLookupLookup), + PrefixMatchRoutes: make(router.PrefixRouteSets, 0, 16), + PrefixMatchRoutesLkp: make(router.PrefixRouteSetLookup), + } + rt.routes[h] = hrc + } + if !isWildcard { + rl, ok := hrc.ExactMatchRoutes[path] + if rl == nil || !ok { + rl = make(router.RouteLookup) + hrc.ExactMatchRoutes[path] = rl + } + for _, m := range methods { + rl[m] = &router.Route{ + ExactMatch: true, + Method: m, + Host: h, + Path: path, + Handler: handler, + } + if m == http.MethodGet { + if _, ok := rl[http.MethodHead]; !ok { + rl[http.MethodHead] = &router.Route{ + ExactMatch: true, + Method: http.MethodHead, + Host: h, + Path: path, + Handler: handler, + } + } + } + } + continue + } + prc, ok := hrc.PrefixMatchRoutesLkp[path] + if prc == nil || !ok { + prc = &router.PrefixRouteSet{ + Path: path, + PathLen: pl, + RoutesByMethod: make(router.RouteLookup), + } + hrc.PrefixMatchRoutesLkp[path] = prc + if len(hrc.PrefixMatchRoutes) == 0 { + hrc.PrefixMatchRoutes = make(router.PrefixRouteSets, 0, 16) + } + hrc.PrefixMatchRoutes = append(hrc.PrefixMatchRoutes, prc) + } + for _, m := range methods { + prc.RoutesByMethod[m] = &router.Route{ + ExactMatch: true, + Method: m, + Host: h, + Path: path, + Handler: handler, + } + if m == http.MethodGet { + if _, ok := prc.RoutesByMethod[http.MethodHead]; !ok { + prc.RoutesByMethod[http.MethodHead] = &router.Route{ + ExactMatch: true, + Method: http.MethodHead, + Host: h, + Path: path, + Handler: handler, + } + } + } + } + } + rt.sort() + return nil +} + +// this sorts the prefix-match paths longest to shorted +func (rt *rtr) sort() { + for _, hrc := range rt.routes { + if len(hrc.PrefixMatchRoutes) == 0 { + continue + } + prs := prefixRouteSets(hrc.PrefixMatchRoutes) + sort.Sort(prs) + slices.Reverse(prs) + hrc.PrefixMatchRoutes = router.PrefixRouteSets(prs) + } +} + +func (rt *rtr) Handler(r *http.Request) http.Handler { + if rt.matchScheme&router.MatchHostname == router.MatchHostname { + host := r.Host + i := strings.Index(host, ":") + if i >= 0 { + host = host[0:i] + } + h := rt.matchByHost(r.Method, host, r.URL.Path) + if h != nil { + return h + } + } + h := rt.matchByHost(r.Method, "", r.URL.Path) + if h != nil { + return h + } + return notFoundHandler +} + +func (rt *rtr) matchByHost(method, host, path string) http.Handler { + if hrc, ok := rt.routes[host]; ok && hrc != nil { + if rs, ok := hrc.ExactMatchRoutes[path]; ok && rs != nil { + r, ok := rs[method] + if !ok || r == nil { + return methodNotAllowedHandler + } + return r.Handler + } + if !(rt.matchScheme&router.MatchPathPrefix == router.MatchPathPrefix) { + return nil + } + lp := len(path) + for _, prc := range hrc.PrefixMatchRoutes { + if prc.PathLen > lp { + continue + } + if strings.HasPrefix(prc.Path, path) { + r, ok := prc.RoutesByMethod[method] + if !ok || r == nil { + return methodNotAllowedHandler + } + return r.Handler + } + } + } + return nil +} + +func (rt *rtr) SetMatchingScheme(s router.MatchingScheme) { + rt.matchScheme = s +} + +func MethodNotAllowed(w http.ResponseWriter, r *http.Request) { + http.Error(w, "405 method not allowed", http.StatusMethodNotAllowed) +} + +var methodNotAllowedHandler = http.HandlerFunc(MethodNotAllowed) +var notFoundHandler = http.HandlerFunc(http.NotFound) + +type prefixRouteSets router.PrefixRouteSets + +func (prs prefixRouteSets) Len() int { + return len(prs) +} + +func (prs prefixRouteSets) Swap(i, j int) { + prs[i], prs[j] = prs[j], prs[i] +} + +func (prs prefixRouteSets) Less(i, j int) bool { + return prs[i].PathLen < prs[j].PathLen +} diff --git a/pkg/routing/routing.go b/pkg/routing/routing.go index 48766aa8f..2cc4044ec 100644 --- a/pkg/routing/routing.go +++ b/pkg/routing/routing.go @@ -21,7 +21,6 @@ import ( "fmt" "net/http" "net/http/pprof" - "sort" "strings" "github.com/trickstercache/trickster/v2/pkg/backends" @@ -43,25 +42,32 @@ import ( po "github.com/trickstercache/trickster/v2/pkg/proxy/paths/options" "github.com/trickstercache/trickster/v2/pkg/proxy/request/rewriter" "github.com/trickstercache/trickster/v2/pkg/router" + "github.com/trickstercache/trickster/v2/pkg/router/lm" "github.com/trickstercache/trickster/v2/pkg/util/middleware" ) // RegisterPprofRoutes will register the Pprof Debugging endpoints to the provided router -func RegisterPprofRoutes(routerName string, h *http.ServeMux, logger interface{}) { +func RegisterPprofRoutes(routerName string, r router.Router, logger interface{}) { tl.Info(logger, "registering pprof /debug routes", tl.Pairs{"routerName": routerName}) - h.HandleFunc("/debug/pprof/", pprof.Index) - h.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) - h.HandleFunc("/debug/pprof/profile", pprof.Profile) - h.HandleFunc("/debug/pprof/symbol", pprof.Symbol) - h.HandleFunc("/debug/pprof/trace", pprof.Trace) + r.RegisterRoute("/debug/pprof/", nil, []string{http.MethodGet}, + false, http.HandlerFunc(pprof.Index)) + r.RegisterRoute("/debug/pprof/cmdline", nil, []string{http.MethodGet}, + false, http.HandlerFunc(pprof.Cmdline)) + r.RegisterRoute("/debug/pprof/profile", nil, []string{http.MethodGet}, + false, http.HandlerFunc(pprof.Profile)) + r.RegisterRoute("/debug/pprof/symbol", nil, []string{http.MethodGet}, + false, http.HandlerFunc(pprof.Symbol)) + r.RegisterRoute("/debug/pprof/trace", nil, []string{http.MethodGet}, + false, http.HandlerFunc(pprof.Trace)) } // RegisterProxyRoutes iterates the Trickster Configuration and // registers the routes for the configured backends -func RegisterProxyRoutes(conf *config.Config, r router.Router, metricsRouter *http.ServeMux, - caches map[string]cache.Cache, tracers tracing.Tracers, - logger interface{}, dryRun bool) (backends.Backends, error) { +func RegisterProxyRoutes(conf *config.Config, r router.Router, + metricsRouter router.Router, caches map[string]cache.Cache, + tracers tracing.Tracers, logger interface{}, + dryRun bool) (backends.Backends, error) { // a fake "top-level" backend representing the main frontend, so rules can route // to it via the clients map @@ -146,13 +152,16 @@ var noCacheBackends = map[string]interface{}{ } // RegisterHealthHandler registers the main health handler -func RegisterHealthHandler(router *http.ServeMux, path string, hc healthcheck.HealthChecker) { - router.Handle(path, health.StatusHandler(hc)) +func RegisterHealthHandler(router router.Router, path string, + hc healthcheck.HealthChecker) { + router.RegisterRoute(path, []string{""}, []string{http.MethodGet}, + false, health.StatusHandler(hc)) } -func registerBackendRoutes(r router.Router, metricsRouter *http.ServeMux, conf *config.Config, k string, - o *bo.Options, clients backends.Backends, caches map[string]cache.Cache, - tracers tracing.Tracers, logger interface{}, dryRun bool) error { +func registerBackendRoutes(r router.Router, metricsRouter router.Router, + conf *config.Config, k string, o *bo.Options, clients backends.Backends, + caches map[string]cache.Cache, tracers tracing.Tracers, logger interface{}, + dryRun bool) error { var client backends.Backend var c cache.Cache @@ -172,7 +181,7 @@ func registerBackendRoutes(r router.Router, metricsRouter *http.ServeMux, conf * cf := registration.SupportedProviders() if f, ok := cf[strings.ToLower(o.Provider)]; ok && f != nil { - client, err = f(k, o, router.NewRouter(), c, clients, cf) + client, err = f(k, o, lm.NewRouter(), c, clients, cf) } if err != nil { return err @@ -196,7 +205,9 @@ func registerBackendRoutes(r router.Router, metricsRouter *http.ServeMux, conf * tl.Pairs{"path": hp, "backendName": o.Name, "upstreamPath": o.HealthCheck.Path, "upstreamVerb": o.HealthCheck.Verb}) - metricsRouter.Handle(hp, http.Handler(middleware.WithResourcesContext(client, o, nil, nil, nil, logger, h))) + metricsRouter.RegisterRoute(hp, []string{""}, + []string{http.MethodGet}, false, + http.Handler(middleware.WithResourcesContext(client, o, nil, nil, nil, logger, h))) } } return nil @@ -207,7 +218,7 @@ func registerBackendRoutes(r router.Router, metricsRouter *http.ServeMux, conf * // the path routes to the appropriate handler from the provided handlers map func RegisterPathRoutes(r router.Router, handlers map[string]http.Handler, client backends.Backend, o *bo.Options, c cache.Cache, - defaultPaths map[string]*po.Options, tracers tracing.Tracers, + paths map[string]*po.Options, tracers tracing.Tracers, healthHandlerPath string, logger interface{}) { if o == nil { @@ -247,35 +258,24 @@ func RegisterPathRoutes(r router.Router, handlers map[string]http.Handler, return h } - // This takes the default paths, named like '/api/v1/query' and morphs the name - // into what the router wants, with methods like '/api/v1/query-0000011001', to help - // route sorting. the bitmap provides unique names multiple path entries of the same - // path but with different methods, without impacting true path sorting - pathsWithVerbs := make(map[string]*po.Options) - for _, p := range defaultPaths { - if len(p.Methods) == 0 { - p.Methods = methods.CacheableHTTPMethods() - } - pathsWithVerbs[p.Path+"-"+fmt.Sprintf("%010b", methods.MethodMask(p.Methods...))] = p - } - - // now we will iterate through the configured paths, and overlay them on those default paths. - // for rule & alb backend providers, only the default paths are used with no overlay or importable config + // now we will iterate through the configured paths, and overlay them on + // those default paths. for rule & alb backend providers, only the default + // paths are used with no overlay or importable config if !backends.IsVirtual(o.Provider) { for k, p := range o.Paths { - if p2, ok := pathsWithVerbs[k]; ok { + if p2, ok := paths[k]; ok { p2.Merge(p) continue } p3 := po.New() p3.Merge(p) - pathsWithVerbs[k] = p3 + paths[k] = p3 } } - plist := make([]string, 0, len(pathsWithVerbs)) - deletes := make([]string, 0, len(pathsWithVerbs)) - for k, p := range pathsWithVerbs { + plist := make([]string, 0, len(paths)) + deletes := make([]string, 0, len(paths)) + for k, p := range paths { if h, ok := handlers[p.HandlerName]; ok && h != nil { p.Handler = h plist = append(plist, k) @@ -286,19 +286,12 @@ func RegisterPathRoutes(r router.Router, handlers map[string]http.Handler, } } for _, p := range deletes { - delete(pathsWithVerbs, p) + delete(paths, p) } - - sort.Sort(ByLen(plist)) - for i := len(plist)/2 - 1; i >= 0; i-- { - opp := len(plist) - 1 - i - plist[i], plist[opp] = plist[opp], plist[i] - } - or := client.Router().(router.Router) for _, v := range plist { - p := pathsWithVerbs[v] + p := paths[v] pathPrefix := "/" + o.Name handledPath := pathPrefix + p.Path @@ -312,42 +305,27 @@ func RegisterPathRoutes(r router.Router, handlers map[string]http.Handler, if p.Methods[0] == "*" { p.Methods = methods.AllHTTPMethods() } - - switch p.MatchType { - case matching.PathMatchTypePrefix: - // Case where we path match by prefix - // Host Header Routing - for _, h := range o.Hosts { - r.PathPrefix(p.Path).Handler(decorate(p)).Methods(p.Methods...).Host(h) - } - if !o.PathRoutingDisabled { - // Path Routing - r.PathPrefix(handledPath).Handler(middleware.StripPathPrefix(pathPrefix, - decorate(p))).Methods(p.Methods...) - } - or.PathPrefix(p.Path).Handler(decorate(p)).Methods(p.Methods...) - default: - // default to exact match - // Host Header Routing - for _, h := range o.Hosts { - r.Handle(p.Path, decorate(p)).Methods(p.Methods...).Host(h) - } - if !o.PathRoutingDisabled { - // Path Routing - r.Handle(handledPath, middleware.StripPathPrefix(pathPrefix, - decorate(p))).Methods(p.Methods...) - } - or.Handle(p.Path, decorate(p)).Methods(p.Methods...) + if len(o.Hosts) > 0 { + r.RegisterRoute(p.Path, o.Hosts, p.Methods, + p.MatchType == matching.PathMatchTypePrefix, decorate(p)) } + if !o.PathRoutingDisabled { + r.RegisterRoute(handledPath, nil, p.Methods, + p.MatchType == matching.PathMatchTypePrefix, + middleware.StripPathPrefix(pathPrefix, decorate(p))) + } + or.RegisterRoute(p.Path, nil, p.Methods, + p.MatchType == matching.PathMatchTypePrefix, + decorate(p)) } } o.Router = or - o.Paths = pathsWithVerbs + o.Paths = paths } // RegisterDefaultBackendRoutes will iterate the Backends and register the default routes -func RegisterDefaultBackendRoutes(router router.Router, bknds backends.Backends, +func RegisterDefaultBackendRoutes(r router.Router, bknds backends.Backends, logger interface{}, tracers tracing.Tracers) { decorate := func(o *bo.Options, po *po.Options, tr *tracing.Tracer, @@ -384,50 +362,23 @@ func RegisterDefaultBackendRoutes(router router.Router, bknds backends.Backends, tl.Info(logger, "registering default backend handler paths", tl.Pairs{"backendName": o.Name}) - // Sort by key length(Path length) to ensure /api/v1/query_range appear before /api/v1 or / path in regex path matching - keylist := make([]string, 0, len(o.Paths)) - for key := range o.Paths { - keylist = append(keylist, key) - } - sort.Sort(ByLen(keylist)) - for i := len(keylist)/2 - 1; i >= 0; i-- { - opp := len(keylist) - 1 - i - keylist[i], keylist[opp] = keylist[opp], keylist[i] - } - - for _, k := range keylist { - var p = o.Paths[k] + for _, p := range o.Paths { if p.Handler != nil && len(p.Methods) > 0 { - tl.Debug(logger, "registering default backend handler paths", - tl.Pairs{"backendName": o.Name, "path": p.Path, "handlerName": p.HandlerName, - "matchType": p.MatchType}) - switch p.MatchType { - case matching.PathMatchTypePrefix: - // Case where we path match by prefix - router.PathPrefix(p.Path).Handler(decorate(o, p, tr, b.Cache(), b)).Methods(p.Methods...) - default: - // default to exact match - router.Handle(p.Path, decorate(o, p, tr, b.Cache(), b)).Methods(p.Methods...) + tl.Debug(logger, + "registering default backend handler paths", + tl.Pairs{"backendName": o.Name, "path": p.Path, + "handlerName": p.HandlerName, + "matchType": p.MatchType}) + + if p.MatchType == matching.PathMatchTypePrefix { + r.RegisterRoute(p.Path, nil, p.Methods, + true, decorate(o, p, tr, b.Cache(), b)) } - router.Handle(p.Path, decorate(o, p, tr, b.Cache(), b)).Methods(p.Methods...) + r.RegisterRoute(p.Path, nil, p.Methods, + false, decorate(o, p, tr, b.Cache(), b)) } } } } } - -// ByLen allows sorting of a string slice by string length -type ByLen []string - -func (a ByLen) Len() int { - return len(a) -} - -func (a ByLen) Less(i, j int) bool { - return len(a[i]) < len(a[j]) -} - -func (a ByLen) Swap(i, j int) { - a[i], a[j] = a[j], a[i] -} diff --git a/pkg/routing/routing_test.go b/pkg/routing/routing_test.go index 71dd56e8b..a5c71c18e 100644 --- a/pkg/routing/routing_test.go +++ b/pkg/routing/routing_test.go @@ -38,24 +38,24 @@ import ( "github.com/trickstercache/trickster/v2/pkg/proxy/methods" "github.com/trickstercache/trickster/v2/pkg/proxy/paths/matching" po "github.com/trickstercache/trickster/v2/pkg/proxy/paths/options" - "github.com/trickstercache/trickster/v2/pkg/router" + "github.com/trickstercache/trickster/v2/pkg/router/lm" testutil "github.com/trickstercache/trickster/v2/pkg/testutil" tlstest "github.com/trickstercache/trickster/v2/pkg/testutil/tls" ) func TestRegisterPprofRoutes(t *testing.T) { - router := http.NewServeMux() + router := lm.NewRouter() log := logging.ConsoleLogger("info") RegisterPprofRoutes("test", router, log) r, _ := http.NewRequest("GET", "http://0/debug/pprof", nil) - _, p := router.Handler(r) - if p != "/debug/pprof/" { - t.Error("expected pprof route path") + h := router.Handler(r) + if h == nil { + t.Error("expected non-nil handler") } } func TestRegisterHealthHandler(t *testing.T) { - router := http.NewServeMux() + router := lm.NewRouter() path := "/test" hc := healthcheck.New() RegisterHealthHandler(router, path, hc) @@ -73,7 +73,7 @@ func TestRegisterProxyRoutes(t *testing.T) { } caches := registration.LoadCachesFromConfig(conf, logging.ConsoleLogger("error")) defer registration.CloseCaches(caches) - proxyClients, err = RegisterProxyRoutes(conf, router.NewRouter(), http.NewServeMux(), caches, nil, log, false) + proxyClients, err = RegisterProxyRoutes(conf, lm.NewRouter(), lm.NewRouter(), caches, nil, log, false) if err != nil { t.Error(err) } @@ -88,7 +88,7 @@ func TestRegisterProxyRoutes(t *testing.T) { o.Hosts = []string{"test", "test2"} registration.LoadCachesFromConfig(conf, logging.ConsoleLogger("error")) - RegisterProxyRoutes(conf, router.NewRouter(), http.NewServeMux(), caches, tr, log, false) + RegisterProxyRoutes(conf, lm.NewRouter(), lm.NewRouter(), caches, tr, log, false) if len(proxyClients) == 0 { t.Errorf("expected %d got %d", 1, 0) @@ -108,34 +108,34 @@ func TestRegisterProxyRoutes(t *testing.T) { conf.Backends["2"] = o2 - router := router.NewRouter() - _, err = RegisterProxyRoutes(conf, router, http.NewServeMux(), caches, tr, log, false) + router := lm.NewRouter() + _, err = RegisterProxyRoutes(conf, router, lm.NewRouter(), caches, tr, log, false) if err == nil { t.Error("Expected error for too many default backends.") } o1.IsDefault = false o1.CacheName = "invalid" - _, err = RegisterProxyRoutes(conf, router, http.NewServeMux(), caches, tr, log, false) + _, err = RegisterProxyRoutes(conf, router, lm.NewRouter(), caches, tr, log, false) if err == nil { t.Errorf("Expected error for invalid cache name") } o1.CacheName = o2.CacheName - _, err = RegisterProxyRoutes(conf, router, http.NewServeMux(), caches, tr, log, false) + _, err = RegisterProxyRoutes(conf, router, lm.NewRouter(), caches, tr, log, false) if err != nil { t.Error(err) } o2.IsDefault = false o2.CacheName = "invalid" - _, err = RegisterProxyRoutes(conf, router, http.NewServeMux(), caches, tr, log, false) + _, err = RegisterProxyRoutes(conf, router, lm.NewRouter(), caches, tr, log, false) if err == nil { t.Errorf("Expected error for invalid cache name") } o2.CacheName = "default" - _, err = RegisterProxyRoutes(conf, router, http.NewServeMux(), caches, tr, log, false) + _, err = RegisterProxyRoutes(conf, router, lm.NewRouter(), caches, tr, log, false) if err != nil { t.Error(err) } @@ -148,9 +148,9 @@ func TestRegisterProxyRoutes(t *testing.T) { conf.Backends["1"] = o1 delete(conf.Backends, "default") - o1.Paths["/-0000000011"].Methods = nil + o1.Paths["/-GET-HEAD"].Methods = nil - _, err = RegisterProxyRoutes(conf, router, http.NewServeMux(), caches, tr, log, false) + _, err = RegisterProxyRoutes(conf, router, lm.NewRouter(), caches, tr, log, false) if err != nil { t.Error(err) } @@ -166,7 +166,7 @@ func TestRegisterProxyRoutesInflux(t *testing.T) { caches := registration.LoadCachesFromConfig(conf, logging.ConsoleLogger("error")) defer registration.CloseCaches(caches) - proxyClients, err := RegisterProxyRoutes(conf, router.NewRouter(), http.NewServeMux(), caches, + proxyClients, err := RegisterProxyRoutes(conf, lm.NewRouter(), lm.NewRouter(), caches, nil, logging.ConsoleLogger("info"), false) if err != nil { t.Error(err) @@ -187,7 +187,7 @@ func TestRegisterProxyRoutesReverseProxy(t *testing.T) { caches := registration.LoadCachesFromConfig(conf, logging.ConsoleLogger("error")) defer registration.CloseCaches(caches) - proxyClients, err := RegisterProxyRoutes(conf, router.NewRouter(), http.NewServeMux(), caches, + proxyClients, err := RegisterProxyRoutes(conf, lm.NewRouter(), lm.NewRouter(), caches, nil, logging.ConsoleLogger("info"), false) if err != nil { t.Error(err) @@ -209,7 +209,7 @@ func TestRegisterProxyRoutesClickHouse(t *testing.T) { caches := registration.LoadCachesFromConfig(conf, logging.ConsoleLogger("error")) defer registration.CloseCaches(caches) - proxyClients, err := RegisterProxyRoutes(conf, router.NewRouter(), http.NewServeMux(), caches, + proxyClients, err := RegisterProxyRoutes(conf, lm.NewRouter(), lm.NewRouter(), caches, nil, logging.ConsoleLogger("info"), false) if err != nil { t.Error(err) @@ -233,7 +233,7 @@ func TestRegisterProxyRoutesALB(t *testing.T) { caches := registration.LoadCachesFromConfig(conf, logging.ConsoleLogger("error")) defer registration.CloseCaches(caches) - proxyClients, err := RegisterProxyRoutes(conf, router.NewRouter(), http.NewServeMux(), caches, + proxyClients, err := RegisterProxyRoutes(conf, lm.NewRouter(), lm.NewRouter(), caches, nil, logging.ConsoleLogger("info"), false) if err != nil { t.Error(err) @@ -255,7 +255,7 @@ func TestRegisterProxyRoutesIRONdb(t *testing.T) { caches := registration.LoadCachesFromConfig(conf, logging.ConsoleLogger("error")) defer registration.CloseCaches(caches) - proxyClients, err := RegisterProxyRoutes(conf, router.NewRouter(), http.NewServeMux(), caches, + proxyClients, err := RegisterProxyRoutes(conf, lm.NewRouter(), lm.NewRouter(), caches, nil, logging.ConsoleLogger("info"), false) if err != nil { t.Error(err) @@ -280,7 +280,7 @@ func TestRegisterProxyRoutesWithReqRewriters(t *testing.T) { caches := registration.LoadCachesFromConfig(conf, logging.ConsoleLogger("error")) defer registration.CloseCaches(caches) - proxyClients, err := RegisterProxyRoutes(conf, router.NewRouter(), http.NewServeMux(), caches, + proxyClients, err := RegisterProxyRoutes(conf, lm.NewRouter(), lm.NewRouter(), caches, nil, logging.ConsoleLogger("info"), false) if err != nil { t.Error(err) @@ -302,7 +302,7 @@ func TestRegisterProxyRoutesMultipleDefaults(t *testing.T) { } caches := registration.LoadCachesFromConfig(conf, logging.ConsoleLogger("error")) defer registration.CloseCaches(caches) - _, err = RegisterProxyRoutes(conf, router.NewRouter(), http.NewServeMux(), caches, + _, err = RegisterProxyRoutes(conf, lm.NewRouter(), lm.NewRouter(), caches, nil, logging.ConsoleLogger("info"), false) if err == nil { t.Errorf("expected error `%s` got nothing", expected1) @@ -346,7 +346,7 @@ func TestRegisterProxyRoutesInvalidCert(t *testing.T) { } caches := registration.LoadCachesFromConfig(conf, logging.ConsoleLogger("error")) defer registration.CloseCaches(caches) - _, err = RegisterProxyRoutes(conf, router.NewRouter(), http.NewServeMux(), caches, + _, err = RegisterProxyRoutes(conf, lm.NewRouter(), lm.NewRouter(), caches, nil, logging.ConsoleLogger("info"), false) if err == nil { t.Errorf("expected error: %s", expected) @@ -376,7 +376,7 @@ func TestRegisterProxyRoutesBadProvider(t *testing.T) { } caches := registration.LoadCachesFromConfig(conf, logging.ConsoleLogger("error")) defer registration.CloseCaches(caches) - _, err = RegisterProxyRoutes(conf, router.NewRouter(), http.NewServeMux(), caches, + _, err = RegisterProxyRoutes(conf, lm.NewRouter(), lm.NewRouter(), caches, nil, logging.ConsoleLogger("info"), false) if err == nil { t.Errorf("expected error `%s` got nothing", expected) @@ -393,7 +393,7 @@ func TestRegisterMultipleBackends(t *testing.T) { } caches := registration.LoadCachesFromConfig(conf, logging.ConsoleLogger("error")) defer registration.CloseCaches(caches) - _, err = RegisterProxyRoutes(conf, router.NewRouter(), http.NewServeMux(), caches, + _, err = RegisterProxyRoutes(conf, lm.NewRouter(), lm.NewRouter(), caches, nil, logging.ConsoleLogger("info"), false) if err != nil { t.Error(err) @@ -408,7 +408,7 @@ func TestRegisterMultipleBackendsPlusDefault(t *testing.T) { } caches := registration.LoadCachesFromConfig(conf, logging.ConsoleLogger("error")) defer registration.CloseCaches(caches) - _, err = RegisterProxyRoutes(conf, router.NewRouter(), http.NewServeMux(), caches, + _, err = RegisterProxyRoutes(conf, lm.NewRouter(), lm.NewRouter(), caches, nil, logging.ConsoleLogger("info"), false) if err != nil { t.Error(err) @@ -429,7 +429,7 @@ func TestRegisterPathRoutes(t *testing.T) { } oo := conf.Backends["default"] - rpc, _ := reverseproxycache.NewClient("test", oo, router.NewRouter(), nil, nil, nil) + rpc, _ := reverseproxycache.NewClient("test", oo, lm.NewRouter(), nil, nil, nil) dpc := rpc.DefaultPathConfigs(oo) dpc["/-GET-HEAD"].Methods = nil @@ -438,7 +438,7 @@ func TestRegisterPathRoutes(t *testing.T) { RegisterPathRoutes(nil, handlers, rpc, oo, nil, dpc, nil, "", logging.ConsoleLogger("INFO")) - router := router.NewRouter() + router := lm.NewRouter() dpc = rpc.DefaultPathConfigs(oo) dpc["/-GET-HEAD"].Methods = []string{"*"} dpc["/-GET-HEAD"].Handler = testHandler @@ -470,7 +470,7 @@ func TestValidateRuleClients(t *testing.T) { o := conf.Backends["default"] o.Provider = "rule" - _, err = RegisterProxyRoutes(conf, router.NewRouter(), http.NewServeMux(), caches, + _, err = RegisterProxyRoutes(conf, lm.NewRouter(), lm.NewRouter(), caches, nil, logging.ConsoleLogger("info"), false) if err == nil { t.Error("expected error") @@ -482,7 +482,7 @@ func TestRegisterDefaultBackendRoutes(t *testing.T) { // successful passing of this test is no panic - r := router.NewRouter() + r := lm.NewRouter() conf := config.NewConfig() oo := conf.Backends["default"] w := httptest.NewRecorder() @@ -497,7 +497,7 @@ func TestRegisterDefaultBackendRoutes(t *testing.T) { oo.TracingConfigName = "testTracer" oo.Paths = map[string]*po.Options{"root": po1} oo.IsDefault = true - rpc, _ := reverseproxycache.NewClient("default", oo, router.NewRouter(), nil, nil, nil) + rpc, _ := reverseproxycache.NewClient("default", oo, lm.NewRouter(), nil, nil, nil) b := backends.Backends{"default": rpc} tr := tracing.Tracers{"testTracer": testutil.NewTestTracer()} @@ -507,7 +507,7 @@ func TestRegisterDefaultBackendRoutes(t *testing.T) { po1.ReqRewriter = ri RegisterDefaultBackendRoutes(r, b, logger, tr) - r = router.NewRouter() + r = lm.NewRouter() po1.MatchType = matching.PathMatchTypeExact RegisterDefaultBackendRoutes(r, b, logger, tr)