diff --git a/server/handler/try.go b/server/handler/try.go index 47054eb..6cfe08e 100644 --- a/server/handler/try.go +++ b/server/handler/try.go @@ -39,43 +39,8 @@ func tryUpstream(ctx *context.Context, giteaClient *gitea.Client, // Add host for debugging. options.Host = trimmedHost - // Check for redirects - redirects := options.GetRedirects(giteaClient, redirectsCache) - if len(redirects) > 0 { - for _, redirect := range redirects { - reqUrl := ctx.Req.RequestURI - trimmedFromUrl := strings.TrimSuffix(redirect.From, "/*") - if strings.TrimSuffix(redirect.From, "/") == strings.TrimSuffix(reqUrl, "/") { - if redirect.StatusCode == 200 { - options.TargetPath = redirect.To - } else { - ctx.Redirect(redirect.To, redirect.StatusCode) - return - } - } - if strings.HasSuffix(redirect.From, "/*") && strings.HasPrefix(reqUrl, trimmedFromUrl) { - if strings.Contains(redirect.To, ":splat") { - splatUrl := strings.ReplaceAll(redirect.To, ":splat", strings.TrimPrefix(reqUrl, trimmedFromUrl)) - if redirect.StatusCode == 200 { - options.TargetPath = splatUrl - } else { - ctx.Redirect(splatUrl, redirect.StatusCode) - return - } - } else { - if redirect.StatusCode == 200 { - options.TargetPath = redirect.To - } else { - ctx.Redirect(redirect.To, redirect.StatusCode) - return - } - } - } - } - } - // Try to request the file from the Gitea API - if !options.Upstream(ctx, giteaClient) { + if !options.Upstream(ctx, giteaClient, redirectsCache) { html.ReturnErrorPage(ctx, "", ctx.StatusCode) } } diff --git a/server/upstream/redirects.go b/server/upstream/redirects.go index f27aed4..a48ffe4 100644 --- a/server/upstream/redirects.go +++ b/server/upstream/redirects.go @@ -25,9 +25,11 @@ const redirectsConfig = "_redirects" func (o *Options) GetRedirects(giteaClient *gitea.Client, redirectsCache cache.SetGetKey) []Redirect { var redirects []Redirect + // Check for cached redirects if cachedValue, ok := redirectsCache.Get(o.TargetOwner + "/" + o.TargetRepo + "/" + o.TargetBranch); ok { redirects = cachedValue.([]Redirect) } else { + // Get _redirects file and parse body, err := giteaClient.GiteaRawContent(o.TargetOwner, o.TargetRepo, o.TargetBranch, redirectsConfig) if err == nil { for _, line := range strings.Split(string(body), "\n") { diff --git a/server/upstream/upstream.go b/server/upstream/upstream.go index 3845969..38dc6c8 100644 --- a/server/upstream/upstream.go +++ b/server/upstream/upstream.go @@ -11,6 +11,7 @@ import ( "github.com/rs/zerolog/log" "codeberg.org/codeberg/pages/html" + "codeberg.org/codeberg/pages/server/cache" "codeberg.org/codeberg/pages/server/context" "codeberg.org/codeberg/pages/server/gitea" ) @@ -52,7 +53,7 @@ type Options struct { } // Upstream requests a file from the Gitea API at GiteaRoot and writes it to the request context. -func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client) (final bool) { +func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client, redirectsCache cache.SetGetKey) (final bool) { log := log.With().Strs("upstream", []string{o.TargetOwner, o.TargetRepo, o.TargetBranch, o.TargetPath}).Logger() if o.TargetOwner == "" || o.TargetRepo == "" { @@ -110,7 +111,7 @@ func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client) (fin optionsForIndexPages.appendTrailingSlash = true for _, indexPage := range upstreamIndexPages { optionsForIndexPages.TargetPath = strings.TrimSuffix(o.TargetPath, "/") + "/" + indexPage - if optionsForIndexPages.Upstream(ctx, giteaClient) { + if optionsForIndexPages.Upstream(ctx, giteaClient, redirectsCache) { return true } } @@ -118,7 +119,7 @@ func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client) (fin optionsForIndexPages.appendTrailingSlash = false optionsForIndexPages.redirectIfExists = strings.TrimSuffix(ctx.Path(), "/") + ".html" optionsForIndexPages.TargetPath = o.TargetPath + ".html" - if optionsForIndexPages.Upstream(ctx, giteaClient) { + if optionsForIndexPages.Upstream(ctx, giteaClient, redirectsCache) { return true } } @@ -131,11 +132,60 @@ func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client) (fin optionsForNotFoundPages.appendTrailingSlash = false for _, notFoundPage := range upstreamNotFoundPages { optionsForNotFoundPages.TargetPath = "/" + notFoundPage - if optionsForNotFoundPages.Upstream(ctx, giteaClient) { + if optionsForNotFoundPages.Upstream(ctx, giteaClient, redirectsCache) { return true } } } + + // Check for redirects + redirects := o.GetRedirects(giteaClient, redirectsCache) + if len(redirects) > 0 { + for _, redirect := range redirects { + reqUrl := ctx.Req.RequestURI + + // check if from url matches request url + if strings.TrimSuffix(redirect.From, "/") == strings.TrimSuffix(reqUrl, "/") { + // do rewrite if status code is 200 + if redirect.StatusCode == 200 { + o.TargetPath = redirect.To + o.Upstream(ctx, giteaClient, redirectsCache) + return true + } else { + ctx.Redirect(redirect.To, redirect.StatusCode) + return true + } + } + + // handle wildcard redirects + trimmedFromUrl := strings.TrimSuffix(redirect.From, "/*") + if strings.HasSuffix(redirect.From, "/*") && strings.HasPrefix(reqUrl, trimmedFromUrl) { + if strings.Contains(redirect.To, ":splat") { + splatUrl := strings.ReplaceAll(redirect.To, ":splat", strings.TrimPrefix(reqUrl, trimmedFromUrl)) + // do rewrite if status code is 200 + if redirect.StatusCode == 200 { + o.TargetPath = splatUrl + o.Upstream(ctx, giteaClient, redirectsCache) + return true + } else { + ctx.Redirect(splatUrl, redirect.StatusCode) + return true + } + } else { + // do rewrite if status code is 200 + if redirect.StatusCode == 200 { + o.TargetPath = redirect.To + o.Upstream(ctx, giteaClient, redirectsCache) + return true + } else { + ctx.Redirect(redirect.To, redirect.StatusCode) + return true + } + } + } + } + } + return false }