Files
git-pages/src/wildcard.go

106 lines
2.6 KiB
Go

package main
import (
"fmt"
"log"
"net/http"
"net/http/httputil"
"net/url"
"slices"
"strings"
"github.com/valyala/fasttemplate"
)
type WildcardPattern struct {
Domain []string
CloneURL *fasttemplate.Template
IndexRepos []*fasttemplate.Template
FallbackURL *url.URL
}
var wildcardPatterns []*WildcardPattern
func (pattern *WildcardPattern) GetHost() string {
parts := []string{"*"}
parts = append(parts, pattern.Domain...)
return strings.Join(parts, ".")
}
// Returns `subdomain, found` where if `found == true`, `subdomain` contains the part of `host`
// corresponding to the * in the domain pattern.
func (pattern *WildcardPattern) Matches(host string) (string, bool) {
hostParts := strings.Split(host, ".")
if len(hostParts) != 1+len(pattern.Domain) || !slices.Equal(hostParts[1:], pattern.Domain) {
return "", false
}
return hostParts[0], true
}
func (pattern *WildcardPattern) IsFallbackFor(host string) bool {
if pattern.FallbackURL == nil {
return false
}
_, found := pattern.Matches(host)
return found
}
func HandleWildcardFallback(w http.ResponseWriter, r *http.Request) (bool, error) {
host, err := GetHost(r)
if err != nil {
return false, err
}
for _, pattern := range wildcardPatterns {
if pattern.IsFallbackFor(host) {
log.Printf("proxy: %s via %s", pattern.GetHost(), pattern.FallbackURL)
(&httputil.ReverseProxy{
Rewrite: func(r *httputil.ProxyRequest) {
r.SetURL(pattern.FallbackURL)
r.Out.Host = r.In.Host
r.Out.Header["X-Forwarded-For"] = r.In.Header["X-Forwarded-For"]
},
}).ServeHTTP(w, r)
return true, nil
}
}
return false, nil
}
func ConfigureWildcards(configs []WildcardConfig) error {
for _, config := range configs {
cloneURLTemplate, err := fasttemplate.NewTemplate(config.CloneURL, "<", ">")
if err != nil {
return fmt.Errorf("wildcard pattern: clone URL: %w", err)
}
var indexRepoTemplates []*fasttemplate.Template
for _, indexRepo := range config.IndexRepos {
indexRepoTemplate, err := fasttemplate.NewTemplate(indexRepo, "<", ">")
if err != nil {
return fmt.Errorf("wildcard pattern: index repo: %w", err)
}
indexRepoTemplates = append(indexRepoTemplates, indexRepoTemplate)
}
var fallbackURL *url.URL
if config.FallbackProxyTo != "" {
fallbackURL, err = url.Parse(config.FallbackProxyTo)
if err != nil {
return fmt.Errorf("wildcard pattern: fallback URL: %w", err)
}
}
wildcardPatterns = append(wildcardPatterns, &WildcardPattern{
Domain: strings.Split(config.Domain, "."),
CloneURL: cloneURLTemplate,
IndexRepos: indexRepoTemplates,
FallbackURL: fallbackURL,
})
}
return nil
}