mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-27 18:57:04 +02:00
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:
59
internal/net/gphttp/middleware/route_overlay_context.go
Normal file
59
internal/net/gphttp/middleware/route_overlay_context.go
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user