From f0eeaecbb1cabe0d7097ec79d83c36e3c9ff9cb2 Mon Sep 17 00:00:00 2001 From: KartoffelChips <104089082+KartoffelChipss@users.noreply.github.com> Date: Tue, 31 Mar 2026 14:17:46 +0200 Subject: [PATCH] Added custom headers option --- app/handlers/static.go | 15 +++++++++++ config.example.yaml | 12 +++++++-- internal/config/config.go | 54 +++++++++++++++++++++++++++++++-------- 3 files changed, 69 insertions(+), 12 deletions(-) diff --git a/app/handlers/static.go b/app/handlers/static.go index ca80534..a1349be 100644 --- a/app/handlers/static.go +++ b/app/handlers/static.go @@ -2,6 +2,7 @@ package handlers import ( "os" + "path" "path/filepath" "quay/internal/config" @@ -21,6 +22,20 @@ func NewStaticHandler(storagePath string, siteMap map[string]config.SiteConfig) urlPath := filepath.Clean(c.Path()) + for _, header := range site.CustomHeaders { + var matched bool + if header.Regex && header.Compiled != nil { + matched = header.Compiled.MatchString(urlPath) + } else { + matched, _ = path.Match(header.Source, urlPath) + } + if matched { + for key, value := range header.Headers { + c.Set(key, value) + } + } + } + for _, rule := range site.ForwardRules { if rule.Regex && rule.Compiled != nil { match := rule.Compiled.FindStringSubmatchIndex(urlPath) diff --git a/config.example.yaml b/config.example.yaml index c6a1b93..03f378d 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -9,20 +9,28 @@ sites: domain: docs.my-lib.com deploy_token: "${MY_LIB_DEPLOY_TOKEN}" enabled: true + not_found_file: 404.html forward_rules: - source: /npm destination: https://www.npmjs.com/package/my-lib status_code: 302 - - source: ^/docs/v(\d+)$ destination: https://v$1.docs.my-lib.com/ status_code: 301 regex: true - - source: ^/blog/(?P[^/]+)$ destination: /posts/${slug} status_code: 302 regex: true + custom_headers: + - source: /json/* # glob (default) + headers: + Content-Type: "application/json" + Cache-Control: "max-age=7200, must-revalidate" + - source: ^/api/v\d+/ # regex opt-in + regex: true + headers: + Cache-Control: "no-store" - repo: portfolio owner: yourname diff --git a/internal/config/config.go b/internal/config/config.go index d264f99..b292b8b 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -3,6 +3,7 @@ package config import ( "fmt" "os" + "path" "regexp" "strconv" @@ -17,17 +18,25 @@ type ForwardRule struct { Compiled *regexp.Regexp } +type CustomHeader struct { + Source string `yaml:"source"` + Regex bool `yaml:"regex"` + Headers map[string]string `yaml:"headers"` + Compiled *regexp.Regexp +} + type SiteConfig struct { - Name string `yaml:"name"` - Repo string `yaml:"repo"` - Owner string `yaml:"owner"` - Branch string `yaml:"branch"` - Domain string `yaml:"domain"` - Enabled bool `yaml:"enabled"` - SPA bool `yaml:"spa"` - NotFoundFile string `yaml:"not_found_file"` - DeployToken string `yaml:"deploy_token"` - ForwardRules []ForwardRule `yaml:"forward_rules"` + Name string `yaml:"name"` + Repo string `yaml:"repo"` + Owner string `yaml:"owner"` + Branch string `yaml:"branch"` + Domain string `yaml:"domain"` + Enabled bool `yaml:"enabled"` + SPA bool `yaml:"spa"` + NotFoundFile string `yaml:"not_found_file"` + DeployToken string `yaml:"deploy_token"` + ForwardRules []ForwardRule `yaml:"forward_rules"` + CustomHeaders []CustomHeader `yaml:"custom_headers"` } type Config struct { @@ -84,6 +93,31 @@ func validateConfig(config *Config) error { config.Sites[i].ForwardRules[j].Compiled = re } } + for k, header := range site.CustomHeaders { + if header.Source == "" { + return &Error{Field: fmt.Sprintf("sites[%d].custom_headers[%d].source", i, k), Message: "Source is required"} + } + if len(header.Headers) == 0 { + return &Error{Field: fmt.Sprintf("sites[%d].custom_headers[%d].headers", i, k), Message: "At least one header is required"} + } + if header.Regex { + re, err := regexp.Compile(header.Source) + if err != nil { + return &Error{ + Field: fmt.Sprintf("sites[%d].custom_headers[%d].source", i, k), + Message: "Invalid regex: " + err.Error(), + } + } + config.Sites[i].CustomHeaders[k].Compiled = re + } else { + if _, err := path.Match(header.Source, ""); err != nil { + return &Error{ + Field: fmt.Sprintf("sites[%d].custom_headers[%d].source", i, k), + Message: "Invalid glob pattern: " + err.Error(), + } + } + } + } } return nil }