From 66c56dcf8290c407681caae66654cfc7bb889505 Mon Sep 17 00:00:00 2001
From: 6543 <6543@obermui.de>
Date: Sat, 12 Nov 2022 19:57:37 +0100
Subject: [PATCH] split
---
server/context/context.go | 6 +
server/handler/handler.go | 219 ++----------------------
server/handler/handler_custom_domain.go | 71 ++++++++
server/handler/handler_raw_domain.go | 67 ++++++++
server/handler/handler_sub_domain.go | 120 +++++++++++++
5 files changed, 283 insertions(+), 200 deletions(-)
create mode 100644 server/handler/handler_custom_domain.go
create mode 100644 server/handler/handler_raw_domain.go
create mode 100644 server/handler/handler_sub_domain.go
diff --git a/server/context/context.go b/server/context/context.go
index 14a3972..481fee2 100644
--- a/server/context/context.go
+++ b/server/context/context.go
@@ -3,6 +3,8 @@ package context
import (
stdContext "context"
"net/http"
+
+ "codeberg.org/codeberg/pages/server/utils"
)
type Context struct {
@@ -56,3 +58,7 @@ func (c *Context) Path() string {
func (c *Context) Host() string {
return c.Req.URL.Host
}
+
+func (c *Context) TrimHostPort() string {
+ return utils.TrimHostPort(c.Req.Host)
+}
diff --git a/server/handler/handler.go b/server/handler/handler.go
index d81a364..b42751e 100644
--- a/server/handler/handler.go
+++ b/server/handler/handler.go
@@ -1,9 +1,7 @@
package handler
import (
- "fmt"
"net/http"
- "path"
"strings"
"github.com/rs/zerolog/log"
@@ -11,10 +9,7 @@ import (
"codeberg.org/codeberg/pages/html"
"codeberg.org/codeberg/pages/server/cache"
"codeberg.org/codeberg/pages/server/context"
- "codeberg.org/codeberg/pages/server/dns"
"codeberg.org/codeberg/pages/server/gitea"
- "codeberg.org/codeberg/pages/server/upstream"
- "codeberg.org/codeberg/pages/server/utils"
"codeberg.org/codeberg/pages/server/version"
)
@@ -42,7 +37,7 @@ func Handler(mainDomainSuffix, rawDomain string,
// Enable browser caching for up to 10 minutes
ctx.RespWriter.Header().Set("Cache-Control", "public, max-age=600")
- trimmedHost := utils.TrimHostPort(req.Host)
+ trimmedHost := ctx.TrimHostPort()
// Add HSTS for RawDomain and MainDomainSuffix
if hsts := getHSTSHeader(trimmedHost, mainDomainSuffix, rawDomain); hsts != "" {
@@ -90,203 +85,27 @@ func Handler(mainDomainSuffix, rawDomain string,
// Prepare request information to Gitea
pathElements := strings.Split(strings.Trim(ctx.Path(), "/"), "/")
- log.Debug().Msg("preparations")
if rawDomain != "" && strings.EqualFold(trimmedHost, rawDomain) {
- // Serve raw content from RawDomain
- log.Debug().Msg("raw domain")
-
- if len(pathElements) < 2 {
- // https://{RawDomain}/{owner}/{repo}[/@{branch}]/{path} is required
- ctx.Redirect(rawInfoPage, http.StatusTemporaryRedirect)
- return
- }
-
- // raw.codeberg.org/example/myrepo/@main/index.html
- if len(pathElements) > 2 && strings.HasPrefix(pathElements[2], "@") {
- log.Debug().Msg("raw domain preparations, now trying with specified branch")
- if targetOpt, works := tryBranch(log, ctx, giteaClient, &upstream.Options{
- ServeRaw: true,
- TargetOwner: pathElements[0],
- TargetRepo: pathElements[1],
- TargetBranch: pathElements[2][1:],
- TargetPath: path.Join(pathElements[3:]...),
- }, true); works {
- log.Trace().Msg("tryUpstream: serve raw domain with specified branch")
- tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache)
- return
- }
- log.Debug().Msg("missing branch info")
- html.ReturnErrorPage(ctx, "missing branch info", http.StatusFailedDependency)
- return
- }
-
- log.Debug().Msg("raw domain preparations, now trying with default branch")
- if targetOpt, works := tryBranch(log, ctx, giteaClient, &upstream.Options{
- TryIndexPages: false,
- ServeRaw: true,
- TargetOwner: pathElements[0],
- TargetRepo: pathElements[1],
- TargetPath: path.Join(pathElements[2:]...),
- }, true); works {
- log.Trace().Msg("tryUpstream: serve raw domain with default branch")
- tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache)
- } else {
- html.ReturnErrorPage(ctx,
- fmt.Sprintf("raw domain could not find repo '%s/%s' or repo is empty", targetOpt.TargetOwner, targetOpt.TargetRepo),
- http.StatusNotFound)
- }
- return
-
+ log.Debug().Msg("raw domain request detecded")
+ handleRaw(log, ctx, giteaClient,
+ mainDomainSuffix, rawInfoPage,
+ trimmedHost,
+ pathElements,
+ canonicalDomainCache)
} else if strings.HasSuffix(trimmedHost, mainDomainSuffix) {
- // Serve pages from subdomains of MainDomainSuffix
- log.Debug().Msg("main domain suffix")
-
- targetOwner := strings.TrimSuffix(trimmedHost, mainDomainSuffix)
- targetRepo := pathElements[0]
-
- if targetOwner == "www" {
- // www.codeberg.page redirects to codeberg.page // TODO: rm hardcoded - use cname?
- ctx.Redirect("https://"+string(mainDomainSuffix[1:])+string(ctx.Path()), http.StatusPermanentRedirect)
- return
- }
-
- // Check if the first directory is a repo with the second directory as a branch
- // example.codeberg.page/myrepo/@main/index.html
- if len(pathElements) > 1 && strings.HasPrefix(pathElements[1], "@") {
- if targetRepo == "pages" {
- // example.codeberg.org/pages/@... redirects to example.codeberg.org/@...
- ctx.Redirect("/"+strings.Join(pathElements[1:], "/"), http.StatusTemporaryRedirect)
- return
- }
-
- log.Debug().Msg("main domain preparations, now trying with specified repo & branch")
- if targetOpt, works := tryBranch(log, ctx, giteaClient, &upstream.Options{
- TryIndexPages: true,
- TargetOwner: targetOwner,
- TargetRepo: pathElements[0],
- TargetBranch: pathElements[1][1:],
- TargetPath: path.Join(pathElements[2:]...),
- }, true); works {
- log.Trace().Msg("tryUpstream: serve with specified repo and branch")
- tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache)
- } else {
- html.ReturnErrorPage(ctx,
- fmt.Sprintf("explizite set branch %q do not exist at '%s/%s'", targetOpt.TargetBranch, targetOpt.TargetOwner, targetOpt.TargetRepo),
- http.StatusFailedDependency)
- }
- return
- }
-
- // Check if the first directory is a branch for the "pages" repo
- // example.codeberg.page/@main/index.html
- if strings.HasPrefix(pathElements[0], "@") {
- log.Debug().Msg("main domain preparations, now trying with specified branch")
- if targetOpt, works := tryBranch(log, ctx, giteaClient, &upstream.Options{
- TryIndexPages: true,
- TargetOwner: targetOwner,
- TargetRepo: "pages",
- TargetBranch: pathElements[0][1:],
- TargetPath: path.Join(pathElements[1:]...),
- }, true); works {
- log.Trace().Msg("tryUpstream: serve default pages repo with specified branch")
- tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache)
- } else {
- html.ReturnErrorPage(ctx,
- fmt.Sprintf("explizite set branch %q do not exist at '%s/%s'", targetOpt.TargetBranch, targetOpt.TargetOwner, targetOpt.TargetRepo),
- http.StatusFailedDependency)
- }
- return
- }
-
- // Check if the first directory is a repo with a "pages" branch
- // example.codeberg.page/myrepo/index.html
- // example.codeberg.page/pages/... is not allowed here.
- log.Debug().Msg("main domain preparations, now trying with specified repo")
- if pathElements[0] != "pages" {
- if targetOpt, works := tryBranch(log, ctx, giteaClient, &upstream.Options{
- TryIndexPages: true,
- TargetOwner: targetOwner,
- TargetRepo: pathElements[0],
- TargetBranch: "pages",
- TargetPath: path.Join(pathElements[1:]...),
- }, false); works {
- log.Debug().Msg("tryBranch, now trying upstream 5")
- tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache)
- return
- }
- }
-
- // Try to use the "pages" repo on its default branch
- // example.codeberg.page/index.html
- log.Debug().Msg("main domain preparations, now trying with default repo/branch")
- if targetOpt, works := tryBranch(log, ctx, giteaClient, &upstream.Options{
- TryIndexPages: true,
- TargetOwner: targetOwner,
- TargetRepo: "pages",
- TargetPath: path.Join(pathElements...),
- }, false); works {
- log.Debug().Msg("tryBranch, now trying upstream 6")
- tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache)
- return
- }
-
- // Couldn't find a valid repo/branch
- html.ReturnErrorPage(ctx,
- fmt.Sprintf("couldn't find a valid repo[%s]", targetRepo),
- http.StatusFailedDependency)
- return
+ log.Debug().Msg("subdomain request detecded")
+ handleSubDomain(log, ctx, giteaClient,
+ mainDomainSuffix,
+ trimmedHost,
+ pathElements,
+ canonicalDomainCache)
} else {
- trimmedHostStr := string(trimmedHost)
-
- // Serve pages from custom domains
- targetOwner, targetRepo, targetBranch := dns.GetTargetFromDNS(trimmedHostStr, string(mainDomainSuffix), dnsLookupCache)
- if targetOwner == "" {
- html.ReturnErrorPage(ctx,
- "could not obtain repo owner from custom domain",
- http.StatusFailedDependency)
- return
- }
-
- pathParts := pathElements
- canonicalLink := false
- if strings.HasPrefix(pathElements[0], "@") {
- targetBranch = pathElements[0][1:]
- pathParts = pathElements[1:]
- canonicalLink = true
- }
-
- // Try to use the given repo on the given branch or the default branch
- log.Debug().Msg("custom domain preparations, now trying with details from DNS")
- if targetOpt, works := tryBranch(log, ctx, giteaClient, &upstream.Options{
- TryIndexPages: true,
- TargetOwner: targetOwner,
- TargetRepo: targetRepo,
- TargetBranch: targetBranch,
- TargetPath: path.Join(pathParts...),
- }, canonicalLink); works {
- canonicalDomain, valid := targetOpt.CheckCanonicalDomain(giteaClient, trimmedHostStr, string(mainDomainSuffix), canonicalDomainCache)
- if !valid {
- html.ReturnErrorPage(ctx, "domain not specified in .domains
file", http.StatusMisdirectedRequest)
- return
- } else if canonicalDomain != trimmedHostStr {
- // only redirect if the target is also a codeberg page!
- targetOwner, _, _ = dns.GetTargetFromDNS(strings.SplitN(canonicalDomain, "/", 2)[0], string(mainDomainSuffix), dnsLookupCache)
- if targetOwner != "" {
- ctx.Redirect("https://"+canonicalDomain+string(targetOpt.TargetPath), http.StatusTemporaryRedirect)
- return
- }
-
- html.ReturnErrorPage(ctx, "target is no codeberg page", http.StatusFailedDependency)
- return
- }
-
- log.Debug().Msg("tryBranch, now trying upstream 7")
- tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache)
- return
- }
-
- html.ReturnErrorPage(ctx, "could not find target for custom domain", http.StatusFailedDependency)
- return
+ log.Debug().Msg("custom domain request detecded")
+ handleCustomDomain(log, ctx, giteaClient,
+ mainDomainSuffix,
+ trimmedHost,
+ pathElements,
+ dnsLookupCache, canonicalDomainCache)
}
}
}
diff --git a/server/handler/handler_custom_domain.go b/server/handler/handler_custom_domain.go
new file mode 100644
index 0000000..bec3b46
--- /dev/null
+++ b/server/handler/handler_custom_domain.go
@@ -0,0 +1,71 @@
+package handler
+
+import (
+ "net/http"
+ "path"
+ "strings"
+
+ "codeberg.org/codeberg/pages/html"
+ "codeberg.org/codeberg/pages/server/cache"
+ "codeberg.org/codeberg/pages/server/context"
+ "codeberg.org/codeberg/pages/server/dns"
+ "codeberg.org/codeberg/pages/server/gitea"
+ "codeberg.org/codeberg/pages/server/upstream"
+ "github.com/rs/zerolog"
+)
+
+func handleCustomDomain(log zerolog.Logger, ctx *context.Context, giteaClient *gitea.Client,
+ mainDomainSuffix string,
+ trimmedHost string,
+ pathElements []string,
+ dnsLookupCache, canonicalDomainCache cache.SetGetKey,
+) {
+ // Serve pages from custom domains
+ targetOwner, targetRepo, targetBranch := dns.GetTargetFromDNS(trimmedHost, string(mainDomainSuffix), dnsLookupCache)
+ if targetOwner == "" {
+ html.ReturnErrorPage(ctx,
+ "could not obtain repo owner from custom domain",
+ http.StatusFailedDependency)
+ return
+ }
+
+ pathParts := pathElements
+ canonicalLink := false
+ if strings.HasPrefix(pathElements[0], "@") {
+ targetBranch = pathElements[0][1:]
+ pathParts = pathElements[1:]
+ canonicalLink = true
+ }
+
+ // Try to use the given repo on the given branch or the default branch
+ log.Debug().Msg("custom domain preparations, now trying with details from DNS")
+ if targetOpt, works := tryBranch(log, ctx, giteaClient, &upstream.Options{
+ TryIndexPages: true,
+ TargetOwner: targetOwner,
+ TargetRepo: targetRepo,
+ TargetBranch: targetBranch,
+ TargetPath: path.Join(pathParts...),
+ }, canonicalLink); works {
+ canonicalDomain, valid := targetOpt.CheckCanonicalDomain(giteaClient, trimmedHost, string(mainDomainSuffix), canonicalDomainCache)
+ if !valid {
+ html.ReturnErrorPage(ctx, "domain not specified in .domains
file", http.StatusMisdirectedRequest)
+ return
+ } else if canonicalDomain != trimmedHost {
+ // only redirect if the target is also a codeberg page!
+ targetOwner, _, _ = dns.GetTargetFromDNS(strings.SplitN(canonicalDomain, "/", 2)[0], string(mainDomainSuffix), dnsLookupCache)
+ if targetOwner != "" {
+ ctx.Redirect("https://"+canonicalDomain+string(targetOpt.TargetPath), http.StatusTemporaryRedirect)
+ return
+ }
+
+ html.ReturnErrorPage(ctx, "target is no codeberg page", http.StatusFailedDependency)
+ return
+ }
+
+ log.Debug().Msg("tryBranch, now trying upstream 7")
+ tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache)
+ return
+ }
+
+ html.ReturnErrorPage(ctx, "could not find target for custom domain", http.StatusFailedDependency)
+}
diff --git a/server/handler/handler_raw_domain.go b/server/handler/handler_raw_domain.go
new file mode 100644
index 0000000..5e974da
--- /dev/null
+++ b/server/handler/handler_raw_domain.go
@@ -0,0 +1,67 @@
+package handler
+
+import (
+ "fmt"
+ "net/http"
+ "path"
+ "strings"
+
+ "github.com/rs/zerolog"
+
+ "codeberg.org/codeberg/pages/html"
+ "codeberg.org/codeberg/pages/server/cache"
+ "codeberg.org/codeberg/pages/server/context"
+ "codeberg.org/codeberg/pages/server/gitea"
+ "codeberg.org/codeberg/pages/server/upstream"
+)
+
+func handleRaw(log zerolog.Logger, ctx *context.Context, giteaClient *gitea.Client,
+ mainDomainSuffix, rawInfoPage string,
+ trimmedHost string,
+ pathElements []string,
+ canonicalDomainCache cache.SetGetKey,
+) {
+ // Serve raw content from RawDomain
+ log.Debug().Msg("raw domain")
+
+ if len(pathElements) < 2 {
+ // https://{RawDomain}/{owner}/{repo}[/@{branch}]/{path} is required
+ ctx.Redirect(rawInfoPage, http.StatusTemporaryRedirect)
+ return
+ }
+
+ // raw.codeberg.org/example/myrepo/@main/index.html
+ if len(pathElements) > 2 && strings.HasPrefix(pathElements[2], "@") {
+ log.Debug().Msg("raw domain preparations, now trying with specified branch")
+ if targetOpt, works := tryBranch(log, ctx, giteaClient, &upstream.Options{
+ ServeRaw: true,
+ TargetOwner: pathElements[0],
+ TargetRepo: pathElements[1],
+ TargetBranch: pathElements[2][1:],
+ TargetPath: path.Join(pathElements[3:]...),
+ }, true); works {
+ log.Trace().Msg("tryUpstream: serve raw domain with specified branch")
+ tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache)
+ return
+ }
+ log.Debug().Msg("missing branch info")
+ html.ReturnErrorPage(ctx, "missing branch info", http.StatusFailedDependency)
+ return
+ }
+
+ log.Debug().Msg("raw domain preparations, now trying with default branch")
+ if targetOpt, works := tryBranch(log, ctx, giteaClient, &upstream.Options{
+ TryIndexPages: false,
+ ServeRaw: true,
+ TargetOwner: pathElements[0],
+ TargetRepo: pathElements[1],
+ TargetPath: path.Join(pathElements[2:]...),
+ }, true); works {
+ log.Trace().Msg("tryUpstream: serve raw domain with default branch")
+ tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache)
+ } else {
+ html.ReturnErrorPage(ctx,
+ fmt.Sprintf("raw domain could not find repo '%s/%s' or repo is empty", targetOpt.TargetOwner, targetOpt.TargetRepo),
+ http.StatusNotFound)
+ }
+}
diff --git a/server/handler/handler_sub_domain.go b/server/handler/handler_sub_domain.go
new file mode 100644
index 0000000..df42d61
--- /dev/null
+++ b/server/handler/handler_sub_domain.go
@@ -0,0 +1,120 @@
+package handler
+
+import (
+ "fmt"
+ "net/http"
+ "path"
+ "strings"
+
+ "github.com/rs/zerolog"
+
+ "codeberg.org/codeberg/pages/html"
+ "codeberg.org/codeberg/pages/server/cache"
+ "codeberg.org/codeberg/pages/server/context"
+ "codeberg.org/codeberg/pages/server/gitea"
+ "codeberg.org/codeberg/pages/server/upstream"
+)
+
+func handleSubDomain(log zerolog.Logger, ctx *context.Context, giteaClient *gitea.Client,
+ mainDomainSuffix string,
+ trimmedHost string,
+ pathElements []string,
+ canonicalDomainCache cache.SetGetKey,
+) {
+ // Serve pages from subdomains of MainDomainSuffix
+ log.Debug().Msg("main domain suffix")
+
+ targetOwner := strings.TrimSuffix(trimmedHost, mainDomainSuffix)
+ targetRepo := pathElements[0]
+
+ if targetOwner == "www" {
+ // www.codeberg.page redirects to codeberg.page // TODO: rm hardcoded - use cname?
+ ctx.Redirect("https://"+string(mainDomainSuffix[1:])+string(ctx.Path()), http.StatusPermanentRedirect)
+ return
+ }
+
+ // Check if the first directory is a repo with the second directory as a branch
+ // example.codeberg.page/myrepo/@main/index.html
+ if len(pathElements) > 1 && strings.HasPrefix(pathElements[1], "@") {
+ if targetRepo == "pages" {
+ // example.codeberg.org/pages/@... redirects to example.codeberg.org/@...
+ ctx.Redirect("/"+strings.Join(pathElements[1:], "/"), http.StatusTemporaryRedirect)
+ return
+ }
+
+ log.Debug().Msg("main domain preparations, now trying with specified repo & branch")
+ if targetOpt, works := tryBranch(log, ctx, giteaClient, &upstream.Options{
+ TryIndexPages: true,
+ TargetOwner: targetOwner,
+ TargetRepo: pathElements[0],
+ TargetBranch: pathElements[1][1:],
+ TargetPath: path.Join(pathElements[2:]...),
+ }, true); works {
+ log.Trace().Msg("tryUpstream: serve with specified repo and branch")
+ tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache)
+ } else {
+ html.ReturnErrorPage(ctx,
+ fmt.Sprintf("explizite set branch %q do not exist at '%s/%s'", targetOpt.TargetBranch, targetOpt.TargetOwner, targetOpt.TargetRepo),
+ http.StatusFailedDependency)
+ }
+ return
+ }
+
+ // Check if the first directory is a branch for the "pages" repo
+ // example.codeberg.page/@main/index.html
+ if strings.HasPrefix(pathElements[0], "@") {
+ log.Debug().Msg("main domain preparations, now trying with specified branch")
+ if targetOpt, works := tryBranch(log, ctx, giteaClient, &upstream.Options{
+ TryIndexPages: true,
+ TargetOwner: targetOwner,
+ TargetRepo: "pages",
+ TargetBranch: pathElements[0][1:],
+ TargetPath: path.Join(pathElements[1:]...),
+ }, true); works {
+ log.Trace().Msg("tryUpstream: serve default pages repo with specified branch")
+ tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache)
+ } else {
+ html.ReturnErrorPage(ctx,
+ fmt.Sprintf("explizite set branch %q do not exist at '%s/%s'", targetOpt.TargetBranch, targetOpt.TargetOwner, targetOpt.TargetRepo),
+ http.StatusFailedDependency)
+ }
+ return
+ }
+
+ // Check if the first directory is a repo with a "pages" branch
+ // example.codeberg.page/myrepo/index.html
+ // example.codeberg.page/pages/... is not allowed here.
+ log.Debug().Msg("main domain preparations, now trying with specified repo")
+ if pathElements[0] != "pages" {
+ if targetOpt, works := tryBranch(log, ctx, giteaClient, &upstream.Options{
+ TryIndexPages: true,
+ TargetOwner: targetOwner,
+ TargetRepo: pathElements[0],
+ TargetBranch: "pages",
+ TargetPath: path.Join(pathElements[1:]...),
+ }, false); works {
+ log.Debug().Msg("tryBranch, now trying upstream 5")
+ tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache)
+ return
+ }
+ }
+
+ // Try to use the "pages" repo on its default branch
+ // example.codeberg.page/index.html
+ log.Debug().Msg("main domain preparations, now trying with default repo/branch")
+ if targetOpt, works := tryBranch(log, ctx, giteaClient, &upstream.Options{
+ TryIndexPages: true,
+ TargetOwner: targetOwner,
+ TargetRepo: "pages",
+ TargetPath: path.Join(pathElements...),
+ }, false); works {
+ log.Debug().Msg("tryBranch, now trying upstream 6")
+ tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache)
+ return
+ }
+
+ // Couldn't find a valid repo/branch
+ html.ReturnErrorPage(ctx,
+ fmt.Sprintf("couldn't find a valid repo[%s]", targetRepo),
+ http.StatusFailedDependency)
+}