feat: middleware bypass overlay (#221)

* **New Features**
  * Routes can promote route-local bypass rules into matching entrypoint middleware, layering route-specific bypasses onto existing entrypoint rules and avoiding duplicate evaluation.

* **Behavior Changes**
  * Entrypoint middleware updates now refresh per-route overlays at runtime; overlay compilation failures result in HTTP 500 (errors are not exposed verbatim).
  * Route middleware accessors now return safe clones.

* **Documentation**
  * Clarified promotion, consumption, merging and qualification semantics with examples.

* **Tests**
  * Added tests covering promotion, cache invalidation, consumption semantics, and error handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Yuzerion
2026-04-15 18:35:06 +08:00
committed by GitHub
parent 31eea0a885
commit 44298d1933
18 changed files with 1000 additions and 7 deletions

View File

@@ -11,6 +11,7 @@ This package implements a flexible HTTP middleware system for GoDoxy. Middleware
- **Middleware Chaining**: Compose multiple middleware in priority order
- **YAML Composition**: Define middleware chains in configuration files
- **Bypass Rules**: Skip middleware based on request properties
- **Entrypoint Overlay Promotion**: Promote route-local middleware entries with `bypass` into matching entrypoint middleware for HTTP routes
- **Dynamic Loading**: Load middleware definitions from files at runtime
Response body rewriting is only applied to unencoded, text-like content types (for example `text/*`, JSON, YAML, XML). Response status and headers can always be modified.
@@ -140,6 +141,42 @@ type Bypass []rules.RuleOn
func (b Bypass) ShouldBypass(w http.ResponseWriter, r *http.Request) bool
```
For HTTP routes, any route-local middleware entry that sets `bypass` and matches an existing entrypoint middleware name contributes an overlay: its bypass rules are promoted into the effective entrypoint middleware for that route.
Semantics:
- route-local middleware entries may be promoted when they include `bypass`; only the bypass portion is promoted in v1
- promoted rules are qualified as `route <alias> & <rule>`
- existing entrypoint bypass rules are preserved and the route rules are appended
- if the route-local middleware entry is **bypass-only**, it is consumed so the same middleware is not evaluated twice
- if the route-local middleware entry contains additional options, only the bypass portion is consumed; the rest of the route-local middleware still executes normally
- if no matching entrypoint middleware exists, route-local middleware behavior is unchanged
Example:
```yaml
entrypoint:
middlewares:
- use: oidc
routes:
app:
middlewares:
oidc:
bypass:
- path glob("/public/*")
```
Effective behavior for route `app` is equivalent to:
```yaml
entrypoint:
middlewares:
- use: oidc
bypass:
- route app & path glob("/public/*")
```
## Available Middleware
| Name | Type | Description |
@@ -247,6 +284,8 @@ if err != nil {
}
```
`PatchReverseProxy` still handles route-local middleware in the normal way. Entrypoint overlay promotion happens earlier, at entrypoint request dispatch time, where the server has both the resolved route and the raw entrypoint middleware definitions available.
### Bypass Rules
```go

View File

@@ -82,6 +82,9 @@ func (c *checkBypass) shouldModReqBypass(w http.ResponseWriter, r *http.Request)
return true
}
}
if isRouteBypassPromoted(r, c.name) {
return false
}
return c.bypass.ShouldBypass(w, r)
}
@@ -99,6 +102,9 @@ func (c *checkBypass) shouldModResBypass(resp *http.Response) bool {
return true
}
}
if isRouteBypassPromoted(resp.Request, c.name) {
return false
}
return c.bypass.ShouldBypass(httputils.ResponseAsRW(resp), resp.Request)
}
@@ -106,6 +112,9 @@ func (c *checkBypass) shouldModResBypass(resp *http.Response) bool {
//
// Returns true if the request is not done, false otherwise.
func (c *checkBypass) before(w http.ResponseWriter, r *http.Request) (proceedNext bool) {
if isRouteMiddlewareConsumed(r, c.name) {
return true
}
if c.modReq == nil || c.shouldModReqBypass(w, r) {
return true
}
@@ -115,6 +124,9 @@ func (c *checkBypass) before(w http.ResponseWriter, r *http.Request) (proceedNex
// modifyResponse modifies the response if the response should be modified.
func (c *checkBypass) modifyResponse(resp *http.Response) error {
if isRouteMiddlewareConsumed(resp.Request, c.name) {
return nil
}
if c.modRes == nil || c.shouldModResBypass(resp) {
return nil
}

View File

@@ -10,10 +10,13 @@ import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/yusing/godoxy/internal/entrypoint"
. "github.com/yusing/godoxy/internal/net/gphttp/middleware"
"github.com/yusing/godoxy/internal/route"
routeTypes "github.com/yusing/godoxy/internal/route/types"
"github.com/yusing/godoxy/internal/types"
"github.com/yusing/goutils/http/reverseproxy"
expect "github.com/yusing/goutils/testing"
)
@@ -266,3 +269,150 @@ func TestEntrypointBypassRoute(t *testing.T) {
expect.Equal(t, recorder.Body.String(), "test")
expect.Equal(t, recorder.Header().Get("Test-Header"), "test-value")
}
func TestEntrypointPromotesRouteBypassOverlay(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("test"))
}))
defer srv.Close()
targetURL, err := url.Parse(srv.URL)
require.NoError(t, err)
host, port, err := net.SplitHostPort(targetURL.Host)
require.NoError(t, err)
portInt, err := strconv.Atoi(port)
require.NoError(t, err)
entry := entrypoint.NewTestEntrypoint(t, nil)
_, err = route.NewStartedTestRoute(t, &route.Route{
Alias: "test-route",
Scheme: routeTypes.SchemeHTTP,
Host: host,
Port: routeTypes.Port{
Listening: 1000,
Proxy: portInt,
},
Middlewares: map[string]types.LabelMap{
"redirectHTTP": {
"bypass": `
- path glob(/public/*)
`[1:],
},
},
})
require.NoError(t, err)
err = entry.SetMiddlewares([]map[string]any{
{
"use": "redirectHTTP",
"bypass": []string{"path /health"},
},
})
require.NoError(t, err)
server, ok := entry.GetServer(":1000")
require.True(t, ok, "server not found")
tests := []struct {
name string
path string
expectStatus int
expectBody string
expectLoc string
}{
{
name: "existing_entrypoint_bypass_still_applies",
path: "/health",
expectStatus: http.StatusOK,
expectBody: "test",
},
{
name: "route_bypass_is_promoted_to_entrypoint",
path: "/public/index.html",
expectStatus: http.StatusOK,
expectBody: "test",
},
{
name: "non_matching_path_still_redirects",
path: "/private",
expectStatus: http.StatusPermanentRedirect,
expectLoc: "https://test-route.example.com/private",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
recorder := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "http://test-route.example.com"+test.path, nil)
server.ServeHTTP(recorder, req)
assert.Equal(t, test.expectStatus, recorder.Code)
if test.expectBody != "" {
assert.Equal(t, test.expectBody, recorder.Body.String())
}
assert.Equal(t, test.expectLoc, recorder.Header().Get("Location"))
})
}
}
func TestRouteBypassWithoutMatchingEntrypointMiddlewareKeepsCurrentBehavior(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("test"))
}))
defer srv.Close()
targetURL, err := url.Parse(srv.URL)
require.NoError(t, err)
host, port, err := net.SplitHostPort(targetURL.Host)
require.NoError(t, err)
portInt, err := strconv.Atoi(port)
require.NoError(t, err)
entry := entrypoint.NewTestEntrypoint(t, nil)
_, err = route.NewStartedTestRoute(t, &route.Route{
Alias: "test-route",
Scheme: routeTypes.SchemeHTTP,
Host: host,
Port: routeTypes.Port{
Listening: 1000,
Proxy: portInt,
},
Middlewares: map[string]types.LabelMap{
"redirectHTTP": {
"bypass": `
- path glob(/public/*)
`[1:],
},
},
})
require.NoError(t, err)
require.NoError(t, entry.SetMiddlewares([]map[string]any{{
"use": "response",
"set_headers": map[string]string{
"X-Entrypoint-Overlay": "true",
},
}}))
server, ok := entry.GetServer(":1000")
require.True(t, ok, "server not found")
t.Run("bypass_still_works_without_matching_entrypoint_middleware", func(t *testing.T) {
recorder := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "http://test-route.example.com/public/index.html", nil)
server.ServeHTTP(recorder, req)
assert.Equal(t, http.StatusOK, recorder.Code)
assert.Equal(t, "test", recorder.Body.String())
})
t.Run("route_middleware_still_redirects_for_non_matching_paths", func(t *testing.T) {
recorder := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "http://test-route.example.com/private", nil)
server.ServeHTTP(recorder, req)
assert.Equal(t, http.StatusPermanentRedirect, recorder.Code)
assert.Equal(t, "https://test-route.example.com/private", recorder.Header().Get("Location"))
})
}

View File

@@ -0,0 +1,210 @@
package middleware
import (
"errors"
"fmt"
"maps"
"slices"
"github.com/yusing/godoxy/internal/route/rules"
"github.com/yusing/godoxy/internal/serialization"
strutils "github.com/yusing/goutils/strings"
)
type EntrypointRouteOverlay struct {
Middleware *Middleware
ConsumedBypass map[string]struct{}
ConsumedMiddlewares map[string]struct{}
}
type bypassOnlyField struct {
Bypass Bypass `json:"bypass"`
}
var ErrNoEntrypointRouteOverlay = errors.New("no entrypoint route overlay")
// BuildEntrypointRouteOverlay promotes route-level bypass rules into a copy of the entrypoint middleware
// chain. For each route middleware entry in routeMiddlewares that sets "bypass", it finds the entrypoint
// definition with the same "use" name (case-insensitive, snake-agnostic) and appends those rules after
// qualifying them with the route (each rule becomes "route <routeName> & <original>").
//
// name is the logical chain name passed to [BuildMiddlewareFromChainRaw].
//
// It returns [ErrNoEntrypointRouteOverlay] when entrypointDefs or routeMiddlewares is empty, or when no
// route bypass was merged into any entrypoint definition. On success, ConsumedBypass lists normalized
// middleware names whose bypass was applied; ConsumedMiddlewares lists names whose route options contained
// only "bypass", so downstream handling can treat those overlay-only route entries as fully satisfied.
// Route middleware entries with additional options still run at route scope after promotion.
//
// Errors wrap parse/merge failures for bypass values or route qualification.
func BuildEntrypointRouteOverlay(
name string,
entrypointDefs []map[string]any,
routeName string,
routeMiddlewares map[string]OptionsRaw,
) (*EntrypointRouteOverlay, error) {
if len(entrypointDefs) == 0 || len(routeMiddlewares) == 0 {
return nil, ErrNoEntrypointRouteOverlay
}
effectiveDefs := cloneMiddlewareDefs(entrypointDefs)
var consumedBypass map[string]struct{}
var consumedMiddlewares map[string]struct{}
promotedAny := false
for routeMiddlewareName, routeOpts := range routeMiddlewares {
promotedBypass, ok, err := buildPromotedRouteBypass(routeName, routeMiddlewareName, routeOpts)
if err != nil {
return nil, err
}
if !ok {
continue
}
matched, err := mergePromotedBypassIntoEffectiveDefs(effectiveDefs, routeMiddlewareName, promotedBypass)
if err != nil {
return nil, err
}
if !matched {
continue
}
promotedAny = true
consumedBypass, consumedMiddlewares = recordPromotedRouteOverlayConsumption(
consumedBypass,
consumedMiddlewares,
routeMiddlewareName,
routeOpts,
)
}
if !promotedAny {
return nil, ErrNoEntrypointRouteOverlay
}
mid, err := BuildMiddlewareFromChainRaw(name, effectiveDefs)
if err != nil {
return nil, err
}
return &EntrypointRouteOverlay{
Middleware: mid,
ConsumedBypass: consumedBypass,
ConsumedMiddlewares: consumedMiddlewares,
}, nil
}
func buildPromotedRouteBypass(routeName, routeMiddlewareName string, routeOpts OptionsRaw) (Bypass, bool, error) {
routeBypass, ok, err := parseBypassValue(routeOpts["bypass"])
if err != nil {
return nil, false, fmt.Errorf("route middleware %q bypass: %w", routeMiddlewareName, err)
}
if !ok || len(routeBypass) == 0 {
return nil, false, nil
}
promotedBypass, err := qualifyBypassWithRoute(routeName, routeBypass)
if err != nil {
return nil, false, fmt.Errorf("route middleware %q bypass promotion: %w", routeMiddlewareName, err)
}
return promotedBypass, true, nil
}
func mergePromotedBypassIntoEffectiveDefs(effectiveDefs []map[string]any, routeMiddlewareName string, promotedBypass Bypass) (bool, error) {
normalizedRouteMiddlewareName := strutils.ToLowerNoSnake(routeMiddlewareName)
matched := false
for i, def := range effectiveDefs {
use, _ := def["use"].(string)
if strutils.ToLowerNoSnake(use) != normalizedRouteMiddlewareName {
continue
}
mergedBypass, err := appendBypassValue(def["bypass"], promotedBypass)
if err != nil {
return false, fmt.Errorf("entrypoint middleware %q bypass merge: %w", use, err)
}
clonedDef := maps.Clone(def)
clonedDef["bypass"] = mergedBypass
effectiveDefs[i] = clonedDef
matched = true
}
return matched, nil
}
func recordPromotedRouteOverlayConsumption(
consumedBypass map[string]struct{},
consumedMiddlewares map[string]struct{},
routeMiddlewareName string,
routeOpts OptionsRaw,
) (map[string]struct{}, map[string]struct{}) {
normalizedName := strutils.ToLowerNoSnake(routeMiddlewareName)
if consumedBypass == nil {
consumedBypass = make(map[string]struct{})
}
consumedBypass[normalizedName] = struct{}{}
if !isBypassOnlyOptions(routeOpts) {
return consumedBypass, consumedMiddlewares
}
if consumedMiddlewares == nil {
consumedMiddlewares = make(map[string]struct{})
}
consumedMiddlewares[normalizedName] = struct{}{}
return consumedBypass, consumedMiddlewares
}
func cloneMiddlewareDefs(defs []map[string]any) []map[string]any {
cloned := make([]map[string]any, len(defs))
for i, def := range defs {
// Shallow clone is intentional: overlay promotion only replaces the top-level
// bypass field and leaves nested option values untouched.
cloned[i] = maps.Clone(def)
}
return cloned
}
func appendBypassValue(existing any, promoted Bypass) (Bypass, error) {
current, ok, err := parseBypassValue(existing)
if err != nil {
return nil, err
}
if !ok {
return slices.Clone(promoted), nil
}
return append(slices.Clone(current), promoted...), nil
}
func parseBypassValue(raw any) (Bypass, bool, error) {
if raw == nil {
return nil, false, nil
}
var dst bypassOnlyField
if err := serialization.MapUnmarshalValidate(map[string]any{"bypass": raw}, &dst); err != nil {
return nil, true, err
}
return dst.Bypass, true, nil
}
func qualifyBypassWithRoute(routeName string, bypass Bypass) (Bypass, error) {
qualified := make(Bypass, len(bypass))
for i, rule := range bypass {
var routeQualified rules.RuleOn
if err := routeQualified.Parse(fmt.Sprintf("route %s & %s", routeName, rule.String())); err != nil {
return nil, err
}
qualified[i] = routeQualified
}
return qualified, nil
}
func isBypassOnlyOptions(opts OptionsRaw) bool {
if len(opts) == 0 {
return false
}
for key := range opts {
if strutils.ToLowerNoSnake(key) != "bypass" {
return false
}
}
return true
}

View File

@@ -0,0 +1,109 @@
package middleware
import (
"net/http/httptest"
"testing"
"github.com/stretchr/testify/require"
"github.com/yusing/godoxy/internal/route/routes"
"github.com/yusing/godoxy/internal/route/rules"
)
func TestBuildEntrypointRouteOverlayReturnsSentinelWhenNoPromotionOccurs(t *testing.T) {
t.Run("no_matching_entrypoint_middleware", func(t *testing.T) {
overlay, err := BuildEntrypointRouteOverlay(
"entrypoint",
[]map[string]any{{
"use": "response",
}},
"test-route",
map[string]OptionsRaw{
"redirectHTTP": {
"bypass": []string{"path /health"},
},
},
)
require.Nil(t, overlay)
require.ErrorIs(t, err, ErrNoEntrypointRouteOverlay)
})
t.Run("empty_route_middlewares", func(t *testing.T) {
overlay, err := BuildEntrypointRouteOverlay(
"entrypoint",
[]map[string]any{{
"use": "response",
}},
"test-route",
nil,
)
require.Nil(t, overlay)
require.ErrorIs(t, err, ErrNoEntrypointRouteOverlay)
})
}
func TestBuildEntrypointRouteOverlayPromotesRouteBypass(t *testing.T) {
overlay, err := BuildEntrypointRouteOverlay(
"entrypoint",
[]map[string]any{{
"use": "redirectHTTP",
}},
"test-route",
map[string]OptionsRaw{
"redirectHTTP": {
"bypass": []string{"path /health"},
},
},
)
require.NoError(t, err)
require.NotNil(t, overlay)
require.NotNil(t, overlay.Middleware)
require.Contains(t, overlay.ConsumedBypass, "redirecthttp")
require.Contains(t, overlay.ConsumedMiddlewares, "redirecthttp")
}
func TestBuildEntrypointRouteOverlayKeepsNonBypassRouteMiddlewareActive(t *testing.T) {
overlay, err := BuildEntrypointRouteOverlay(
"entrypoint",
[]map[string]any{{
"use": "redirectHTTP",
}},
"test-route",
map[string]OptionsRaw{
"redirectHTTP": {
"bypass": []string{"path /health"},
"redirectHTTP": "https://example.com",
},
},
)
require.NoError(t, err)
require.NotNil(t, overlay)
require.NotNil(t, overlay.Middleware)
require.Contains(t, overlay.ConsumedBypass, "redirecthttp")
require.Empty(t, overlay.ConsumedMiddlewares)
}
func TestQualifyBypassWithRoutePreservesCompositeRuleSemantics(t *testing.T) {
var composite rules.RuleOn
require.NoError(t, composite.Parse("path /health | path /status"))
qualified, err := qualifyBypassWithRoute("test-route", Bypass{composite})
require.NoError(t, err)
require.Len(t, qualified, 1)
matches := func(path, routeName string) bool {
req := httptest.NewRequest("GET", "http://example.com"+path, nil)
if routeName != "" {
req = routes.WithRouteContext(req, fakeMiddlewareHTTPRoute{name: routeName})
}
return qualified[0].Check(httptest.NewRecorder(), req)
}
require.True(t, matches("/health", "test-route"))
require.True(t, matches("/status", "test-route"))
require.False(t, matches("/health", "other-route"))
require.False(t, matches("/metrics", "test-route"))
}

View File

@@ -0,0 +1,59 @@
package middleware
import (
"context"
"net/http"
strutils "github.com/yusing/goutils/strings"
)
type routeOverlayConsumptionContextKey struct{}
type routeOverlayConsumption struct {
bypass map[string]struct{}
middlewares map[string]struct{}
}
var routeOverlayConsumptionKey routeOverlayConsumptionContextKey
func WithConsumedRouteOverlays(
r *http.Request,
bypass map[string]struct{},
middlewares map[string]struct{},
) *http.Request {
if len(bypass) == 0 && len(middlewares) == 0 {
return r
}
return r.WithContext(context.WithValue(r.Context(), routeOverlayConsumptionKey, routeOverlayConsumption{
bypass: bypass,
middlewares: middlewares,
}))
}
func isRouteBypassPromoted(r *http.Request, middlewareName string) bool {
return routeOverlayConsumed(r, middlewareName, func(consumption routeOverlayConsumption) map[string]struct{} {
return consumption.bypass
})
}
func isRouteMiddlewareConsumed(r *http.Request, middlewareName string) bool {
return routeOverlayConsumed(r, middlewareName, func(consumption routeOverlayConsumption) map[string]struct{} {
return consumption.middlewares
})
}
func routeOverlayConsumed(
r *http.Request,
middlewareName string,
selectSet func(routeOverlayConsumption) map[string]struct{},
) bool {
if r == nil {
return false
}
consumption, ok := r.Context().Value(routeOverlayConsumptionKey).(routeOverlayConsumption)
if !ok {
return false
}
_, ok = selectSet(consumption)[strutils.ToLowerNoSnake(middlewareName)]
return ok
}

View File

@@ -0,0 +1,82 @@
package middleware
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/rs/zerolog"
"github.com/stretchr/testify/require"
"github.com/yusing/godoxy/internal/agentpool"
"github.com/yusing/godoxy/internal/homepage"
nettypes "github.com/yusing/godoxy/internal/net/types"
"github.com/yusing/godoxy/internal/route/routes"
"github.com/yusing/godoxy/internal/types"
"github.com/yusing/goutils/task"
)
func TestWithConsumedRouteOverlaysPreservesExistingRequestContext(t *testing.T) {
req := httptest.NewRequest("GET", "http://example.com", nil)
req = routes.WithRouteContext(req, fakeMiddlewareHTTPRoute{name: "test-route"})
req = WithConsumedRouteOverlays(req, map[string]struct{}{
"redirecthttp": {},
}, map[string]struct{}{
"oidc": {},
})
require.Equal(t, "test-route", routes.TryGetUpstreamName(req))
require.True(t, isRouteBypassPromoted(req, "redirectHTTP"))
require.True(t, isRouteMiddlewareConsumed(req, "oidc"))
require.False(t, isRouteBypassPromoted(req, "forwardauth"))
require.False(t, isRouteMiddlewareConsumed(req, "forwardauth"))
}
func TestWithConsumedRouteOverlaysReturnsNewRequestWhenOverlayIsPresent(t *testing.T) {
req := httptest.NewRequest("GET", "http://example.com", nil)
updated := WithConsumedRouteOverlays(req, map[string]struct{}{"redirecthttp": {}}, nil)
require.NotEqual(t, req, updated)
require.True(t, isRouteBypassPromoted(updated, "redirectHTTP"))
require.False(t, isRouteBypassPromoted(req, "redirectHTTP"))
}
type fakeMiddlewareHTTPRoute struct {
name string
}
func (r fakeMiddlewareHTTPRoute) Key() string { return r.name }
func (r fakeMiddlewareHTTPRoute) Name() string { return r.name }
func (r fakeMiddlewareHTTPRoute) Start(task.Parent) error { return nil }
func (r fakeMiddlewareHTTPRoute) Task() *task.Task { return nil }
func (r fakeMiddlewareHTTPRoute) Finish(any) {}
func (r fakeMiddlewareHTTPRoute) MarshalZerologObject(*zerolog.Event) {}
func (r fakeMiddlewareHTTPRoute) ProviderName() string { return "" }
func (r fakeMiddlewareHTTPRoute) GetProvider() types.RouteProvider { return nil }
func (r fakeMiddlewareHTTPRoute) ListenURL() *nettypes.URL { return nil }
func (r fakeMiddlewareHTTPRoute) TargetURL() *nettypes.URL { return nil }
func (r fakeMiddlewareHTTPRoute) HealthMonitor() types.HealthMonitor { return nil }
func (r fakeMiddlewareHTTPRoute) SetHealthMonitor(types.HealthMonitor) {}
func (r fakeMiddlewareHTTPRoute) References() []string { return nil }
func (r fakeMiddlewareHTTPRoute) ShouldExclude() bool { return false }
func (r fakeMiddlewareHTTPRoute) Started() <-chan struct{} { return nil }
func (r fakeMiddlewareHTTPRoute) IdlewatcherConfig() *types.IdlewatcherConfig { return nil }
func (r fakeMiddlewareHTTPRoute) HealthCheckConfig() types.HealthCheckConfig {
return types.HealthCheckConfig{}
}
func (r fakeMiddlewareHTTPRoute) LoadBalanceConfig() *types.LoadBalancerConfig {
return nil
}
func (r fakeMiddlewareHTTPRoute) HomepageItem() homepage.Item { return homepage.Item{} }
func (r fakeMiddlewareHTTPRoute) DisplayName() string { return r.name }
func (r fakeMiddlewareHTTPRoute) ContainerInfo() *types.Container { return nil }
func (r fakeMiddlewareHTTPRoute) InboundMTLSProfileRef() string { return "" }
func (r fakeMiddlewareHTTPRoute) RouteMiddlewares() map[string]types.LabelMap { return nil }
func (r fakeMiddlewareHTTPRoute) GetAgent() *agentpool.Agent { return nil }
func (r fakeMiddlewareHTTPRoute) IsDocker() bool { return false }
func (r fakeMiddlewareHTTPRoute) IsAgent() bool { return false }
func (r fakeMiddlewareHTTPRoute) UseLoadBalance() bool { return false }
func (r fakeMiddlewareHTTPRoute) UseIdleWatcher() bool { return false }
func (r fakeMiddlewareHTTPRoute) UseHealthCheck() bool { return false }
func (r fakeMiddlewareHTTPRoute) UseAccessLog() bool { return false }
func (r fakeMiddlewareHTTPRoute) ServeHTTP(http.ResponseWriter, *http.Request) {}