mirror of
https://codeberg.org/Codeberg/pages-server.git
synced 2024-11-05 14:07:01 +00:00
118 lines
3.4 KiB
Go
118 lines
3.4 KiB
Go
|
package upstream
|
||
|
|
||
|
import (
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
"codeberg.org/codeberg/pages/server/cache"
|
||
|
"codeberg.org/codeberg/pages/server/context"
|
||
|
"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"
|
||
|
|
||
|
// getRedirects returns redirects specified in the _redirects file.
|
||
|
func (o *Options) getRedirects(giteaClient *gitea.Client, redirectsCache cache.SetGetKey) []Redirect {
|
||
|
var redirects []Redirect
|
||
|
cacheKey := o.TargetOwner + "/" + o.TargetRepo + "/" + o.TargetBranch
|
||
|
|
||
|
// Check for cached redirects
|
||
|
if cachedValue, ok := redirectsCache.Get(cacheKey); 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") {
|
||
|
redirectArr := strings.Fields(line)
|
||
|
|
||
|
// Ignore comments and invalid lines
|
||
|
if strings.HasPrefix(line, "#") || len(redirectArr) < 2 {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// Get redirect status code
|
||
|
statusCode := 301
|
||
|
if len(redirectArr) == 3 {
|
||
|
statusCode, err = strconv.Atoi(redirectArr[2])
|
||
|
if err != nil {
|
||
|
log.Info().Err(err).Msgf("could not read %s of %s/%s", redirectsConfig, o.TargetOwner, o.TargetRepo)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
redirects = append(redirects, Redirect{
|
||
|
From: redirectArr[0],
|
||
|
To: redirectArr[1],
|
||
|
StatusCode: statusCode,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
_ = redirectsCache.Set(cacheKey, redirects, redirectsCacheTimeout)
|
||
|
}
|
||
|
return redirects
|
||
|
}
|
||
|
|
||
|
func (o *Options) matchRedirects(ctx *context.Context, giteaClient *gitea.Client, redirects []Redirect, redirectsCache cache.SetGetKey) (final bool) {
|
||
|
if len(redirects) > 0 {
|
||
|
for _, redirect := range redirects {
|
||
|
reqUrl := ctx.Req.RequestURI
|
||
|
// remove repo and branch from request url
|
||
|
reqUrl = strings.TrimPrefix(reqUrl, "/"+o.TargetRepo)
|
||
|
reqUrl = strings.TrimPrefix(reqUrl, "/@"+o.TargetBranch)
|
||
|
|
||
|
// 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
|
||
|
}
|