Some checks failed
Veza CI / Backend (Go) (push) Waiting to run
Veza CI / Frontend (Web) (push) Waiting to run
Veza CI / Notify on failure (push) Blocked by required conditions
Security Scan / Secret Scanning (gitleaks) (push) Failing after 3m4s
Veza CI / Rust (Stream Server) (push) Has been cancelled
Backend API CI / test-integration (push) Failing after 11m59s
Backend API CI / test-unit (push) Failing after 12m1s
backend-ci.yml's `test -z "$(gofmt -l .)"` strict gate (added in
c96edd692) failed on a backlog of unformatted files. None of the
85 files in this commit had been edited since the gate was added
because no push touched veza-backend-api/** in between, so the
gate never fired until today's CI fixes triggered it.
The diff is exclusively whitespace alignment in struct literals
and trailing-space comments. `go build ./...` and the full test
suite (with VEZA_SKIP_INTEGRATION=1 -short) pass identically.
82 lines
2.4 KiB
Go
82 lines
2.4 KiB
Go
package middleware
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// CacheHeadersConfig defines cache-control rules per path prefix
|
|
type CacheHeadersConfig struct {
|
|
Rules []CacheRule
|
|
}
|
|
|
|
// CacheRule maps a URL path prefix to cache headers
|
|
type CacheRule struct {
|
|
PathPrefix string
|
|
MaxAge int // seconds
|
|
Directive string // e.g. "public", "private", "no-cache"
|
|
Immutable bool
|
|
}
|
|
|
|
// DefaultCacheHeadersConfig returns production-ready cache header rules
|
|
// Reference: ORIGIN_PERFORMANCE_TARGETS.md §8.4
|
|
func DefaultCacheHeadersConfig() CacheHeadersConfig {
|
|
return CacheHeadersConfig{
|
|
Rules: []CacheRule{
|
|
// Static assets (JS, CSS, fonts) — immutable with content hash
|
|
{PathPrefix: "/static/", MaxAge: 31536000, Directive: "public", Immutable: true},
|
|
{PathPrefix: "/assets/", MaxAge: 31536000, Directive: "public", Immutable: true},
|
|
// Audio files — CDN cached for 7 days
|
|
{PathPrefix: "/audio/", MaxAge: 604800, Directive: "public"},
|
|
// HLS segments — short cache (live content changes)
|
|
{PathPrefix: "/hls/", MaxAge: 60, Directive: "public"},
|
|
// Images (covers, avatars) — CDN cached for 30 days
|
|
{PathPrefix: "/images/", MaxAge: 2592000, Directive: "public"},
|
|
{PathPrefix: "/uploads/", MaxAge: 86400, Directive: "public"},
|
|
// API responses — no caching by default (handled by ResponseCache middleware)
|
|
{PathPrefix: "/api/", MaxAge: 0, Directive: "no-cache"},
|
|
},
|
|
}
|
|
}
|
|
|
|
// CacheHeaders returns a middleware that sets appropriate Cache-Control headers
|
|
// based on the request path. This enables CDN and browser caching.
|
|
func CacheHeaders(cfg CacheHeadersConfig) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
path := c.Request.URL.Path
|
|
|
|
for _, rule := range cfg.Rules {
|
|
if strings.HasPrefix(path, rule.PathPrefix) {
|
|
setCacheHeaders(c, rule)
|
|
break
|
|
}
|
|
}
|
|
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
func setCacheHeaders(c *gin.Context, rule CacheRule) {
|
|
if rule.MaxAge == 0 && rule.Directive == "no-cache" {
|
|
c.Header("Cache-Control", "no-cache, no-store, must-revalidate")
|
|
c.Header("Pragma", "no-cache")
|
|
return
|
|
}
|
|
|
|
var parts []string
|
|
if rule.Directive != "" {
|
|
parts = append(parts, rule.Directive)
|
|
}
|
|
if rule.MaxAge > 0 {
|
|
parts = append(parts, "max-age="+strconv.Itoa(rule.MaxAge))
|
|
}
|
|
if rule.Immutable {
|
|
parts = append(parts, "immutable")
|
|
}
|
|
|
|
if len(parts) > 0 {
|
|
c.Header("Cache-Control", strings.Join(parts, ", "))
|
|
}
|
|
}
|