feat: middleware reach, response writer interfaces, and CORS fixes

- Run global middleware for all requests, including OPTIONS preflights, NotFound, and MethodNotAllowed — previously bypassed by httprouter's internal handling
- Implement Hijacker, Flusher, and Pusher on the response writer for WebSocket, SSE, and HTTP/2 push support
- Fix CORS: echo a single matching origin, handle AllowCredentials with wildcard, append Vary: Origin
- Logger logs from a defer to capture correct status on panicked requests
- Static and StaticFS accept route middleware; add Context.AddHeader; warn on NotFound handler override
This commit is contained in:
2026-05-17 17:51:56 +02:00
parent 36c6d76e53
commit ae5d1f610a
7 changed files with 237 additions and 69 deletions

View File

@@ -34,14 +34,37 @@ func CORSWithConfig(cfg CORSConfig) kite.Middleware {
cfg.AllowedHeaders = []string{"Content-Type", "Authorization"}
}
origins := strings.Join(cfg.AllowedOrigins, ", ")
allowAll := len(cfg.AllowedOrigins) == 1 && cfg.AllowedOrigins[0] == "*"
methods := strings.Join(cfg.AllowedMethods, ", ")
headers := strings.Join(cfg.AllowedHeaders, ", ")
exposed := strings.Join(cfg.ExposedHeaders, ", ")
originSet := make(map[string]struct{}, len(cfg.AllowedOrigins))
for _, o := range cfg.AllowedOrigins {
originSet[o] = struct{}{}
}
return func(h kite.Handler) kite.Handler {
return func(ctx *kite.Context) error {
ctx.SetHeader("Access-Control-Allow-Origin", origins)
origin := ctx.GetHeader("Origin")
allowOrigin := ""
switch {
case allowAll && !cfg.AllowCredentials:
allowOrigin = "*"
case allowAll && cfg.AllowCredentials:
allowOrigin = origin
default:
if _, ok := originSet[origin]; ok {
allowOrigin = origin
}
}
if allowOrigin != "" {
ctx.SetHeader("Access-Control-Allow-Origin", allowOrigin)
ctx.AddHeader("Vary", "Origin")
}
ctx.SetHeader("Access-Control-Allow-Methods", methods)
ctx.SetHeader("Access-Control-Allow-Headers", headers)

View File

@@ -42,10 +42,10 @@ func LoggerWithConfig(cfg LoggerConfig) kite.Middleware {
}
start := time.Now()
err := h(ctx)
logger.Println(cfg.Format(ctx.GetMethod(), ctx.GetPath(), ctx.GetStatusCode(), time.Since(start)))
return err
defer func() {
logger.Println(cfg.Format(ctx.GetMethod(), ctx.GetPath(), ctx.GetStatusCode(), time.Since(start)))
}()
return h(ctx)
}
}
}