package handler import ( "fmt" "net/http" "path" "strings" "github.com/rs/zerolog" "golang.org/x/exp/slices" "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, defaultPagesBranches []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://"+mainDomainSuffix[1:]+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 == defaultPagesRepo { // 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 defaultPagesRepo // example.codeberg.page/@main/index.html if strings.HasPrefix(pathElements[0], "@") { targetBranch := pathElements[0][1:] // if the default pages branch can be determined exactly, it does not need to be set if len(defaultPagesBranches) == 1 && slices.Contains(defaultPagesBranches, targetBranch) { // 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 branch") if targetOpt, works := tryBranch(log, ctx, giteaClient, &upstream.Options{ TryIndexPages: true, TargetOwner: targetOwner, TargetRepo: defaultPagesRepo, TargetBranch: targetBranch, 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 } for _, defaultPagesBranch := range defaultPagesBranches { // Check if the first directory is a repo with a default pages branch // example.codeberg.page/myrepo/index.html // example.codeberg.page/{PAGES_BRANCHE}/... is not allowed here. log.Debug().Msg("main domain preparations, now trying with specified repo") if pathElements[0] != defaultPagesBranch { if targetOpt, works := tryBranch(log, ctx, giteaClient, &upstream.Options{ TryIndexPages: true, TargetOwner: targetOwner, TargetRepo: pathElements[0], TargetBranch: defaultPagesBranch, 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 defaultPagesRepo on an default pages branch // example.codeberg.page/index.html log.Debug().Msg("main domain preparations, now trying with default repo") if targetOpt, works := tryBranch(log, ctx, giteaClient, &upstream.Options{ TryIndexPages: true, TargetOwner: targetOwner, TargetRepo: defaultPagesRepo, TargetBranch: defaultPagesBranch, TargetPath: path.Join(pathElements...), }, false); works { log.Debug().Msg("tryBranch, now trying upstream 6") tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache) return } } // Try to use the defaultPagesRepo 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: defaultPagesRepo, 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("could not find a valid repository[%s]", targetRepo), http.StatusNotFound) }