diff --git a/server/gitea/cache.go b/server/gitea/cache.go index bf87a67..fe7ead3 100644 --- a/server/gitea/cache.go +++ b/server/gitea/cache.go @@ -2,6 +2,7 @@ package gitea import ( "bytes" + "fmt" "io" "net/http" "time" @@ -55,6 +56,8 @@ func (f FileResponse) createHttpResponse() *http.Response { } resp.Header.Set(eTagHeader, f.ETag) resp.Header.Set(contentTypeHeader, f.MimeType) + resp.Header.Set(contentLengthHeader, fmt.Sprint(len(f.Body))) + resp.Header.Set(pagesCacheIndicator, "true") return resp } diff --git a/server/gitea/client.go b/server/gitea/client.go index 3e74e8e..bda5d14 100644 --- a/server/gitea/client.go +++ b/server/gitea/client.go @@ -27,6 +27,9 @@ const ( defaultBranchCacheKeyPrefix = "defaultBranch" rawContentCacheKeyPrefix = "rawContent" + // pages server + pagesCacheIndicator = "X-Pages-Cache" + // gitea giteaObjectTypeHeader = "X-Gitea-Object-Type" objTypeSymlink = "symlink" diff --git a/server/handler.go b/server/handler.go index 135316a..43fc24a 100644 --- a/server/handler.go +++ b/server/handler.go @@ -1,7 +1,9 @@ package server import ( + "fmt" "net/http" + "path" "strings" "github.com/rs/zerolog" @@ -58,7 +60,7 @@ func Handler(mainDomainSuffix, rawDomain string, // Block blacklisted paths (like ACME challenges) for _, blacklistedPath := range blacklistedPaths { if strings.HasPrefix(ctx.Path(), blacklistedPath) { - html.ReturnErrorPage(ctx, "", http.StatusForbidden) + html.ReturnErrorPage(ctx, "requested blacklisted path", http.StatusForbidden) return } } @@ -90,7 +92,7 @@ func Handler(mainDomainSuffix, rawDomain string, // tryBranch checks if a branch exists and populates the target variables. If canonicalLink is non-empty, it will // also disallow search indexing and add a Link header to the canonical URL. - tryBranch := func(log zerolog.Logger, repo, branch string, path []string, canonicalLink string) bool { + tryBranch := func(log zerolog.Logger, repo, branch string, _path []string, canonicalLink string) bool { if repo == "" { log.Debug().Msg("tryBranch: repo == ''") return false @@ -109,7 +111,7 @@ func Handler(mainDomainSuffix, rawDomain string, // Branch exists, use it targetRepo = repo - targetPath = strings.Trim(strings.Join(path, "/"), "/") + targetPath = path.Join(_path...) targetBranch = branchTimestampResult.Branch targetOptions.BranchTimestamp = branchTimestampResult.Timestamp @@ -157,8 +159,8 @@ func Handler(mainDomainSuffix, rawDomain string, canonicalDomainCache) return } - log.Debug().Msg("missing branch") - html.ReturnErrorPage(ctx, "", http.StatusFailedDependency) + log.Debug().Msg("missing branch info") + html.ReturnErrorPage(ctx, "missing branch info", http.StatusFailedDependency) return } @@ -198,8 +200,9 @@ func Handler(mainDomainSuffix, rawDomain string, } log.Debug().Msg("main domain preparations, now trying with specified repo & branch") + branch := pathElements[1][1:] if tryBranch(log, - pathElements[0], pathElements[1][1:], pathElements[2:], + pathElements[0], branch, pathElements[2:], "/"+pathElements[0]+"/%p", ) { log.Debug().Msg("tryBranch, now trying upstream 3") @@ -207,7 +210,9 @@ func Handler(mainDomainSuffix, rawDomain string, targetOptions, targetOwner, targetRepo, targetBranch, targetPath, canonicalDomainCache) } else { - html.ReturnErrorPage(ctx, "", http.StatusFailedDependency) + html.ReturnErrorPage(ctx, + fmt.Sprintf("explizite set branch '%s' do not exist at '%s/%s'", branch, targetOwner, targetRepo), + http.StatusFailedDependency) } return } @@ -216,14 +221,17 @@ func Handler(mainDomainSuffix, rawDomain string, // example.codeberg.page/@main/index.html if strings.HasPrefix(pathElements[0], "@") { log.Debug().Msg("main domain preparations, now trying with specified branch") + branch := pathElements[0][1:] if tryBranch(log, - "pages", pathElements[0][1:], pathElements[1:], "/%p") { + "pages", branch, pathElements[1:], "/%p") { log.Debug().Msg("tryBranch, now trying upstream 4") tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, - targetOptions, targetOwner, targetRepo, targetBranch, targetPath, + targetOptions, targetOwner, "pages", targetBranch, targetPath, canonicalDomainCache) } else { - html.ReturnErrorPage(ctx, "", http.StatusFailedDependency) + html.ReturnErrorPage(ctx, + fmt.Sprintf("explizite set branch '%s' do not exist at '%s/%s'", branch, targetOwner, "pages"), + http.StatusFailedDependency) } return } @@ -254,15 +262,19 @@ func Handler(mainDomainSuffix, rawDomain string, } // Couldn't find a valid repo/branch - html.ReturnErrorPage(ctx, "", http.StatusFailedDependency) + html.ReturnErrorPage(ctx, + fmt.Sprintf("couldn't find a valid repo[%s]/branch[%s]", targetRepo, targetBranch), + http.StatusFailedDependency) return } else { trimmedHostStr := string(trimmedHost) - // Serve pages from external domains + // Serve pages from custom domains targetOwner, targetRepo, targetBranch = dns.GetTargetFromDNS(trimmedHostStr, string(mainDomainSuffix), dnsLookupCache) if targetOwner == "" { - html.ReturnErrorPage(ctx, "", http.StatusFailedDependency) + html.ReturnErrorPage(ctx, + "could not obtain repo owner from custom domain", + http.StatusFailedDependency) return } @@ -280,7 +292,7 @@ func Handler(mainDomainSuffix, rawDomain string, targetRepo, targetBranch, pathElements, canonicalLink) { canonicalDomain, valid := upstream.CheckCanonicalDomain(giteaClient, targetOwner, targetRepo, targetBranch, trimmedHostStr, string(mainDomainSuffix), canonicalDomainCache) if !valid { - html.ReturnErrorPage(ctx, "", http.StatusMisdirectedRequest) + 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! @@ -290,7 +302,7 @@ func Handler(mainDomainSuffix, rawDomain string, return } - html.ReturnErrorPage(ctx, "", http.StatusFailedDependency) + html.ReturnErrorPage(ctx, "target is no codeberg page", http.StatusFailedDependency) return } @@ -301,7 +313,7 @@ func Handler(mainDomainSuffix, rawDomain string, return } - html.ReturnErrorPage(ctx, "", http.StatusFailedDependency) + html.ReturnErrorPage(ctx, "could not find target for custom domain", http.StatusFailedDependency) return } } diff --git a/server/upstream/upstream.go b/server/upstream/upstream.go index 6796588..40345c0 100644 --- a/server/upstream/upstream.go +++ b/server/upstream/upstream.go @@ -2,6 +2,7 @@ package upstream import ( "errors" + "fmt" "io" "net/http" "strings" @@ -56,23 +57,25 @@ type Options struct { func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client) (final bool) { log := log.With().Strs("upstream", []string{o.TargetOwner, o.TargetRepo, o.TargetBranch, o.TargetPath}).Logger() + if o.TargetOwner == "" || o.TargetRepo == "" { + html.ReturnErrorPage(ctx, "either repo owner or name info is missing", http.StatusBadRequest) + return true + } + // Check if the branch exists and when it was modified if o.BranchTimestamp.IsZero() { branch := GetBranchTimestamp(giteaClient, o.TargetOwner, o.TargetRepo, o.TargetBranch) - if branch == nil { - html.ReturnErrorPage(ctx, "", http.StatusFailedDependency) + if branch == nil || branch.Branch == "" { + html.ReturnErrorPage(ctx, + fmt.Sprintf("could not get timestamp of branch '%s'", o.TargetBranch), + http.StatusFailedDependency) return true } o.TargetBranch = branch.Branch o.BranchTimestamp = branch.Timestamp } - if o.TargetOwner == "" || o.TargetRepo == "" || o.TargetBranch == "" { - html.ReturnErrorPage(ctx, "", http.StatusBadRequest) - return true - } - // Check if the browser has a cached version if ifModifiedSince, err := time.Parse(time.RFC1123, string(ctx.Response().Header.Get(headerIfModifiedSince))); err == nil { if !ifModifiedSince.Before(o.BranchTimestamp) { @@ -127,7 +130,7 @@ func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client) (fin } if res != nil && (err != nil || res.StatusCode != http.StatusOK) { log.Printf("Couldn't fetch contents (status code %d): %v\n", res.StatusCode, err) - html.ReturnErrorPage(ctx, "", http.StatusInternalServerError) + html.ReturnErrorPage(ctx, fmt.Sprintf("%v", err), http.StatusInternalServerError) return true }