diff --git a/cli/flags.go b/cli/flags.go
index 58004b3..0aed4a9 100644
--- a/cli/flags.go
+++ b/cli/flags.go
@@ -81,11 +81,11 @@ var (
Usage: "specifies the domain from which raw repository content shall be served, not set disable raw content hosting",
EnvVars: []string{"RAW_DOMAIN"},
},
- &cli.StringFlag{
+ &cli.StringSliceFlag{
Name: "canonical-domain-file",
- Usage: "specifies the file from which the canonical domain shall be specified in",
- EnvVars: []string{"CANONICAL_DOMAIN_FILE"},
- Value: ".domains",
+ Usage: "specifies the file from which the canonical domain may be specified in. Use this flag multiple times to support multiple different file names, if multiple files exist in a single repository they will be merged.",
+ EnvVars: []string{"CANONICAL_DOMAIN_FILES"},
+ Value: cli.NewStringSlice(".domains"),
},
// #########################
diff --git a/config/config.go b/config/config.go
index 954cdc9..d8c3da1 100644
--- a/config/config.go
+++ b/config/config.go
@@ -9,16 +9,16 @@ type Config struct {
}
type ServerConfig struct {
- Host string `default:"[::]"`
- Port uint16 `default:"443"`
- HttpPort uint16 `default:"80"`
- HttpServerEnabled bool `default:"true"`
- MainDomain string
- RawDomain string
- CanonicalDomainFile string `default:".domains"`
- PagesBranches []string
- AllowedCorsDomains []string
- BlacklistedPaths []string
+ Host string `default:"[::]"`
+ Port uint16 `default:"443"`
+ HttpPort uint16 `default:"80"`
+ HttpServerEnabled bool `default:"true"`
+ MainDomain string
+ RawDomain string
+ CanonicalDomainFiles []string `default:"[\".domains\"]"`
+ PagesBranches []string `default:"[\"main\", \"master\", \"pages\"]"`
+ AllowedCorsDomains []string
+ BlacklistedPaths []string
}
type ForgeConfig struct {
diff --git a/config/setup.go b/config/setup.go
index 5b56500..2f131c5 100644
--- a/config/setup.go
+++ b/config/setup.go
@@ -20,9 +20,6 @@ func NewDefaultConfig() Config {
panic(err)
}
- // defaults does not support setting arrays from strings
- config.Server.PagesBranches = []string{"main", "master", "pages"}
-
return config
}
@@ -76,7 +73,7 @@ func mergeServerConfig(ctx *cli.Context, config *ServerConfig) {
config.RawDomain = ctx.String("raw-domain")
}
if ctx.IsSet("canonical-domain-file") {
- config.CanonicalDomainFile = ctx.String("canonical-domain-file")
+ config.CanonicalDomainFiles = ctx.StringSlice("canonical-domain-file")
}
if ctx.IsSet("pages-branch") {
config.PagesBranches = ctx.StringSlice("pages-branch")
diff --git a/config/setup_test.go b/config/setup_test.go
index f9a5e1f..dea9fd2 100644
--- a/config/setup_test.go
+++ b/config/setup_test.go
@@ -136,16 +136,16 @@ func TestMergeConfigShouldReplaceAllExistingValuesGivenAllArgsExist(t *testing.T
cfg := &Config{
LogLevel: "original",
Server: ServerConfig{
- Host: "original",
- Port: 8080,
- HttpPort: 80,
- HttpServerEnabled: false,
- MainDomain: "original",
- RawDomain: "original",
- CanonicalDomainFile: "original",
- PagesBranches: []string{"original"},
- AllowedCorsDomains: []string{"original"},
- BlacklistedPaths: []string{"original"},
+ Host: "original",
+ Port: 8080,
+ HttpPort: 80,
+ HttpServerEnabled: false,
+ MainDomain: "original",
+ RawDomain: "original",
+ CanonicalDomainFiles: []string{"original"},
+ PagesBranches: []string{"original"},
+ AllowedCorsDomains: []string{"original"},
+ BlacklistedPaths: []string{"original"},
},
Forge: ForgeConfig{
Root: "original",
@@ -177,16 +177,16 @@ func TestMergeConfigShouldReplaceAllExistingValuesGivenAllArgsExist(t *testing.T
expectedConfig := &Config{
LogLevel: "changed",
Server: ServerConfig{
- Host: "changed",
- Port: 8443,
- HttpPort: 443,
- HttpServerEnabled: true,
- MainDomain: "changed",
- RawDomain: "changed",
- CanonicalDomainFile: "changed",
- PagesBranches: []string{"changed"},
- AllowedCorsDomains: []string{"changed"},
- BlacklistedPaths: append([]string{"changed"}, ALWAYS_BLACKLISTED_PATHS...),
+ Host: "changed",
+ Port: 8443,
+ HttpPort: 443,
+ HttpServerEnabled: true,
+ MainDomain: "changed",
+ RawDomain: "changed",
+ CanonicalDomainFiles: []string{"changed"},
+ PagesBranches: []string{"changed"},
+ AllowedCorsDomains: []string{"changed"},
+ BlacklistedPaths: append([]string{"changed"}, ALWAYS_BLACKLISTED_PATHS...),
},
Forge: ForgeConfig{
Root: "changed",
@@ -276,29 +276,29 @@ func TestMergeServerConfigShouldReplaceAllExistingValuesGivenAllArgsExist(t *tes
t,
func(ctx *cli.Context) error {
cfg := &ServerConfig{
- Host: "original",
- Port: 8080,
- HttpPort: 80,
- HttpServerEnabled: false,
- MainDomain: "original",
- RawDomain: "original",
- CanonicalDomainFile: "original",
- AllowedCorsDomains: []string{"original"},
- BlacklistedPaths: []string{"original"},
+ Host: "original",
+ Port: 8080,
+ HttpPort: 80,
+ HttpServerEnabled: false,
+ MainDomain: "original",
+ RawDomain: "original",
+ CanonicalDomainFiles: []string{"original"},
+ AllowedCorsDomains: []string{"original"},
+ BlacklistedPaths: []string{"original"},
}
mergeServerConfig(ctx, cfg)
expectedConfig := &ServerConfig{
- Host: "changed",
- Port: 8443,
- HttpPort: 443,
- HttpServerEnabled: true,
- MainDomain: "changed",
- RawDomain: "changed",
- CanonicalDomainFile: "changed",
- AllowedCorsDomains: fixArrayFromCtx(ctx, "allowed-cors-domains", []string{"changed"}),
- BlacklistedPaths: fixArrayFromCtx(ctx, "blacklisted-paths", append([]string{"changed"}, ALWAYS_BLACKLISTED_PATHS...)),
+ Host: "changed",
+ Port: 8443,
+ HttpPort: 443,
+ HttpServerEnabled: true,
+ MainDomain: "changed",
+ RawDomain: "changed",
+ CanonicalDomainFiles: fixArrayFromCtx(ctx, "canonical-domain-file", []string{"changed"}),
+ AllowedCorsDomains: fixArrayFromCtx(ctx, "allowed-cors-domains", []string{"changed"}),
+ BlacklistedPaths: fixArrayFromCtx(ctx, "blacklisted-paths", append([]string{"changed"}, ALWAYS_BLACKLISTED_PATHS...)),
}
assert.Equal(t, expectedConfig, cfg)
@@ -332,7 +332,7 @@ func TestMergeServerConfigShouldReplaceOnlyOneValueExistingValueGivenOnlyOneArgE
{args: []string{"--enable-http-server"}, callback: func(sc *ServerConfig) { sc.HttpServerEnabled = true }},
{args: []string{"--pages-domain", "changed"}, callback: func(sc *ServerConfig) { sc.MainDomain = "changed" }},
{args: []string{"--raw-domain", "changed"}, callback: func(sc *ServerConfig) { sc.RawDomain = "changed" }},
- {args: []string{"--canonical-domain-file", "changed"}, callback: func(sc *ServerConfig) { sc.CanonicalDomainFile = "changed" }},
+ {args: []string{"--canonical-domain-file", "changed"}, callback: func(sc *ServerConfig) { sc.CanonicalDomainFiles = []string{"changed"} }},
{args: []string{"--pages-branch", "changed"}, callback: func(sc *ServerConfig) { sc.PagesBranches = []string{"changed"} }},
{args: []string{"--allowed-cors-domains", "changed"}, callback: func(sc *ServerConfig) { sc.AllowedCorsDomains = []string{"changed"} }},
{args: []string{"--blacklisted-paths", "changed"}, callback: func(sc *ServerConfig) { sc.BlacklistedPaths = []string{"changed"} }},
@@ -343,22 +343,23 @@ func TestMergeServerConfigShouldReplaceOnlyOneValueExistingValueGivenOnlyOneArgE
t,
func(ctx *cli.Context) error {
cfg := ServerConfig{
- Host: "original",
- Port: 8080,
- HttpPort: 80,
- HttpServerEnabled: false,
- MainDomain: "original",
- RawDomain: "original",
- CanonicalDomainFile: "original",
- PagesBranches: []string{"original"},
- AllowedCorsDomains: []string{"original"},
- BlacklistedPaths: []string{"original"},
+ Host: "original",
+ Port: 8080,
+ HttpPort: 80,
+ HttpServerEnabled: false,
+ MainDomain: "original",
+ RawDomain: "original",
+ CanonicalDomainFiles: []string{"original"},
+ PagesBranches: []string{"original"},
+ AllowedCorsDomains: []string{"original"},
+ BlacklistedPaths: []string{"original"},
}
expectedConfig := cfg
pair.callback(&expectedConfig)
expectedConfig.BlacklistedPaths = append(expectedConfig.BlacklistedPaths, ALWAYS_BLACKLISTED_PATHS...)
+ expectedConfig.CanonicalDomainFiles = fixArrayFromCtx(ctx, "canonical-domain-file", expectedConfig.CanonicalDomainFiles)
expectedConfig.PagesBranches = fixArrayFromCtx(ctx, "pages-branch", expectedConfig.PagesBranches)
expectedConfig.AllowedCorsDomains = fixArrayFromCtx(ctx, "allowed-cors-domains", expectedConfig.AllowedCorsDomains)
expectedConfig.BlacklistedPaths = fixArrayFromCtx(ctx, "blacklisted-paths", expectedConfig.BlacklistedPaths)
diff --git a/server/certificates/certificates.go b/server/certificates/certificates.go
index aa368de..2386609 100644
--- a/server/certificates/certificates.go
+++ b/server/certificates/certificates.go
@@ -32,7 +32,7 @@ func TLSConfig(mainDomainSuffix string,
giteaClient *gitea.Client,
acmeClient *AcmeClient,
firstDefaultBranch string,
- canonicalDomainConfig string,
+ canonicalDomainConfigs []string,
challengeCache, canonicalDomainCache cache.ICache,
certDB database.CertDB,
noDNS01 bool,
@@ -101,10 +101,10 @@ func TLSConfig(mainDomainSuffix string,
TargetRepo: targetRepo,
TargetBranch: targetBranch,
}
- _, valid := targetOpt.CheckCanonicalDomain(giteaClient, domain, mainDomainSuffix, canonicalDomainConfig, canonicalDomainCache)
+ _, valid := targetOpt.CheckCanonicalDomain(giteaClient, domain, mainDomainSuffix, canonicalDomainConfigs, canonicalDomainCache)
if !valid {
// We shouldn't obtain a certificate when we cannot check if the
- // repository has specified this domain in the `.domains` file.
+ // repository has specified this domain in the specified canonical domain file such as the `.domains` file.
mayObtainCert = false
}
}
diff --git a/server/handler/handler.go b/server/handler/handler.go
index 22325ec..fdc47a5 100644
--- a/server/handler/handler.go
+++ b/server/handler/handler.go
@@ -92,7 +92,7 @@ func Handler(
cfg.MainDomain,
trimmedHost,
pathElements,
- cfg.CanonicalDomainFile,
+ cfg.CanonicalDomainFiles,
canonicalDomainCache, redirectsCache)
} else if strings.HasSuffix(trimmedHost, cfg.MainDomain) {
log.Debug().Msg("subdomain request detected")
@@ -101,7 +101,7 @@ func Handler(
cfg.PagesBranches,
trimmedHost,
pathElements,
- cfg.CanonicalDomainFile,
+ cfg.CanonicalDomainFiles,
canonicalDomainCache, redirectsCache)
} else {
log.Debug().Msg("custom domain request detected")
@@ -110,7 +110,7 @@ func Handler(
trimmedHost,
pathElements,
cfg.PagesBranches[0],
- cfg.CanonicalDomainFile,
+ cfg.CanonicalDomainFiles,
canonicalDomainCache, redirectsCache)
}
}
diff --git a/server/handler/handler_custom_domain.go b/server/handler/handler_custom_domain.go
index a655b9b..3776fb8 100644
--- a/server/handler/handler_custom_domain.go
+++ b/server/handler/handler_custom_domain.go
@@ -1,6 +1,7 @@
package handler
import (
+ "fmt"
"net/http"
"path"
"strings"
@@ -19,7 +20,7 @@ func handleCustomDomain(log zerolog.Logger, ctx *context.Context, giteaClient *g
trimmedHost string,
pathElements []string,
firstDefaultBranch string,
- canonicalDomainConfig string,
+ canonicalDomainConfigs []string,
canonicalDomainCache, redirectsCache cache.ICache,
) {
// Serve pages from custom domains
@@ -48,9 +49,10 @@ func handleCustomDomain(log zerolog.Logger, ctx *context.Context, giteaClient *g
TargetBranch: targetBranch,
TargetPath: path.Join(pathParts...),
}, canonicalLink); works {
- canonicalDomain, valid := targetOpt.CheckCanonicalDomain(giteaClient, trimmedHost, mainDomainSuffix, canonicalDomainConfig, canonicalDomainCache)
+ canonicalDomain, valid := targetOpt.CheckCanonicalDomain(giteaClient, trimmedHost, mainDomainSuffix, canonicalDomainConfigs, canonicalDomainCache)
if !valid {
- html.ReturnErrorPage(ctx, "domain not specified in .domains
file", http.StatusMisdirectedRequest)
+ msg := fmt.Sprintf("canonical domain not specified, files checked: %s
", strings.Join(canonicalDomainConfigs, ", "))
+ html.ReturnErrorPage(ctx, msg, http.StatusMisdirectedRequest)
return
} else if canonicalDomain != trimmedHost {
// only redirect if the target is also a codeberg page!
@@ -65,7 +67,7 @@ func handleCustomDomain(log zerolog.Logger, ctx *context.Context, giteaClient *g
}
log.Debug().Msg("tryBranch, now trying upstream 7")
- tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfig, canonicalDomainCache, redirectsCache)
+ tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfigs, canonicalDomainCache, redirectsCache)
return
}
diff --git a/server/handler/handler_raw_domain.go b/server/handler/handler_raw_domain.go
index 1aba584..279e7a7 100644
--- a/server/handler/handler_raw_domain.go
+++ b/server/handler/handler_raw_domain.go
@@ -19,7 +19,7 @@ func handleRaw(log zerolog.Logger, ctx *context.Context, giteaClient *gitea.Clie
mainDomainSuffix string,
trimmedHost string,
pathElements []string,
- canonicalDomainConfig string,
+ canonicalDomainConfigs []string,
canonicalDomainCache, redirectsCache cache.ICache,
) {
// Serve raw content from RawDomain
@@ -46,7 +46,7 @@ func handleRaw(log zerolog.Logger, ctx *context.Context, giteaClient *gitea.Clie
TargetPath: path.Join(pathElements[3:]...),
}, true); works {
log.Trace().Msg("tryUpstream: serve raw domain with specified branch")
- tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfig, canonicalDomainCache, redirectsCache)
+ tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfigs, canonicalDomainCache, redirectsCache)
return
}
log.Debug().Msg("missing branch info")
@@ -63,7 +63,7 @@ func handleRaw(log zerolog.Logger, ctx *context.Context, giteaClient *gitea.Clie
TargetPath: path.Join(pathElements[2:]...),
}, true); works {
log.Trace().Msg("tryUpstream: serve raw domain with default branch")
- tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfig, canonicalDomainCache, redirectsCache)
+ tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfigs, canonicalDomainCache, redirectsCache)
} else {
html.ReturnErrorPage(ctx,
fmt.Sprintf("raw domain could not find repo %s/%s
or repo is empty", targetOpt.TargetOwner, targetOpt.TargetRepo),
diff --git a/server/handler/handler_sub_domain.go b/server/handler/handler_sub_domain.go
index 9a19e81..571a6e0 100644
--- a/server/handler/handler_sub_domain.go
+++ b/server/handler/handler_sub_domain.go
@@ -21,7 +21,7 @@ func handleSubDomain(log zerolog.Logger, ctx *context.Context, giteaClient *gite
defaultPagesBranches []string,
trimmedHost string,
pathElements []string,
- canonicalDomainConfig string,
+ canonicalDomainConfigs []string,
canonicalDomainCache, redirectsCache cache.ICache,
) {
// Serve pages from subdomains of MainDomainSuffix
@@ -54,7 +54,7 @@ func handleSubDomain(log zerolog.Logger, ctx *context.Context, giteaClient *gite
TargetPath: path.Join(pathElements[2:]...),
}, true); works {
log.Trace().Msg("tryUpstream: serve with specified repo and branch")
- tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfig, canonicalDomainCache, redirectsCache)
+ tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfigs, canonicalDomainCache, redirectsCache)
} else {
html.ReturnErrorPage(
ctx,
@@ -86,7 +86,7 @@ func handleSubDomain(log zerolog.Logger, ctx *context.Context, giteaClient *gite
TargetPath: path.Join(pathElements[1:]...),
}, true); works {
log.Trace().Msg("tryUpstream: serve default pages repo with specified branch")
- tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfig, canonicalDomainCache, redirectsCache)
+ tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfigs, canonicalDomainCache, redirectsCache)
} else {
html.ReturnErrorPage(
ctx,
@@ -111,7 +111,7 @@ func handleSubDomain(log zerolog.Logger, ctx *context.Context, giteaClient *gite
TargetPath: path.Join(pathElements[1:]...),
}, false); works {
log.Debug().Msg("tryBranch, now trying upstream 5")
- tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfig, canonicalDomainCache, redirectsCache)
+ tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfigs, canonicalDomainCache, redirectsCache)
return
}
}
@@ -127,7 +127,7 @@ func handleSubDomain(log zerolog.Logger, ctx *context.Context, giteaClient *gite
TargetPath: path.Join(pathElements...),
}, false); works {
log.Debug().Msg("tryBranch, now trying upstream 6")
- tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfig, canonicalDomainCache, redirectsCache)
+ tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfigs, canonicalDomainCache, redirectsCache)
return
}
}
@@ -142,7 +142,7 @@ func handleSubDomain(log zerolog.Logger, ctx *context.Context, giteaClient *gite
TargetPath: path.Join(pathElements...),
}, false); works {
log.Debug().Msg("tryBranch, now trying upstream 6")
- tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfig, canonicalDomainCache, redirectsCache)
+ tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfigs, canonicalDomainCache, redirectsCache)
return
}
diff --git a/server/handler/try.go b/server/handler/try.go
index 8cdf3e9..87c30b7 100644
--- a/server/handler/try.go
+++ b/server/handler/try.go
@@ -18,13 +18,13 @@ import (
func tryUpstream(ctx *context.Context, giteaClient *gitea.Client,
mainDomainSuffix, trimmedHost string,
options *upstream.Options,
- canonicalDomainConfig string,
+ canonicalDomainConfigs []string,
canonicalDomainCache cache.ICache,
redirectsCache cache.ICache,
) {
// check if a canonical domain exists on a request on MainDomain
if strings.HasSuffix(trimmedHost, mainDomainSuffix) && !options.ServeRaw {
- canonicalDomain, _ := options.CheckCanonicalDomain(giteaClient, "", mainDomainSuffix, canonicalDomainConfig, canonicalDomainCache)
+ canonicalDomain, _ := options.CheckCanonicalDomain(giteaClient, "", mainDomainSuffix, canonicalDomainConfigs, canonicalDomainCache)
if !strings.HasSuffix(strings.SplitN(canonicalDomain, "/", 2)[0], mainDomainSuffix) {
canonicalPath := ctx.Req.RequestURI
if options.TargetRepo != defaultPagesRepo {
diff --git a/server/startup.go b/server/startup.go
index eab847a..b7b5717 100644
--- a/server/startup.go
+++ b/server/startup.go
@@ -101,7 +101,7 @@ func Serve(ctx *cli.Context) error {
giteaClient,
acmeClient,
cfg.Server.PagesBranches[0],
- cfg.Server.CanonicalDomainFile,
+ cfg.Server.CanonicalDomainFiles,
challengeCache, canonicalDomainCache,
certDB,
cfg.ACME.NoDNS01,
diff --git a/server/upstream/domains.go b/server/upstream/domains.go
index b5d93fc..1200320 100644
--- a/server/upstream/domains.go
+++ b/server/upstream/domains.go
@@ -15,56 +15,91 @@ import (
var canonicalDomainCacheTimeout = 15 * time.Minute
// CheckCanonicalDomain returns the canonical domain specified in the repo (using the `.domains` file).
-func (o *Options) CheckCanonicalDomain(giteaClient *gitea.Client, actualDomain, mainDomainSuffix, canonicalDomainConfig string, canonicalDomainCache cache.ICache) (domain string, valid bool) {
- canonicalDomainCacheKey := o.TargetOwner + "/" + o.TargetRepo + "/" + o.TargetBranch + "/" + canonicalDomainConfig
+func (o *Options) CheckCanonicalDomain(giteaClient *gitea.Client, actualDomain, mainDomainSuffix string, canonicalDomainConfigs []string, canonicalDomainCache cache.ICache) (domain string, valid bool) {
+ canonicalDomainCacheKey := o.TargetOwner + "/" + o.TargetRepo + "/" + o.TargetBranch + "/(" + strings.Join(canonicalDomainConfigs, "|") + ")"
+
+ var domains []string
// Check if this request is cached.
if cachedValue, ok := canonicalDomainCache.Get(canonicalDomainCacheKey); ok {
- domains := cachedValue.([]string)
- for _, domain := range domains {
- if domain == actualDomain {
- valid = true
- break
- }
- }
- return domains[0], valid
+ domains = cachedValue.([]string)
+ } else {
+ // Create cache entry for future invocations.
+ domains = o.canonicalDomainList(giteaClient, mainDomainSuffix, canonicalDomainConfigs)
+
+ // Add result to cache.
+ _ = canonicalDomainCache.Set(canonicalDomainCacheKey, domains, canonicalDomainCacheTimeout)
}
- body, err := giteaClient.GiteaRawContent(o.TargetOwner, o.TargetRepo, o.TargetBranch, canonicalDomainConfig)
- if err != nil && !errors.Is(err, gitea.ErrorNotFound) {
- log.Error().Err(err).Msgf("could not read %s of %s/%s", canonicalDomainConfig, o.TargetOwner, o.TargetRepo)
- }
-
- var domains []string
- for _, domain := range strings.Split(string(body), "\n") {
- domain = strings.ToLower(domain)
- domain = strings.TrimSpace(domain)
- domain = strings.TrimPrefix(domain, "http://")
- domain = strings.TrimPrefix(domain, "https://")
- if domain != "" && !strings.HasPrefix(domain, "#") && !strings.ContainsAny(domain, "\t /") && strings.ContainsRune(domain, '.') {
- domains = append(domains, domain)
- }
+ for _, domain := range domains {
if domain == actualDomain {
valid = true
+ break
}
}
- // Add [owner].[pages-domain] as valid domain.
- domains = append(domains, o.TargetOwner+mainDomainSuffix)
- if domains[len(domains)-1] == actualDomain {
- valid = true
- }
-
- // If the target repository isn't called pages, add `/[repository]` to the
- // previous valid domain.
- if o.TargetRepo != "" && o.TargetRepo != "pages" {
- domains[len(domains)-1] += "/" + o.TargetRepo
- }
-
- // Add result to cache.
- _ = canonicalDomainCache.Set(canonicalDomainCacheKey, domains, canonicalDomainCacheTimeout)
-
// Return the first domain from the list and return if any of the domains
// matched the requested domain.
return domains[0], valid
}
+
+// canonicalDomainList returns a list of normalized canonical domains as reported by the repository being served.
+func (o *Options) canonicalDomainList(giteaClient *gitea.Client, mainDomainSuffix string, canonicalDomainConfigs []string) []string {
+ domainConfigMerge := ""
+
+ for _, canonicalDomainConfig := range canonicalDomainConfigs {
+ body, err := giteaClient.GiteaRawContent(o.TargetOwner, o.TargetRepo, o.TargetBranch, canonicalDomainConfig)
+ if err != nil && !errors.Is(err, gitea.ErrorNotFound) {
+ log.Error().Err(err).Msgf("could not read %s of %s/%s", canonicalDomainConfig, o.TargetOwner, o.TargetRepo)
+ continue
+ }
+
+ // Ensures files that don't end with a `\n` don't cause domains to be concatenated when combining files.
+ domainConfigMerge = domainConfigMerge + "\n" + string(body)
+ }
+
+ domains := normalizeDomainEntries(domainConfigMerge)
+
+ // Add [owner].[pages-domain] as valid domain.
+ domains = append(domains, o.pageMainDomain(mainDomainSuffix))
+
+ return domains
+}
+
+// pageMainDomain returns the [owner].[pages-domain] domain.
+func (o *Options) pageMainDomain(mainDomainSuffix string) string {
+ pageMainDomain := o.TargetOwner + mainDomainSuffix
+
+ // If the target repository isn't called pages, add `/[repository]` to the
+ // previous valid domain.
+ if o.TargetRepo != "" && o.TargetRepo != "pages" {
+ pageMainDomain += "/" + o.TargetRepo
+ }
+
+ return pageMainDomain
+}
+
+// normalizeDomainEntries returns a list of domains, ill formatted domains are skipped.
+// domainEntries is a new-line separated list of domains.
+func normalizeDomainEntries(domainEntries string) []string {
+ domains := []string{}
+
+ for _, domain := range strings.Split(domainEntries, "\n") {
+ domain = strings.ToLower(domain)
+ domain = strings.TrimSpace(domain)
+ domain = strings.TrimPrefix(domain, "http://")
+ domain = strings.TrimPrefix(domain, "https://")
+
+ // Skip blank lines.
+ // Skip commented lines.
+ // Skip poorly formatted lines.
+ // Skip domains without '.'.
+ if domain == "" || strings.HasPrefix(domain, "#") || strings.ContainsAny(domain, "\t /") || !strings.ContainsRune(domain, '.') {
+ continue
+ }
+
+ domains = append(domains, domain)
+ }
+
+ return domains
+}
diff --git a/server/upstream/domains_test.go b/server/upstream/domains_test.go
new file mode 100644
index 0000000..8956ad1
--- /dev/null
+++ b/server/upstream/domains_test.go
@@ -0,0 +1,75 @@
+package upstream
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestPageMainDomainGeneratesTheExpectedDomain(t *testing.T) {
+ defaultOptions := Options{
+ TargetOwner: "",
+ TargetRepo: "",
+ TargetBranch: "",
+ TargetPath: "",
+ Host: "",
+ TryIndexPages: false,
+ BranchTimestamp: time.Time{},
+ appendTrailingSlash: false,
+ redirectIfExists: "",
+ ServeRaw: false,
+ }
+
+ for _, tc := range []struct {
+ targetOwner string
+ targetRepo string
+ domainSuffix string
+ expectedDomain string
+ }{
+ {"foo", "", ".localhost.mock.directory", "foo.localhost.mock.directory"},
+ {"foo", "pages", ".localhost.mock.directory", "foo.localhost.mock.directory"},
+ {"foo", "bar", ".localhost.mock.directory", "foo.localhost.mock.directory/bar"},
+ } {
+ options := defaultOptions
+ options.TargetOwner = tc.targetOwner
+ options.TargetRepo = tc.targetRepo
+
+ actualDomain := options.pageMainDomain(tc.domainSuffix)
+
+ assert.Equal(t, tc.expectedDomain, actualDomain)
+ }
+}
+
+func TestNormalizeDomainEntries(t *testing.T) {
+ for _, tc := range []struct {
+ domain string
+ }{
+ {"abc.com"},
+ {"ABC.com"},
+ {" ABC.com"},
+ {"ABC.com "},
+ {" ABC.com "},
+ {"http://ABC.com"},
+ {"https://ABC.com"},
+ } {
+ actualDomains := normalizeDomainEntries(tc.domain)
+ expectedDomains := []string{"abc.com"}
+
+ assert.Equal(t, expectedDomains, actualDomains)
+ }
+
+ for _, tc := range []struct {
+ domains string
+ expectedDomains []string
+ }{
+ {"", []string{}},
+ {"ABC.com", []string{"abc.com"}},
+ {"ABC.com\nhttps://example.com", []string{"abc.com", "example.com"}},
+ {"\n\nABC.com\n\nhttps://example.com\n", []string{"abc.com", "example.com"}},
+ } {
+ actualDomains := normalizeDomainEntries(tc.domains)
+
+ assert.Equal(t, tc.expectedDomains, actualDomains)
+ }
+}