mirror of
https://codeberg.org/Codeberg/pages-server.git
synced 2025-01-19 17:07:54 +00:00
more string
This commit is contained in:
parent
662d76386c
commit
51ca74fc11
16 changed files with 121 additions and 123 deletions
11
cmd/main.go
11
cmd/main.go
|
@ -1,7 +1,8 @@
|
||||||
|
//go:build !fasthttp
|
||||||
|
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -47,7 +48,7 @@ func Serve(ctx *cli.Context) error {
|
||||||
giteaRoot := strings.TrimSuffix(ctx.String("gitea-root"), "/")
|
giteaRoot := strings.TrimSuffix(ctx.String("gitea-root"), "/")
|
||||||
giteaAPIToken := ctx.String("gitea-api-token")
|
giteaAPIToken := ctx.String("gitea-api-token")
|
||||||
rawDomain := ctx.String("raw-domain")
|
rawDomain := ctx.String("raw-domain")
|
||||||
mainDomainSuffix := []byte(ctx.String("pages-domain"))
|
mainDomainSuffix := ctx.String("pages-domain")
|
||||||
rawInfoPage := ctx.String("raw-info-page")
|
rawInfoPage := ctx.String("raw-info-page")
|
||||||
listeningAddress := fmt.Sprintf("%s:%s", ctx.String("host"), ctx.String("port"))
|
listeningAddress := fmt.Sprintf("%s:%s", ctx.String("host"), ctx.String("port"))
|
||||||
enableHTTPServer := ctx.Bool("enable-http-server")
|
enableHTTPServer := ctx.Bool("enable-http-server")
|
||||||
|
@ -69,8 +70,8 @@ func Serve(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure MainDomain has a trailing dot, and GiteaRoot has no trailing slash
|
// Make sure MainDomain has a trailing dot, and GiteaRoot has no trailing slash
|
||||||
if !bytes.HasPrefix(mainDomainSuffix, []byte{'.'}) {
|
if !strings.HasPrefix(mainDomainSuffix, ".") {
|
||||||
mainDomainSuffix = append([]byte{'.'}, mainDomainSuffix...)
|
mainDomainSuffix = "." + mainDomainSuffix
|
||||||
}
|
}
|
||||||
|
|
||||||
keyCache := cache.NewKeyValueCache()
|
keyCache := cache.NewKeyValueCache()
|
||||||
|
@ -88,7 +89,7 @@ func Serve(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create handler based on settings
|
// Create handler based on settings
|
||||||
handler := server.Handler(mainDomainSuffix, []byte(rawDomain),
|
handler := server.Handler(mainDomainSuffix, rawDomain,
|
||||||
giteaClient,
|
giteaClient,
|
||||||
giteaRoot, rawInfoPage,
|
giteaRoot, rawInfoPage,
|
||||||
BlacklistedPaths, allowedCorsDomains,
|
BlacklistedPaths, allowedCorsDomains,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package html
|
package html
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func errorMessage(statusCode int) string {
|
func errorMessage(statusCode int) string {
|
||||||
|
@ -20,8 +20,8 @@ func errorMessage(statusCode int) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use template engine?
|
// TODO: use template engine?
|
||||||
func errorBody(statusCode int) []byte {
|
func errorBody(statusCode int) string {
|
||||||
return bytes.ReplaceAll(NotFoundPage,
|
return strings.ReplaceAll(NotFoundPage,
|
||||||
[]byte("%status"),
|
"%status",
|
||||||
[]byte(strconv.Itoa(statusCode)+" "+errorMessage(statusCode)))
|
strconv.Itoa(statusCode)+" "+errorMessage(statusCode))
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,5 +13,5 @@ func ReturnErrorPage(ctx *fasthttp.RequestCtx, code int) {
|
||||||
ctx.Response.Header.SetContentType("text/html; charset=utf-8")
|
ctx.Response.Header.SetContentType("text/html; charset=utf-8")
|
||||||
|
|
||||||
// TODO: use template engine?
|
// TODO: use template engine?
|
||||||
ctx.Response.SetBody(errorBody(code))
|
ctx.Response.SetBody([]byte(errorBody(code)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,17 +3,21 @@
|
||||||
package html
|
package html
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"io"
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"codeberg.org/codeberg/pages/server/context"
|
"codeberg.org/codeberg/pages/server/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReturnErrorPage sets the response status code and writes NotFoundPage to the response body, with "%status" replaced
|
// ReturnErrorPage sets the response status code and writes NotFoundPage to the response body, with "%status" replaced
|
||||||
// with the provided status code.
|
// with the provided status code.
|
||||||
func ReturnErrorPage(ctx *context.Context, code int) {
|
func ReturnErrorPage(ctx *context.Context, msg string, code int) {
|
||||||
ctx.RespWriter.Header().Set("Content-Type", "text/html; charset=utf-8")
|
ctx.RespWriter.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
ctx.RespWriter.WriteHeader(code)
|
ctx.RespWriter.WriteHeader(code)
|
||||||
|
|
||||||
io.Copy(ctx.RespWriter, bytes.NewReader(errorBody(code)))
|
if msg == "" {
|
||||||
|
msg = errorBody(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
io.Copy(ctx.RespWriter, strings.NewReader(msg))
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,4 +3,4 @@ package html
|
||||||
import _ "embed"
|
import _ "embed"
|
||||||
|
|
||||||
//go:embed 404.html
|
//go:embed 404.html
|
||||||
var NotFoundPage []byte
|
var NotFoundPage string
|
||||||
|
|
|
@ -36,7 +36,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// TLSConfig returns the configuration for generating, serving and cleaning up Let's Encrypt certificates.
|
// TLSConfig returns the configuration for generating, serving and cleaning up Let's Encrypt certificates.
|
||||||
func TLSConfig(mainDomainSuffix []byte,
|
func TLSConfig(mainDomainSuffix string,
|
||||||
giteaClient *gitea.Client,
|
giteaClient *gitea.Client,
|
||||||
dnsProvider string,
|
dnsProvider string,
|
||||||
acmeUseRateLimits bool,
|
acmeUseRateLimits bool,
|
||||||
|
@ -47,7 +47,6 @@ func TLSConfig(mainDomainSuffix []byte,
|
||||||
// check DNS name & get certificate from Let's Encrypt
|
// check DNS name & get certificate from Let's Encrypt
|
||||||
GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||||
sni := strings.ToLower(strings.TrimSpace(info.ServerName))
|
sni := strings.ToLower(strings.TrimSpace(info.ServerName))
|
||||||
sniBytes := []byte(sni)
|
|
||||||
if len(sni) < 1 {
|
if len(sni) < 1 {
|
||||||
return nil, errors.New("missing sni")
|
return nil, errors.New("missing sni")
|
||||||
}
|
}
|
||||||
|
@ -69,23 +68,20 @@ func TLSConfig(mainDomainSuffix []byte,
|
||||||
}
|
}
|
||||||
|
|
||||||
targetOwner := ""
|
targetOwner := ""
|
||||||
if bytes.HasSuffix(sniBytes, mainDomainSuffix) || bytes.Equal(sniBytes, mainDomainSuffix[1:]) {
|
if strings.HasSuffix(sni, mainDomainSuffix) || strings.EqualFold(sni, mainDomainSuffix[1:]) {
|
||||||
// deliver default certificate for the main domain (*.codeberg.page)
|
// deliver default certificate for the main domain (*.codeberg.page)
|
||||||
sniBytes = mainDomainSuffix
|
sni = mainDomainSuffix
|
||||||
sni = string(sniBytes)
|
|
||||||
} else {
|
} else {
|
||||||
var targetRepo, targetBranch string
|
var targetRepo, targetBranch string
|
||||||
targetOwner, targetRepo, targetBranch = dnsutils.GetTargetFromDNS(sni, string(mainDomainSuffix), dnsLookupCache)
|
targetOwner, targetRepo, targetBranch = dnsutils.GetTargetFromDNS(sni, mainDomainSuffix, dnsLookupCache)
|
||||||
if targetOwner == "" {
|
if targetOwner == "" {
|
||||||
// DNS not set up, return main certificate to redirect to the docs
|
// DNS not set up, return main certificate to redirect to the docs
|
||||||
sniBytes = mainDomainSuffix
|
sni = mainDomainSuffix
|
||||||
sni = string(sniBytes)
|
|
||||||
} else {
|
} else {
|
||||||
_, _ = targetRepo, targetBranch
|
_, _ = targetRepo, targetBranch
|
||||||
_, valid := upstream.CheckCanonicalDomain(giteaClient, targetOwner, targetRepo, targetBranch, sni, string(mainDomainSuffix), canonicalDomainCache)
|
_, valid := upstream.CheckCanonicalDomain(giteaClient, targetOwner, targetRepo, targetBranch, sni, mainDomainSuffix, canonicalDomainCache)
|
||||||
if !valid {
|
if !valid {
|
||||||
sniBytes = mainDomainSuffix
|
sni = mainDomainSuffix
|
||||||
sni = string(sniBytes)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,9 +94,9 @@ func TLSConfig(mainDomainSuffix []byte,
|
||||||
var tlsCertificate tls.Certificate
|
var tlsCertificate tls.Certificate
|
||||||
var err error
|
var err error
|
||||||
var ok bool
|
var ok bool
|
||||||
if tlsCertificate, ok = retrieveCertFromDB(sniBytes, mainDomainSuffix, dnsProvider, acmeUseRateLimits, certDB); !ok {
|
if tlsCertificate, ok = retrieveCertFromDB(sni, mainDomainSuffix, dnsProvider, acmeUseRateLimits, certDB); !ok {
|
||||||
// request a new certificate
|
// request a new certificate
|
||||||
if bytes.Equal(sniBytes, mainDomainSuffix) {
|
if strings.EqualFold(sni, mainDomainSuffix) {
|
||||||
return nil, errors.New("won't request certificate for main domain, something really bad has happened")
|
return nil, errors.New("won't request certificate for main domain, something really bad has happened")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,7 +188,7 @@ func (a AcmeHTTPChallengeProvider) CleanUp(domain, token, _ string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func retrieveCertFromDB(sni, mainDomainSuffix []byte, dnsProvider string, acmeUseRateLimits bool, certDB database.CertDB) (tls.Certificate, bool) {
|
func retrieveCertFromDB(sni, mainDomainSuffix, dnsProvider string, acmeUseRateLimits bool, certDB database.CertDB) (tls.Certificate, bool) {
|
||||||
// parse certificate from database
|
// parse certificate from database
|
||||||
res, err := certDB.Get(string(sni))
|
res, err := certDB.Get(string(sni))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -208,7 +204,7 @@ func retrieveCertFromDB(sni, mainDomainSuffix []byte, dnsProvider string, acmeUs
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: document & put into own function
|
// TODO: document & put into own function
|
||||||
if !bytes.Equal(sni, mainDomainSuffix) {
|
if !strings.EqualFold(sni, mainDomainSuffix) {
|
||||||
tlsCertificate.Leaf, err = x509.ParseCertificate(tlsCertificate.Certificate[0])
|
tlsCertificate.Leaf, err = x509.ParseCertificate(tlsCertificate.Certificate[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -239,7 +235,7 @@ func retrieveCertFromDB(sni, mainDomainSuffix []byte, dnsProvider string, acmeUs
|
||||||
|
|
||||||
var obtainLocks = sync.Map{}
|
var obtainLocks = sync.Map{}
|
||||||
|
|
||||||
func obtainCert(acmeClient *lego.Client, domains []string, renew *certificate.Resource, user, dnsProvider string, mainDomainSuffix []byte, acmeUseRateLimits bool, keyDatabase database.CertDB) (tls.Certificate, error) {
|
func obtainCert(acmeClient *lego.Client, domains []string, renew *certificate.Resource, user, dnsProvider, mainDomainSuffix string, acmeUseRateLimits bool, keyDatabase database.CertDB) (tls.Certificate, error) {
|
||||||
name := strings.TrimPrefix(domains[0], "*")
|
name := strings.TrimPrefix(domains[0], "*")
|
||||||
if dnsProvider == "" && len(domains[0]) > 0 && domains[0][0] == '*' {
|
if dnsProvider == "" && len(domains[0]) > 0 && domains[0][0] == '*' {
|
||||||
domains = domains[1:]
|
domains = domains[1:]
|
||||||
|
@ -252,7 +248,7 @@ func obtainCert(acmeClient *lego.Client, domains []string, renew *certificate.Re
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
_, working = obtainLocks.Load(name)
|
_, working = obtainLocks.Load(name)
|
||||||
}
|
}
|
||||||
cert, ok := retrieveCertFromDB([]byte(name), mainDomainSuffix, dnsProvider, acmeUseRateLimits, keyDatabase)
|
cert, ok := retrieveCertFromDB(name, mainDomainSuffix, dnsProvider, acmeUseRateLimits, keyDatabase)
|
||||||
if !ok {
|
if !ok {
|
||||||
return tls.Certificate{}, errors.New("certificate failed in synchronous request")
|
return tls.Certificate{}, errors.New("certificate failed in synchronous request")
|
||||||
}
|
}
|
||||||
|
@ -405,7 +401,7 @@ func SetupAcmeConfig(acmeAPI, acmeMail, acmeEabHmac, acmeEabKID string, acmeAcce
|
||||||
return myAcmeConfig, nil
|
return myAcmeConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetupCertificates(mainDomainSuffix []byte, dnsProvider string, acmeConfig *lego.Config, acmeUseRateLimits, enableHTTPServer bool, challengeCache cache.SetGetKey, certDB database.CertDB) error {
|
func SetupCertificates(mainDomainSuffix, dnsProvider string, acmeConfig *lego.Config, acmeUseRateLimits, enableHTTPServer bool, challengeCache cache.SetGetKey, certDB database.CertDB) error {
|
||||||
// getting main cert before ACME account so that we can fail here without hitting rate limits
|
// getting main cert before ACME account so that we can fail here without hitting rate limits
|
||||||
mainCertBytes, err := certDB.Get(string(mainDomainSuffix))
|
mainCertBytes, err := certDB.Get(string(mainDomainSuffix))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -460,7 +456,7 @@ func SetupCertificates(mainDomainSuffix []byte, dnsProvider string, acmeConfig *
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func MaintainCertDB(ctx context.Context, interval time.Duration, mainDomainSuffix []byte, dnsProvider string, acmeUseRateLimits bool, certDB database.CertDB) {
|
func MaintainCertDB(ctx context.Context, interval time.Duration, mainDomainSuffix, dnsProvider string, acmeUseRateLimits bool, certDB database.CertDB) {
|
||||||
for {
|
for {
|
||||||
// clean up expired certs
|
// clean up expired certs
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
@ -468,7 +464,7 @@ func MaintainCertDB(ctx context.Context, interval time.Duration, mainDomainSuffi
|
||||||
keyDatabaseIterator := certDB.Items()
|
keyDatabaseIterator := certDB.Items()
|
||||||
key, resBytes, err := keyDatabaseIterator.Next()
|
key, resBytes, err := keyDatabaseIterator.Next()
|
||||||
for err == nil {
|
for err == nil {
|
||||||
if !bytes.Equal(key, mainDomainSuffix) {
|
if !strings.EqualFold(string(key), mainDomainSuffix) {
|
||||||
resGob := bytes.NewBuffer(resBytes)
|
resGob := bytes.NewBuffer(resBytes)
|
||||||
resDec := gob.NewDecoder(resGob)
|
resDec := gob.NewDecoder(resGob)
|
||||||
res := &certificate.Resource{}
|
res := &certificate.Resource{}
|
||||||
|
|
|
@ -2,7 +2,9 @@ package context
|
||||||
|
|
||||||
import (
|
import (
|
||||||
stdContext "context"
|
stdContext "context"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Context struct {
|
type Context struct {
|
||||||
|
@ -31,6 +33,19 @@ func (c *Context) Response() *http.Response {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Context) String(raw string, status ...int) {
|
||||||
|
code := http.StatusOK
|
||||||
|
if len(status) != 0 {
|
||||||
|
code = status[0]
|
||||||
|
}
|
||||||
|
c.RespWriter.WriteHeader(code)
|
||||||
|
io.Copy(c.RespWriter, strings.NewReader(raw))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) IsMethod(m string) bool {
|
||||||
|
return c.Req.Method == m
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Context) Redirect(uri string, statusCode int) {
|
func (c *Context) Redirect(uri string, statusCode int) {
|
||||||
http.Redirect(c.RespWriter, c.Req, uri, statusCode)
|
http.Redirect(c.RespWriter, c.Req, uri, statusCode)
|
||||||
}
|
}
|
||||||
|
@ -41,3 +56,7 @@ func (c *Context) Redirect(uri string, statusCode int) {
|
||||||
func (c *Context) Path() string {
|
func (c *Context) Path() string {
|
||||||
return c.Req.URL.Path
|
return c.Req.URL.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Context) Host() string {
|
||||||
|
return c.Req.URL.Host
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -27,7 +26,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Handler handles a single HTTP request to the web server.
|
// Handler handles a single HTTP request to the web server.
|
||||||
func Handler(mainDomainSuffix, rawDomain []byte,
|
func Handler(mainDomainSuffix, rawDomain string,
|
||||||
giteaClient *gitea.Client,
|
giteaClient *gitea.Client,
|
||||||
giteaRoot, rawInfoPage string,
|
giteaRoot, rawInfoPage string,
|
||||||
blacklistedPaths, allowedCorsDomains []string,
|
blacklistedPaths, allowedCorsDomains []string,
|
||||||
|
@ -45,7 +44,7 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
||||||
// Enable browser caching for up to 10 minutes
|
// Enable browser caching for up to 10 minutes
|
||||||
ctx.RespWriter.Header().Set("Cache-Control", "public, max-age=600")
|
ctx.RespWriter.Header().Set("Cache-Control", "public, max-age=600")
|
||||||
|
|
||||||
trimmedHost := utils.TrimHostPort([]byte(req.Host))
|
trimmedHost := utils.TrimHostPort(req.Host)
|
||||||
|
|
||||||
// Add HSTS for RawDomain and MainDomainSuffix
|
// Add HSTS for RawDomain and MainDomainSuffix
|
||||||
if hsts := GetHSTSHeader(trimmedHost, mainDomainSuffix, rawDomain); hsts != "" {
|
if hsts := GetHSTSHeader(trimmedHost, mainDomainSuffix, rawDomain); hsts != "" {
|
||||||
|
@ -53,16 +52,16 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block all methods not required for static pages
|
// Block all methods not required for static pages
|
||||||
if !ctx.IsGet() && !ctx.IsHead() && !ctx.IsOptions() {
|
if !ctx.IsMethod(http.MethodGet) && !ctx.IsMethod(http.MethodHead) && !ctx.IsMethod(http.MethodOptions) {
|
||||||
ctx.Response.Header.Set("Allow", "GET, HEAD, OPTIONS")
|
ctx.RespWriter.Header().Set("Allow", http.MethodGet+", "+http.MethodHead+", "+http.MethodOptions) // duplic 1
|
||||||
ctx.Error("Method not allowed", fasthttp.StatusMethodNotAllowed)
|
ctx.String("Method not allowed", fasthttp.StatusMethodNotAllowed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block blacklisted paths (like ACME challenges)
|
// Block blacklisted paths (like ACME challenges)
|
||||||
for _, blacklistedPath := range blacklistedPaths {
|
for _, blacklistedPath := range blacklistedPaths {
|
||||||
if strings.HasPrefix(ctx.Path(), blacklistedPath) {
|
if strings.HasPrefix(ctx.Path(), blacklistedPath) {
|
||||||
html.ReturnErrorPage(ctx, fasthttp.StatusForbidden)
|
html.ReturnErrorPage(ctx, "", fasthttp.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,7 +69,7 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
||||||
// Allow CORS for specified domains
|
// Allow CORS for specified domains
|
||||||
allowCors := false
|
allowCors := false
|
||||||
for _, allowedCorsDomain := range allowedCorsDomains {
|
for _, allowedCorsDomain := range allowedCorsDomains {
|
||||||
if bytes.Equal(trimmedHost, allowedCorsDomain) {
|
if strings.EqualFold(trimmedHost, allowedCorsDomain) {
|
||||||
allowCors = true
|
allowCors = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -79,9 +78,9 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
||||||
ctx.RespWriter.Header().Set(headerAccessControlAllowOrigin, "*")
|
ctx.RespWriter.Header().Set(headerAccessControlAllowOrigin, "*")
|
||||||
ctx.RespWriter.Header().Set(headerAccessControlAllowMethods, http.MethodGet+", "+http.MethodHead)
|
ctx.RespWriter.Header().Set(headerAccessControlAllowMethods, http.MethodGet+", "+http.MethodHead)
|
||||||
}
|
}
|
||||||
ctx.RespWriter.Header().Set("Allow", http.MethodGet+", "+http.MethodHead+", "+http.MethodOptions)
|
|
||||||
if ctx.IsOptions() {
|
|
||||||
|
|
||||||
|
ctx.RespWriter.Header().Set("Allow", http.MethodGet+", "+http.MethodHead+", "+http.MethodOptions) // duplic 1
|
||||||
|
if ctx.IsMethod(http.MethodOptions) {
|
||||||
ctx.Response().StatusCode = http.StatusNoContent
|
ctx.Response().StatusCode = http.StatusNoContent
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -132,7 +131,7 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug().Msg("preparations")
|
log.Debug().Msg("preparations")
|
||||||
if rawDomain != nil && bytes.Equal(trimmedHost, rawDomain) {
|
if rawDomain != "" && strings.EqualFold(trimmedHost, rawDomain) {
|
||||||
// Serve raw content from RawDomain
|
// Serve raw content from RawDomain
|
||||||
log.Debug().Msg("raw domain")
|
log.Debug().Msg("raw domain")
|
||||||
|
|
||||||
|
@ -166,7 +165,7 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Debug().Msg("missing branch")
|
log.Debug().Msg("missing branch")
|
||||||
html.ReturnErrorPage(ctx, http.StatusFailedDependency)
|
html.ReturnErrorPage(ctx, "", http.StatusFailedDependency)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,12 +180,12 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
||||||
canonicalDomainCache)
|
canonicalDomainCache)
|
||||||
return
|
return
|
||||||
|
|
||||||
} else if bytes.HasSuffix(trimmedHost, mainDomainSuffix) {
|
} else if strings.HasSuffix(trimmedHost, mainDomainSuffix) {
|
||||||
// Serve pages from subdomains of MainDomainSuffix
|
// Serve pages from subdomains of MainDomainSuffix
|
||||||
log.Debug().Msg("main domain suffix")
|
log.Debug().Msg("main domain suffix")
|
||||||
|
|
||||||
pathElements := strings.Split(strings.Trim(ctx.Path(), "/"), "/")
|
pathElements := strings.Split(strings.Trim(ctx.Path(), "/"), "/")
|
||||||
targetOwner = string(bytes.TrimSuffix(trimmedHost, mainDomainSuffix))
|
targetOwner = strings.TrimSuffix(trimmedHost, mainDomainSuffix)
|
||||||
targetRepo = pathElements[0]
|
targetRepo = pathElements[0]
|
||||||
targetPath = strings.Trim(strings.Join(pathElements[1:], "/"), "/")
|
targetPath = strings.Trim(strings.Join(pathElements[1:], "/"), "/")
|
||||||
|
|
||||||
|
@ -215,7 +214,7 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
||||||
targetOptions, targetOwner, targetRepo, targetBranch, targetPath,
|
targetOptions, targetOwner, targetRepo, targetBranch, targetPath,
|
||||||
canonicalDomainCache)
|
canonicalDomainCache)
|
||||||
} else {
|
} else {
|
||||||
html.ReturnErrorPage(ctx, http.StatusFailedDependency)
|
html.ReturnErrorPage(ctx, "", http.StatusFailedDependency)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -231,7 +230,7 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
||||||
targetOptions, targetOwner, targetRepo, targetBranch, targetPath,
|
targetOptions, targetOwner, targetRepo, targetBranch, targetPath,
|
||||||
canonicalDomainCache)
|
canonicalDomainCache)
|
||||||
} else {
|
} else {
|
||||||
html.ReturnErrorPage(ctx, http.StatusFailedDependency)
|
html.ReturnErrorPage(ctx, "", http.StatusFailedDependency)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -262,7 +261,7 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Couldn't find a valid repo/branch
|
// Couldn't find a valid repo/branch
|
||||||
html.ReturnErrorPage(ctx, http.StatusFailedDependency)
|
html.ReturnErrorPage(ctx, "", http.StatusFailedDependency)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
trimmedHostStr := string(trimmedHost)
|
trimmedHostStr := string(trimmedHost)
|
||||||
|
@ -270,7 +269,7 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
||||||
// Serve pages from external domains
|
// Serve pages from external domains
|
||||||
targetOwner, targetRepo, targetBranch = dns.GetTargetFromDNS(trimmedHostStr, string(mainDomainSuffix), dnsLookupCache)
|
targetOwner, targetRepo, targetBranch = dns.GetTargetFromDNS(trimmedHostStr, string(mainDomainSuffix), dnsLookupCache)
|
||||||
if targetOwner == "" {
|
if targetOwner == "" {
|
||||||
html.ReturnErrorPage(ctx, http.StatusFailedDependency)
|
html.ReturnErrorPage(ctx, "", http.StatusFailedDependency)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,7 +287,7 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
||||||
targetRepo, targetBranch, pathElements, canonicalLink) {
|
targetRepo, targetBranch, pathElements, canonicalLink) {
|
||||||
canonicalDomain, valid := upstream.CheckCanonicalDomain(giteaClient, targetOwner, targetRepo, targetBranch, trimmedHostStr, string(mainDomainSuffix), canonicalDomainCache)
|
canonicalDomain, valid := upstream.CheckCanonicalDomain(giteaClient, targetOwner, targetRepo, targetBranch, trimmedHostStr, string(mainDomainSuffix), canonicalDomainCache)
|
||||||
if !valid {
|
if !valid {
|
||||||
html.ReturnErrorPage(ctx, http.StatusMisdirectedRequest)
|
html.ReturnErrorPage(ctx, "", http.StatusMisdirectedRequest)
|
||||||
return
|
return
|
||||||
} else if canonicalDomain != trimmedHostStr {
|
} else if canonicalDomain != trimmedHostStr {
|
||||||
// only redirect if the target is also a codeberg page!
|
// only redirect if the target is also a codeberg page!
|
||||||
|
@ -298,7 +297,7 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
html.ReturnErrorPage(ctx, http.StatusFailedDependency)
|
html.ReturnErrorPage(ctx, "", http.StatusFailedDependency)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,7 +308,7 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
html.ReturnErrorPage(ctx, http.StatusFailedDependency)
|
html.ReturnErrorPage(ctx, "", http.StatusFailedDependency)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Handler handles a single HTTP request to the web server.
|
// Handler handles a single HTTP request to the web server.
|
||||||
func Handler(mainDomainSuffix, rawDomain []byte,
|
func Handler(mainDomainSuffix, rawDomain string,
|
||||||
giteaClient *gitea.Client,
|
giteaClient *gitea.Client,
|
||||||
giteaRoot, rawInfoPage string,
|
giteaRoot, rawInfoPage string,
|
||||||
blacklistedPaths, allowedCorsDomains []string,
|
blacklistedPaths, allowedCorsDomains []string,
|
||||||
|
@ -37,7 +37,7 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
||||||
// Enable browser caching for up to 10 minutes
|
// Enable browser caching for up to 10 minutes
|
||||||
ctx.Response.Header.Set("Cache-Control", "public, max-age=600")
|
ctx.Response.Header.Set("Cache-Control", "public, max-age=600")
|
||||||
|
|
||||||
trimmedHost := utils.TrimHostPort(ctx.Request.Host())
|
trimmedHost := utils.TrimHostPort(string(ctx.Request.Host()))
|
||||||
|
|
||||||
// Add HSTS for RawDomain and MainDomainSuffix
|
// Add HSTS for RawDomain and MainDomainSuffix
|
||||||
if hsts := GetHSTSHeader(trimmedHost, mainDomainSuffix, rawDomain); hsts != "" {
|
if hsts := GetHSTSHeader(trimmedHost, mainDomainSuffix, rawDomain); hsts != "" {
|
||||||
|
@ -53,7 +53,7 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
||||||
|
|
||||||
// Block blacklisted paths (like ACME challenges)
|
// Block blacklisted paths (like ACME challenges)
|
||||||
for _, blacklistedPath := range blacklistedPaths {
|
for _, blacklistedPath := range blacklistedPaths {
|
||||||
if bytes.HasPrefix(ctx.Path(), []byte(blacklistedPath)) {
|
if strings.HasPrefix(string(ctx.Path()), blacklistedPath) {
|
||||||
html.ReturnErrorPage(ctx, fasthttp.StatusForbidden)
|
html.ReturnErrorPage(ctx, fasthttp.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
||||||
// Allow CORS for specified domains
|
// Allow CORS for specified domains
|
||||||
allowCors := false
|
allowCors := false
|
||||||
for _, allowedCorsDomain := range allowedCorsDomains {
|
for _, allowedCorsDomain := range allowedCorsDomains {
|
||||||
if bytes.Equal(trimmedHost, []byte(allowedCorsDomain)) {
|
if strings.EqualFold(trimmedHost, allowedCorsDomain) {
|
||||||
allowCors = true
|
allowCors = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug().Msg("preparations")
|
log.Debug().Msg("preparations")
|
||||||
if rawDomain != nil && bytes.Equal(trimmedHost, rawDomain) {
|
if rawDomain != "" && strings.EqualFold(trimmedHost, rawDomain) {
|
||||||
// Serve raw content from RawDomain
|
// Serve raw content from RawDomain
|
||||||
log.Debug().Msg("raw domain")
|
log.Debug().Msg("raw domain")
|
||||||
|
|
||||||
|
@ -172,12 +172,12 @@ func Handler(mainDomainSuffix, rawDomain []byte,
|
||||||
canonicalDomainCache)
|
canonicalDomainCache)
|
||||||
return
|
return
|
||||||
|
|
||||||
} else if bytes.HasSuffix(trimmedHost, mainDomainSuffix) {
|
} else if strings.HasSuffix(trimmedHost, mainDomainSuffix) {
|
||||||
// Serve pages from subdomains of MainDomainSuffix
|
// Serve pages from subdomains of MainDomainSuffix
|
||||||
log.Debug().Msg("main domain suffix")
|
log.Debug().Msg("main domain suffix")
|
||||||
|
|
||||||
pathElements := strings.Split(string(bytes.Trim(ctx.Request.URI().Path(), "/")), "/")
|
pathElements := strings.Split(strings.Trim(string(ctx.Request.URI().Path()), "/"), "/")
|
||||||
targetOwner = string(bytes.TrimSuffix(trimmedHost, mainDomainSuffix))
|
targetOwner = strings.TrimSuffix(trimmedHost, mainDomainSuffix)
|
||||||
targetRepo = pathElements[0]
|
targetRepo = pathElements[0]
|
||||||
targetPath = strings.Trim(strings.Join(pathElements[1:], "/"), "/")
|
targetPath = strings.Trim(strings.Join(pathElements[1:], "/"), "/")
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetHSTSHeader returns a HSTS header with includeSubdomains & preload for MainDomainSuffix and RawDomain, or an empty
|
// GetHSTSHeader returns a HSTS header with includeSubdomains & preload for MainDomainSuffix and RawDomain, or an empty
|
||||||
// string for custom domains.
|
// string for custom domains.
|
||||||
func GetHSTSHeader(host, mainDomainSuffix, rawDomain []byte) string {
|
func GetHSTSHeader(host, mainDomainSuffix, rawDomain string) string {
|
||||||
if bytes.HasSuffix(host, mainDomainSuffix) || bytes.Equal(host, rawDomain) {
|
if strings.HasSuffix(host, mainDomainSuffix) || strings.EqualFold(host, rawDomain) {
|
||||||
return "max-age=63072000; includeSubdomains; preload"
|
return "max-age=63072000; includeSubdomains; preload"
|
||||||
} else {
|
} else {
|
||||||
return ""
|
return ""
|
||||||
|
|
|
@ -3,53 +3,32 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"strings"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
"github.com/valyala/fasthttp"
|
|
||||||
|
|
||||||
"codeberg.org/codeberg/pages/server/cache"
|
"codeberg.org/codeberg/pages/server/cache"
|
||||||
|
"codeberg.org/codeberg/pages/server/context"
|
||||||
"codeberg.org/codeberg/pages/server/utils"
|
"codeberg.org/codeberg/pages/server/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type fasthttpLogger struct{}
|
func SetupServer(handler http.HandlerFunc) http.HandlerFunc {
|
||||||
|
// TODO: enagle gzip compression
|
||||||
func (fasthttpLogger) Printf(format string, args ...interface{}) {
|
return handler
|
||||||
log.Printf("FastHTTP: %s", fmt.Sprintf(format, args...))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetupServer(handler fasthttp.RequestHandler) *fasthttp.Server {
|
func SetupHTTPACMEChallengeServer(challengeCache cache.SetGetKey) http.HandlerFunc {
|
||||||
// Enable compression by wrapping the handler with the compression function provided by FastHTTP
|
challengePath := "/.well-known/acme-challenge/"
|
||||||
compressedHandler := fasthttp.CompressHandlerBrotliLevel(handler, fasthttp.CompressBrotliBestSpeed, fasthttp.CompressBestSpeed)
|
|
||||||
|
|
||||||
return &fasthttp.Server{
|
return func(w http.ResponseWriter, req *http.Request) {
|
||||||
Handler: compressedHandler,
|
ctx := context.New(w, req)
|
||||||
DisablePreParseMultipartForm: true,
|
if strings.HasPrefix(ctx.Path(), challengePath) {
|
||||||
NoDefaultServerHeader: true,
|
challenge, ok := challengeCache.Get(utils.TrimHostPort(ctx.Host()) + "/" + string(strings.TrimPrefix(ctx.Path(), challengePath)))
|
||||||
NoDefaultDate: true,
|
if !ok || challenge == nil {
|
||||||
ReadTimeout: 30 * time.Second, // needs to be this high for ACME certificates with ZeroSSL & HTTP-01 challenge
|
ctx.String("no challenge for this token", http.StatusNotFound)
|
||||||
Logger: fasthttpLogger{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetupHTTPACMEChallengeServer(challengeCache cache.SetGetKey) *fasthttp.Server {
|
|
||||||
challengePath := []byte("/.well-known/acme-challenge/")
|
|
||||||
|
|
||||||
return &fasthttp.Server{
|
|
||||||
Handler: func(ctx *fasthttp.RequestCtx) {
|
|
||||||
if bytes.HasPrefix(ctx.Path(), challengePath) {
|
|
||||||
challenge, ok := challengeCache.Get(string(utils.TrimHostPort(ctx.Host())) + "/" + string(bytes.TrimPrefix(ctx.Path(), challengePath)))
|
|
||||||
if !ok || challenge == nil {
|
|
||||||
ctx.SetStatusCode(http.StatusNotFound)
|
|
||||||
ctx.SetBodyString("no challenge for this token")
|
|
||||||
}
|
|
||||||
ctx.SetBodyString(challenge.(string))
|
|
||||||
} else {
|
|
||||||
ctx.Redirect("https://"+string(ctx.Host())+string(ctx.RequestURI()), http.StatusMovedPermanently)
|
|
||||||
}
|
}
|
||||||
},
|
ctx.String(challenge.(string))
|
||||||
|
} else {
|
||||||
|
ctx.Redirect("https://"+string(ctx.Host())+string(ctx.Path()), http.StatusMovedPermanently)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
|
@ -27,12 +27,12 @@ func SetupServer(handler fasthttp.RequestHandler) *fasthttp.Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetupHTTPACMEChallengeServer(challengeCache cache.SetGetKey) *fasthttp.Server {
|
func SetupHTTPACMEChallengeServer(challengeCache cache.SetGetKey) *fasthttp.Server {
|
||||||
challengePath := []byte("/.well-known/acme-challenge/")
|
challengePath := "/.well-known/acme-challenge/"
|
||||||
|
|
||||||
return &fasthttp.Server{
|
return &fasthttp.Server{
|
||||||
Handler: func(ctx *fasthttp.RequestCtx) {
|
Handler: func(ctx *fasthttp.RequestCtx) {
|
||||||
if bytes.HasPrefix(ctx.Path(), challengePath) {
|
if strings.HasPrefix(string(ctx.Path()), challengePath) {
|
||||||
challenge, ok := challengeCache.Get(string(utils.TrimHostPort(ctx.Host())) + "/" + string(bytes.TrimPrefix(ctx.Path(), challengePath)))
|
challenge, ok := challengeCache.Get(utils.TrimHostPort(string(ctx.Host())) + "/" + strings.TrimPrefix(string(ctx.Path()), challengePath))
|
||||||
if !ok || challenge == nil {
|
if !ok || challenge == nil {
|
||||||
ctx.SetStatusCode(http.StatusNotFound)
|
ctx.SetStatusCode(http.StatusNotFound)
|
||||||
ctx.SetBodyString("no challenge for this token")
|
ctx.SetBodyString("no challenge for this token")
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -16,7 +15,7 @@ import (
|
||||||
|
|
||||||
// tryUpstream forwards the target request to the Gitea API, and shows an error page on failure.
|
// tryUpstream forwards the target request to the Gitea API, and shows an error page on failure.
|
||||||
func tryUpstream(ctx *context.Context, giteaClient *gitea.Client,
|
func tryUpstream(ctx *context.Context, giteaClient *gitea.Client,
|
||||||
mainDomainSuffix, trimmedHost []byte,
|
mainDomainSuffix, trimmedHost string,
|
||||||
|
|
||||||
targetOptions *upstream.Options,
|
targetOptions *upstream.Options,
|
||||||
targetOwner, targetRepo, targetBranch, targetPath string,
|
targetOwner, targetRepo, targetBranch, targetPath string,
|
||||||
|
@ -24,7 +23,7 @@ func tryUpstream(ctx *context.Context, giteaClient *gitea.Client,
|
||||||
canonicalDomainCache cache.SetGetKey,
|
canonicalDomainCache cache.SetGetKey,
|
||||||
) {
|
) {
|
||||||
// check if a canonical domain exists on a request on MainDomain
|
// check if a canonical domain exists on a request on MainDomain
|
||||||
if bytes.HasSuffix(trimmedHost, mainDomainSuffix) {
|
if strings.HasSuffix(trimmedHost, mainDomainSuffix) {
|
||||||
canonicalDomain, _ := upstream.CheckCanonicalDomain(giteaClient, targetOwner, targetRepo, targetBranch, "", string(mainDomainSuffix), canonicalDomainCache)
|
canonicalDomain, _ := upstream.CheckCanonicalDomain(giteaClient, targetOwner, targetRepo, targetBranch, "", string(mainDomainSuffix), canonicalDomainCache)
|
||||||
if !strings.HasSuffix(strings.SplitN(canonicalDomain, "/", 2)[0], string(mainDomainSuffix)) {
|
if !strings.HasSuffix(strings.SplitN(canonicalDomain, "/", 2)[0], string(mainDomainSuffix)) {
|
||||||
canonicalPath := ctx.Req.RequestURI
|
canonicalPath := ctx.Req.RequestURI
|
||||||
|
@ -47,6 +46,6 @@ func tryUpstream(ctx *context.Context, giteaClient *gitea.Client,
|
||||||
|
|
||||||
// Try to request the file from the Gitea API
|
// Try to request the file from the Gitea API
|
||||||
if !targetOptions.Upstream(ctx, giteaClient) {
|
if !targetOptions.Upstream(ctx, giteaClient) {
|
||||||
html.ReturnErrorPage(w, ctx.Response().StatusCode)
|
html.ReturnErrorPage(ctx, "", ctx.Response().StatusCode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
|
@ -16,7 +15,7 @@ import (
|
||||||
|
|
||||||
// tryUpstream forwards the target request to the Gitea API, and shows an error page on failure.
|
// tryUpstream forwards the target request to the Gitea API, and shows an error page on failure.
|
||||||
func tryUpstream(ctx *fasthttp.RequestCtx, giteaClient *gitea.Client,
|
func tryUpstream(ctx *fasthttp.RequestCtx, giteaClient *gitea.Client,
|
||||||
mainDomainSuffix, trimmedHost []byte,
|
mainDomainSuffix, trimmedHost string,
|
||||||
|
|
||||||
targetOptions *upstream.Options,
|
targetOptions *upstream.Options,
|
||||||
targetOwner, targetRepo, targetBranch, targetPath string,
|
targetOwner, targetRepo, targetBranch, targetPath string,
|
||||||
|
@ -24,7 +23,7 @@ func tryUpstream(ctx *fasthttp.RequestCtx, giteaClient *gitea.Client,
|
||||||
canonicalDomainCache cache.SetGetKey,
|
canonicalDomainCache cache.SetGetKey,
|
||||||
) {
|
) {
|
||||||
// check if a canonical domain exists on a request on MainDomain
|
// check if a canonical domain exists on a request on MainDomain
|
||||||
if bytes.HasSuffix(trimmedHost, mainDomainSuffix) {
|
if strings.HasSuffix(trimmedHost, mainDomainSuffix) {
|
||||||
canonicalDomain, _ := upstream.CheckCanonicalDomain(giteaClient, targetOwner, targetRepo, targetBranch, "", string(mainDomainSuffix), canonicalDomainCache)
|
canonicalDomain, _ := upstream.CheckCanonicalDomain(giteaClient, targetOwner, targetRepo, targetBranch, "", string(mainDomainSuffix), canonicalDomainCache)
|
||||||
if !strings.HasSuffix(strings.SplitN(canonicalDomain, "/", 2)[0], string(mainDomainSuffix)) {
|
if !strings.HasSuffix(strings.SplitN(canonicalDomain, "/", 2)[0], string(mainDomainSuffix)) {
|
||||||
canonicalPath := string(ctx.RequestURI())
|
canonicalPath := string(ctx.RequestURI())
|
||||||
|
|
|
@ -31,7 +31,7 @@ func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client) (fin
|
||||||
branch := GetBranchTimestamp(giteaClient, o.TargetOwner, o.TargetRepo, o.TargetBranch)
|
branch := GetBranchTimestamp(giteaClient, o.TargetOwner, o.TargetRepo, o.TargetBranch)
|
||||||
|
|
||||||
if branch == nil {
|
if branch == nil {
|
||||||
html.ReturnErrorPage(ctx, http.StatusFailedDependency)
|
html.ReturnErrorPage(ctx, "", http.StatusFailedDependency)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
o.TargetBranch = branch.Branch
|
o.TargetBranch = branch.Branch
|
||||||
|
@ -39,7 +39,7 @@ func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client) (fin
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.TargetOwner == "" || o.TargetRepo == "" || o.TargetBranch == "" {
|
if o.TargetOwner == "" || o.TargetRepo == "" || o.TargetBranch == "" {
|
||||||
html.ReturnErrorPage(ctx, http.StatusBadRequest)
|
html.ReturnErrorPage(ctx, "", http.StatusBadRequest)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client) (fin
|
||||||
}
|
}
|
||||||
if res != nil && (err != nil || res.StatusCode != http.StatusOK) {
|
if res != nil && (err != nil || res.StatusCode != http.StatusOK) {
|
||||||
log.Printf("Couldn't fetch contents (status code %d): %v\n", res.StatusCode, err)
|
log.Printf("Couldn't fetch contents (status code %d): %v\n", res.StatusCode, err)
|
||||||
html.ReturnErrorPage(ctx, http.StatusInternalServerError)
|
html.ReturnErrorPage(ctx, "", http.StatusInternalServerError)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client) (fin
|
||||||
_, err := io.Copy(ctx.RespWriter, reader)
|
_, err := io.Copy(ctx.RespWriter, reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Couldn't write body: %s\n", err)
|
log.Printf("Couldn't write body: %s\n", err)
|
||||||
html.ReturnErrorPage(ctx, http.StatusInternalServerError)
|
html.ReturnErrorPage(ctx, "", http.StatusInternalServerError)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import "bytes"
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
func TrimHostPort(host []byte) []byte {
|
func TrimHostPort(host string) string {
|
||||||
i := bytes.IndexByte(host, ':')
|
i := strings.IndexByte(host, ':')
|
||||||
if i >= 0 {
|
if i >= 0 {
|
||||||
return host[:i]
|
return host[:i]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue