mirror of
https://codeberg.org/git-pages/git-pages.git
synced 2026-05-14 03:01:48 +00:00
[breaking-change] Make fallback handler per-instance, not per-wildcard.
There was never a particularly good reason to tie the fallback handler to a wildcard domain; most importantly, this prevented it from being used for custom domains, which is required for migrating custom domains from Codeberg Pages v2 server.
This commit is contained in:
@@ -16,7 +16,10 @@ clone-url = "https://codeberg.org/<user>/<project>.git"
|
||||
index-repos = ["<user>.codeberg.page", "pages"]
|
||||
index-repo-branch = "main"
|
||||
authorization = "forgejo"
|
||||
fallback-proxy-to = "https://codeberg.page"
|
||||
|
||||
[fallback] # non-default section
|
||||
proxy-to = "https://codeberg.page"
|
||||
insecure = false
|
||||
|
||||
[storage]
|
||||
type = "fs"
|
||||
@@ -24,7 +27,7 @@ type = "fs"
|
||||
[storage.fs]
|
||||
root = "./data"
|
||||
|
||||
[storage.s3] # non-default bucket configuration
|
||||
[storage.s3] # non-default section
|
||||
endpoint = "play.min.io"
|
||||
access-key-id = "Q3AM3UQ867SPQQA43P2F"
|
||||
secret-access-key = "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"
|
||||
|
||||
58
src/caddy.go
58
src/caddy.go
@@ -1,6 +1,7 @@
|
||||
package git_pages
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
@@ -34,31 +35,9 @@ func ServeCaddy(w http.ResponseWriter, r *http.Request) {
|
||||
// Pages v2, which would under some circumstances return certificates with subjectAltName
|
||||
// not valid for the SNI. Go's TLS stack makes `tls.Dial` return an error for these,
|
||||
// thankfully making it unnecessary to examine X.509 certificates manually here.)
|
||||
for _, wildcardConfig := range config.Wildcard {
|
||||
if wildcardConfig.FallbackProxyTo == "" {
|
||||
continue
|
||||
}
|
||||
fallbackURL, err := url.Parse(wildcardConfig.FallbackProxyTo)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if fallbackURL.Scheme != "https" {
|
||||
continue
|
||||
}
|
||||
connectHost := fallbackURL.Host
|
||||
if fallbackURL.Port() != "" {
|
||||
connectHost += ":" + fallbackURL.Port()
|
||||
} else {
|
||||
connectHost += ":443"
|
||||
}
|
||||
logc.Printf(r.Context(), "caddy: check TLS %s", fallbackURL)
|
||||
connection, err := tls.Dial("tcp", connectHost, &tls.Config{ServerName: domain})
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
connection.Close()
|
||||
found = true
|
||||
break
|
||||
found, err = tryDialWithSNI(r.Context(), domain)
|
||||
if err != nil {
|
||||
logc.Printf(r.Context(), "caddy err: check SNI: %s\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,3 +53,32 @@ func ServeCaddy(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, err)
|
||||
}
|
||||
}
|
||||
|
||||
func tryDialWithSNI(ctx context.Context, domain string) (bool, error) {
|
||||
if config.Fallback.ProxyTo == "" {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
fallbackURL, err := url.Parse(config.Fallback.ProxyTo)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if fallbackURL.Scheme != "https" {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
connectHost := fallbackURL.Host
|
||||
if fallbackURL.Port() != "" {
|
||||
connectHost += ":" + fallbackURL.Port()
|
||||
} else {
|
||||
connectHost += ":443"
|
||||
}
|
||||
|
||||
logc.Printf(ctx, "caddy: check TLS %s", fallbackURL)
|
||||
connection, err := tls.Dial("tcp", connectHost, &tls.Config{ServerName: domain})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
connection.Close()
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ type Config struct {
|
||||
LogLevel string `toml:"log-level" default:"info"`
|
||||
Server ServerConfig `toml:"server"`
|
||||
Wildcard []WildcardConfig `toml:"wildcard"`
|
||||
Fallback FallbackConfig `toml:"fallback"`
|
||||
Storage StorageConfig `toml:"storage"`
|
||||
Limits LimitsConfig `toml:"limits"`
|
||||
Observability ObservabilityConfig `toml:"observability"`
|
||||
@@ -53,13 +54,16 @@ type ServerConfig struct {
|
||||
}
|
||||
|
||||
type WildcardConfig struct {
|
||||
Domain string `toml:"domain"`
|
||||
CloneURL string `toml:"clone-url"`
|
||||
IndexRepos []string `toml:"index-repos" default:"[]"`
|
||||
IndexRepoBranch string `toml:"index-repo-branch" default:"pages"`
|
||||
Authorization string `toml:"authorization"`
|
||||
FallbackProxyTo string `toml:"fallback-proxy-to"`
|
||||
FallbackInsecure bool `toml:"fallback-insecure"`
|
||||
Domain string `toml:"domain"`
|
||||
CloneURL string `toml:"clone-url"`
|
||||
IndexRepos []string `toml:"index-repos" default:"[]"`
|
||||
IndexRepoBranch string `toml:"index-repo-branch" default:"pages"`
|
||||
Authorization string `toml:"authorization"`
|
||||
}
|
||||
|
||||
type FallbackConfig struct {
|
||||
ProxyTo string `toml:"proxy-to"`
|
||||
Insecure bool `toml:"insecure"`
|
||||
}
|
||||
|
||||
type CacheConfig struct {
|
||||
|
||||
30
src/main.go
30
src/main.go
@@ -2,6 +2,7 @@ package git_pages
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
@@ -22,6 +24,7 @@ import (
|
||||
|
||||
var config *Config
|
||||
var wildcards []*WildcardPattern
|
||||
var fallback http.Handler
|
||||
var backend Backend
|
||||
|
||||
func configureFeatures() (err error) {
|
||||
@@ -63,6 +66,31 @@ func configureWildcards() (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
func configureFallback() (err error) {
|
||||
if config.Fallback.ProxyTo != "" {
|
||||
var fallbackURL *url.URL
|
||||
fallbackURL, err = url.Parse(config.Fallback.ProxyTo)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("fallback: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
fallback = &httputil.ReverseProxy{
|
||||
Rewrite: func(r *httputil.ProxyRequest) {
|
||||
r.SetURL(fallbackURL)
|
||||
r.Out.Host = r.In.Host
|
||||
r.Out.Header["X-Forwarded-For"] = r.In.Header["X-Forwarded-For"]
|
||||
},
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: config.Fallback.Insecure,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func listen(name string, listen string) net.Listener {
|
||||
if listen == "-" {
|
||||
return nil
|
||||
@@ -230,6 +258,7 @@ func Main() {
|
||||
configureFeatures(),
|
||||
configureMemLimit(),
|
||||
configureWildcards(),
|
||||
configureFallback(),
|
||||
); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
@@ -392,6 +421,7 @@ func Main() {
|
||||
configureFeatures(),
|
||||
configureMemLimit(),
|
||||
configureWildcards(),
|
||||
configureFallback(),
|
||||
); err != nil {
|
||||
// At this point the configuration is in an in-between, corrupted state, so
|
||||
// the only reasonable choice is to crash.
|
||||
|
||||
@@ -136,8 +136,10 @@ func getPage(w http.ResponseWriter, r *http.Request) error {
|
||||
result := <-indexManifestCh
|
||||
manifest, manifestMtime, err = result.manifest, result.manifestMtime, result.err
|
||||
if manifest == nil && errors.Is(err, ErrObjectNotFound) {
|
||||
if found, fallbackErr := HandleWildcardFallback(w, r); found {
|
||||
return fallbackErr
|
||||
if fallback != nil {
|
||||
logc.Printf(r.Context(), "fallback: %s via %s", host, config.Fallback.ProxyTo)
|
||||
fallback.ServeHTTP(w, r)
|
||||
return nil
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
fmt.Fprintf(w, "site not found\n")
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
package git_pages
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
@@ -18,8 +14,6 @@ type WildcardPattern struct {
|
||||
IndexRepos []*fasttemplate.Template
|
||||
IndexBranch string
|
||||
Authorization bool
|
||||
FallbackURL *url.URL
|
||||
Fallback http.Handler
|
||||
}
|
||||
|
||||
func (pattern *WildcardPattern) GetHost() string {
|
||||
@@ -78,30 +72,6 @@ func (pattern *WildcardPattern) ApplyTemplate(userName string, projectName strin
|
||||
return repoURLs, branch
|
||||
}
|
||||
|
||||
func (pattern *WildcardPattern) IsFallbackFor(host string) bool {
|
||||
if pattern.Fallback == 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 wildcards {
|
||||
if pattern.IsFallbackFor(host) {
|
||||
logc.Printf(r.Context(), "proxy: %s via %s", pattern.GetHost(), pattern.FallbackURL)
|
||||
pattern.Fallback.ServeHTTP(w, r)
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func TranslateWildcards(configs []WildcardConfig) ([]*WildcardPattern, error) {
|
||||
var wildcardPatterns []*WildcardPattern
|
||||
for _, config := range configs {
|
||||
@@ -134,36 +104,12 @@ func TranslateWildcards(configs []WildcardConfig) ([]*WildcardPattern, error) {
|
||||
}
|
||||
}
|
||||
|
||||
var fallbackURL *url.URL
|
||||
var fallback http.Handler
|
||||
if config.FallbackProxyTo != "" {
|
||||
fallbackURL, err = url.Parse(config.FallbackProxyTo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wildcard pattern: fallback URL: %w", err)
|
||||
}
|
||||
|
||||
fallback = &httputil.ReverseProxy{
|
||||
Rewrite: func(r *httputil.ProxyRequest) {
|
||||
r.SetURL(fallbackURL)
|
||||
r.Out.Host = r.In.Host
|
||||
r.Out.Header["X-Forwarded-For"] = r.In.Header["X-Forwarded-For"]
|
||||
},
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: config.FallbackInsecure,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
wildcardPatterns = append(wildcardPatterns, &WildcardPattern{
|
||||
Domain: strings.Split(config.Domain, "."),
|
||||
CloneURL: cloneURLTemplate,
|
||||
IndexRepos: indexRepoTemplates,
|
||||
IndexBranch: indexRepoBranch,
|
||||
Authorization: authorization,
|
||||
FallbackURL: fallbackURL,
|
||||
Fallback: fallback,
|
||||
})
|
||||
}
|
||||
return wildcardPatterns, nil
|
||||
|
||||
Reference in New Issue
Block a user