58 lines
1.8 KiB
Go
58 lines
1.8 KiB
Go
package httputil
|
|
|
|
import (
|
|
"net/http"
|
|
"slices"
|
|
"strings"
|
|
|
|
"kjol/appenv"
|
|
)
|
|
|
|
// CorsConfig configures CorsMiddleware. AllowedDomains is consulted only outside
|
|
// development (in development every origin is allowed). BundleVersion, when set,
|
|
// is called to stamp the X-Bundle-Version header on /api/ responses; leave it nil
|
|
// to skip that header.
|
|
type CorsConfig struct {
|
|
AllowedDomains []string
|
|
BundleVersion func() string
|
|
}
|
|
|
|
// CorsMiddleware returns middleware that applies CORS headers to all requests.
|
|
// It is a constructor (not the middleware itself) so the app can inject its
|
|
// allowed domains and bundle-version source without this package importing app
|
|
// config or handlers.
|
|
func CorsMiddleware(cfg CorsConfig) func(http.Handler) http.Handler {
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
origin := r.Header.Get("Origin")
|
|
|
|
if appenv.Environment != appenv.EnvTypeDevelopment {
|
|
if len(cfg.AllowedDomains) > 0 && slices.Contains(cfg.AllowedDomains, origin) {
|
|
w.Header().Set("Access-Control-Allow-Origin", origin)
|
|
}
|
|
} else {
|
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
}
|
|
|
|
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
|
|
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
|
w.Header().Set("Access-Control-Expose-Headers", "X-Bundle-Version")
|
|
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
|
|
|
if cfg.BundleVersion != nil {
|
|
if version := cfg.BundleVersion(); version != "" && strings.HasPrefix(r.URL.Path, "/api/") {
|
|
w.Header().Set("X-Bundle-Version", version)
|
|
}
|
|
}
|
|
|
|
// Handle preflight OPTIONS request
|
|
if r.Method == http.MethodOptions {
|
|
w.WriteHeader(http.StatusNoContent)
|
|
return
|
|
}
|
|
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
}
|