pages-server/server/upstream/redirects.go

112 lines
3.2 KiB
Go
Raw Normal View History

2022-12-19 15:50:03 -05:00
package upstream
import (
"strconv"
"strings"
"time"
"codeberg.org/codeberg/pages/server/cache"
2023-03-14 19:08:19 -04:00
"codeberg.org/codeberg/pages/server/context"
2022-12-19 15:50:03 -05:00
"codeberg.org/codeberg/pages/server/gitea"
"github.com/rs/zerolog/log"
)
type Redirect struct {
From string
To string
StatusCode int
}
// redirectsCacheTimeout specifies the timeout for the redirects cache.
var redirectsCacheTimeout = 10 * time.Minute
const redirectsConfig = "_redirects"
2023-03-14 19:08:19 -04:00
// getRedirects returns redirects specified in the _redirects file.
func (o *Options) getRedirects(giteaClient *gitea.Client, redirectsCache cache.SetGetKey) []Redirect {
2022-12-19 15:50:03 -05:00
var redirects []Redirect
2023-03-14 19:08:19 -04:00
cacheKey := o.TargetOwner + "/" + o.TargetRepo + "/" + o.TargetBranch
2022-12-19 15:50:03 -05:00
2023-02-25 21:30:05 -05:00
// Check for cached redirects
2023-03-14 19:08:19 -04:00
if cachedValue, ok := redirectsCache.Get(cacheKey); ok {
2022-12-19 15:50:03 -05:00
redirects = cachedValue.([]Redirect)
} else {
2023-02-25 21:30:05 -05:00
// Get _redirects file and parse
2022-12-19 15:50:03 -05:00
body, err := giteaClient.GiteaRawContent(o.TargetOwner, o.TargetRepo, o.TargetBranch, redirectsConfig)
if err == nil {
for _, line := range strings.Split(string(body), "\n") {
redirectArr := strings.Fields(line)
2023-02-25 21:44:33 -05:00
// Ignore comments and invalid lines
if strings.HasPrefix(line, "#") || len(redirectArr) < 2 {
continue
}
// Get redirect status code
statusCode := 301
2022-12-19 15:50:03 -05:00
if len(redirectArr) == 3 {
2023-02-25 21:44:33 -05:00
statusCode, err = strconv.Atoi(redirectArr[2])
2022-12-19 15:50:03 -05:00
if err != nil {
log.Info().Err(err).Msgf("could not read %s of %s/%s", redirectsConfig, o.TargetOwner, o.TargetRepo)
}
}
2023-02-25 21:44:33 -05:00
redirects = append(redirects, Redirect{
From: redirectArr[0],
To: redirectArr[1],
StatusCode: statusCode,
})
2022-12-19 15:50:03 -05:00
}
}
_ = redirectsCache.Set(o.TargetOwner+"/"+o.TargetRepo+"/"+o.TargetBranch, redirects, redirectsCacheTimeout)
}
return redirects
}
2023-03-14 19:08:19 -04:00
func (o *Options) matchRedirects(ctx *context.Context, giteaClient *gitea.Client, redirects []Redirect, redirectsCache cache.SetGetKey) {
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
} else {
ctx.Redirect(redirect.To, redirect.StatusCode)
return
}
}
// 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
} else {
ctx.Redirect(splatUrl, redirect.StatusCode)
return
}
} else {
// do rewrite if status code is 200
if redirect.StatusCode == 200 {
o.TargetPath = redirect.To
o.Upstream(ctx, giteaClient, redirectsCache)
return
} else {
ctx.Redirect(redirect.To, redirect.StatusCode)
return
}
}
}
}
}
}