Files
godoxy-yusing/internal/net/gphttp/middleware/route_overlay_context.go
Yuzerion 44298d1933 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 -->
2026-04-15 18:35:06 +08:00

60 lines
1.5 KiB
Go

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
}