2022-11-12 18:44:04 +01:00
package handler
2021-12-05 14:45:17 +01:00
import (
2022-07-27 17:25:08 +02:00
"net/http"
2021-12-05 14:45:17 +01:00
"strings"
2021-12-05 15:02:44 +01:00
"github.com/rs/zerolog/log"
2021-12-05 14:45:17 +01:00
"codeberg.org/codeberg/pages/html"
2021-12-05 15:02:44 +01:00
"codeberg.org/codeberg/pages/server/cache"
2022-08-28 15:33:10 +02:00
"codeberg.org/codeberg/pages/server/context"
2022-06-11 23:02:06 +02:00
"codeberg.org/codeberg/pages/server/gitea"
2022-06-14 20:35:11 +02:00
"codeberg.org/codeberg/pages/server/version"
2021-12-05 14:45:17 +01:00
)
2022-08-28 15:33:10 +02:00
const (
headerAccessControlAllowOrigin = "Access-Control-Allow-Origin"
headerAccessControlAllowMethods = "Access-Control-Allow-Methods"
)
2021-12-05 14:45:17 +01:00
// Handler handles a single HTTP request to the web server.
2022-08-28 16:21:37 +02:00
func Handler ( mainDomainSuffix , rawDomain string ,
2022-06-11 23:02:06 +02:00
giteaClient * gitea . Client ,
2022-11-12 02:54:56 +01:00
rawInfoPage string ,
2022-08-28 15:33:10 +02:00
blacklistedPaths , allowedCorsDomains [ ] string ,
2022-07-27 15:39:46 +02:00
dnsLookupCache , canonicalDomainCache cache . SetGetKey ,
2022-07-27 17:25:08 +02:00
) http . HandlerFunc {
return func ( w http . ResponseWriter , req * http . Request ) {
2022-08-28 14:35:27 +02:00
log := log . With ( ) . Strs ( "Handler" , [ ] string { string ( req . Host ) , req . RequestURI } ) . Logger ( )
2022-08-28 15:33:10 +02:00
ctx := context . New ( w , req )
2021-12-05 14:45:17 +01:00
2022-08-28 15:33:10 +02:00
ctx . RespWriter . Header ( ) . Set ( "Server" , "CodebergPages/" + version . Version )
2021-12-05 14:45:17 +01:00
// Force new default from specification (since November 2020) - see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy#strict-origin-when-cross-origin
2022-08-28 15:33:10 +02:00
ctx . RespWriter . Header ( ) . Set ( "Referrer-Policy" , "strict-origin-when-cross-origin" )
2021-12-05 14:45:17 +01:00
// Enable browser caching for up to 10 minutes
2022-08-28 15:33:10 +02:00
ctx . RespWriter . Header ( ) . Set ( "Cache-Control" , "public, max-age=600" )
2021-12-05 14:45:17 +01:00
2022-11-12 19:57:37 +01:00
trimmedHost := ctx . TrimHostPort ( )
2021-12-05 14:45:17 +01:00
// Add HSTS for RawDomain and MainDomainSuffix
2022-11-07 23:01:31 +01:00
if hsts := getHSTSHeader ( trimmedHost , mainDomainSuffix , rawDomain ) ; hsts != "" {
2022-08-28 15:33:10 +02:00
ctx . RespWriter . Header ( ) . Set ( "Strict-Transport-Security" , hsts )
2021-12-05 14:45:17 +01:00
}
2022-11-12 13:10:07 +01:00
// Handle all http methods
ctx . RespWriter . Header ( ) . Set ( "Allow" , http . MethodGet + ", " + http . MethodHead + ", " + http . MethodOptions )
switch ctx . Req . Method {
case http . MethodOptions :
// return Allow header
ctx . RespWriter . WriteHeader ( http . StatusNoContent )
return
case http . MethodGet ,
http . MethodHead :
// end switch case and handle allowed requests
break
default :
// Block all methods not required for static pages
2022-11-07 21:34:23 +01:00
ctx . String ( "Method not allowed" , http . StatusMethodNotAllowed )
2021-12-05 14:45:17 +01:00
return
}
// Block blacklisted paths (like ACME challenges)
for _ , blacklistedPath := range blacklistedPaths {
2022-08-28 15:33:10 +02:00
if strings . HasPrefix ( ctx . Path ( ) , blacklistedPath ) {
2022-11-07 22:47:03 +01:00
html . ReturnErrorPage ( ctx , "requested blacklisted path" , http . StatusForbidden )
2021-12-05 14:45:17 +01:00
return
}
}
// Allow CORS for specified domains
2022-04-10 18:11:00 +02:00
allowCors := false
for _ , allowedCorsDomain := range allowedCorsDomains {
2022-08-28 16:21:37 +02:00
if strings . EqualFold ( trimmedHost , allowedCorsDomain ) {
2022-04-10 18:11:00 +02:00
allowCors = true
break
2021-12-05 14:45:17 +01:00
}
2022-04-10 18:11:00 +02:00
}
if allowCors {
2022-08-28 15:33:10 +02:00
ctx . RespWriter . Header ( ) . Set ( headerAccessControlAllowOrigin , "*" )
ctx . RespWriter . Header ( ) . Set ( headerAccessControlAllowMethods , http . MethodGet + ", " + http . MethodHead )
2022-04-10 18:11:00 +02:00
}
2022-07-27 17:25:08 +02:00
2021-12-05 14:45:17 +01:00
// Prepare request information to Gitea
2022-11-12 14:08:08 +01:00
pathElements := strings . Split ( strings . Trim ( ctx . Path ( ) , "/" ) , "/" )
2021-12-05 14:45:17 +01:00
2022-08-28 16:21:37 +02:00
if rawDomain != "" && strings . EqualFold ( trimmedHost , rawDomain ) {
2022-11-12 19:57:37 +01:00
log . Debug ( ) . Msg ( "raw domain request detecded" )
handleRaw ( log , ctx , giteaClient ,
mainDomainSuffix , rawInfoPage ,
trimmedHost ,
pathElements ,
canonicalDomainCache )
2022-08-28 16:21:37 +02:00
} else if strings . HasSuffix ( trimmedHost , mainDomainSuffix ) {
2022-11-12 19:57:37 +01:00
log . Debug ( ) . Msg ( "subdomain request detecded" )
handleSubDomain ( log , ctx , giteaClient ,
mainDomainSuffix ,
trimmedHost ,
pathElements ,
canonicalDomainCache )
2021-12-05 14:45:17 +01:00
} else {
2022-11-12 19:57:37 +01:00
log . Debug ( ) . Msg ( "custom domain request detecded" )
handleCustomDomain ( log , ctx , giteaClient ,
mainDomainSuffix ,
trimmedHost ,
pathElements ,
dnsLookupCache , canonicalDomainCache )
2021-12-05 14:45:17 +01:00
}
}
}