diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index adf78ad0f8..9297f3d062 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -74,6 +74,7 @@ RUN_USER = ; git ;; especially when the Gitea instance needs to be accessed in a container network. ;; * legacy: detect the public URL from "Host" header if "X-Forwarded-Proto" header exists, otherwise use "ROOT_URL". ;; * auto: always use "Host" header, and also use "X-Forwarded-Proto" header if it exists. If no "Host" header, use "ROOT_URL". +;; * never: always use "ROOT_URL", never detect from request headers. ;PUBLIC_URL_DETECTION = legacy ;; ;; For development purpose only. It makes Gitea handle sub-path ("/sub-path/owner/repo/...") directly when debugging without a reverse proxy. diff --git a/modules/httplib/url.go b/modules/httplib/url.go index 5f35e66964..0133334b2c 100644 --- a/modules/httplib/url.go +++ b/modules/httplib/url.go @@ -72,6 +72,10 @@ func GuessCurrentAppURL(ctx context.Context) string { // GuessCurrentHostURL tries to guess the current full host URL (no sub-path) by http headers, there is no trailing slash. func GuessCurrentHostURL(ctx context.Context) string { + // "never" means always trust ROOT_URL and skip any request header detection. + if setting.PublicURLDetection == setting.PublicURLNever { + return strings.TrimSuffix(setting.AppURL, setting.AppSubURL+"/") + } // Try the best guess to get the current host URL (will be used for public URL) by http headers. // At the moment, if site admin doesn't configure the proxy headers correctly, then Gitea would guess wrong. // There are some cases: diff --git a/modules/httplib/url_test.go b/modules/httplib/url_test.go index 4270d9fa89..728c455cfb 100644 --- a/modules/httplib/url_test.go +++ b/modules/httplib/url_test.go @@ -77,6 +77,21 @@ func TestGuessCurrentHostURL(t *testing.T) { ctx = context.WithValue(t.Context(), RequestContextKey, &http.Request{Host: "req-host:3000", Header: headersWithProto}) assert.Equal(t, "https://req-host:3000", GuessCurrentHostURL(ctx)) }) + + t.Run("Never", func(t *testing.T) { + defer test.MockVariableValue(&setting.PublicURLDetection, setting.PublicURLNever)() + + assert.Equal(t, "http://cfg-host", GuessCurrentHostURL(t.Context())) + + ctx := context.WithValue(t.Context(), RequestContextKey, &http.Request{Host: "req-host:3000"}) + assert.Equal(t, "http://cfg-host", GuessCurrentHostURL(ctx)) + + ctx = context.WithValue(t.Context(), RequestContextKey, &http.Request{Host: "req-host:3000", TLS: &tls.ConnectionState{}}) + assert.Equal(t, "http://cfg-host", GuessCurrentHostURL(ctx)) + + ctx = context.WithValue(t.Context(), RequestContextKey, &http.Request{Host: "req-host:3000", Header: headersWithProto}) + assert.Equal(t, "http://cfg-host", GuessCurrentHostURL(ctx)) + }) } func TestMakeAbsoluteURL(t *testing.T) { diff --git a/modules/setting/server.go b/modules/setting/server.go index 2ea52bc9a5..50a38f544b 100644 --- a/modules/setting/server.go +++ b/modules/setting/server.go @@ -44,6 +44,7 @@ const ( const ( PublicURLAuto = "auto" PublicURLLegacy = "legacy" + PublicURLNever = "never" ) // Server settings @@ -286,7 +287,7 @@ func loadServerFrom(rootCfg ConfigProvider) { defaultAppURL := string(Protocol) + "://" + Domain + ":" + HTTPPort AppURL = sec.Key("ROOT_URL").MustString(defaultAppURL) PublicURLDetection = sec.Key("PUBLIC_URL_DETECTION").MustString(PublicURLLegacy) - if PublicURLDetection != PublicURLAuto && PublicURLDetection != PublicURLLegacy { + if PublicURLDetection != PublicURLAuto && PublicURLDetection != PublicURLLegacy && PublicURLDetection != PublicURLNever { log.Fatal("Invalid PUBLIC_URL_DETECTION value: %s", PublicURLDetection) }