Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add config option "USE_HOST_HEADER" #32564

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions modules/httplib/url.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,18 @@ func GuessCurrentHostURL(ctx context.Context) string {
// 1. The reverse proxy is configured correctly, it passes "X-Forwarded-Proto/Host" headers. Perfect, Gitea can handle it correctly.
// 2. The reverse proxy is not configured correctly, doesn't pass "X-Forwarded-Proto/Host" headers, eg: only one "proxy_pass http://gitea:3000" in Nginx.
// 3. There is no reverse proxy.
// Without an extra config option, Gitea is impossible to distinguish between case 2 and case 3,
// then case 2 would result in wrong guess like guessed AppURL becomes "http://gitea:3000/", which is not accessible by end users.
// So in the future maybe it should introduce a new config option, to let site admin decide how to guess the AppURL.
// With the "USE_HOST_HEADER" config option disabled (default), Gitea is impossible to distinguish between case 2 and case 3,
// When enabling "USE_HOST_HEADER", any reverse proxies must be configured to properly pass "X-Forwarded-Proto/Host" headers,
// otherwise this would result in wrong guess like guessed AppURL becomes "http://gitea:3000/", which is not accessible by end users.
reqScheme := getRequestScheme(req)
if reqScheme == "" {
if setting.UseHostHeader && req.Host != "" {
if req.TLS != nil {
return "https://" + req.Host
}
return "http://" + req.Host
}

return strings.TrimSuffix(setting.AppURL, setting.AppSubURL+"/")
}
// X-Forwarded-Host has many problems: non-standard, not well-defined (X-Forwarded-Port or not), conflicts with Host header.
Expand Down
27 changes: 27 additions & 0 deletions modules/httplib/url_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package httplib

import (
"context"
"crypto/tls"
"net/http"
"testing"

Expand Down Expand Up @@ -39,6 +40,32 @@ func TestIsRelativeURL(t *testing.T) {
}
}

func TestGuessCurrentHostURL(t *testing.T) {
defer test.MockVariableValue(&setting.AppURL, "http://cfg-host/sub/")()
defer test.MockVariableValue(&setting.AppSubURL, "/sub")()

ctx := context.Background()
assert.Equal(t, "http://cfg-host", GuessCurrentHostURL(ctx))

ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
Host: "localhost:3000",
})
assert.Equal(t, "http://cfg-host", GuessCurrentHostURL(ctx))

defer test.MockVariableValue(&setting.UseHostHeader, true)()

ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
Host: "localhost:3000",
})
assert.Equal(t, "http://localhost:3000", GuessCurrentHostURL(ctx))

ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
Host: "localhost",
TLS: &tls.ConnectionState{},
})
assert.Equal(t, "https://localhost", GuessCurrentHostURL(ctx))
}

func TestMakeAbsoluteURL(t *testing.T) {
defer test.MockVariableValue(&setting.Protocol, "http")()
defer test.MockVariableValue(&setting.AppURL, "http://cfg-host/sub/")()
Expand Down
5 changes: 5 additions & 0 deletions modules/setting/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ var (
AppSubURL string
// UseSubURLPath makes Gitea handle requests with sub-path like "/sub-path/owner/repo/...", to make it easier to debug sub-path related problems without a reverse proxy.
UseSubURLPath bool
// UseHostHeader makes Gitea always use the "Host" request header for construction of absolute URLs.
// This requires any reverse proxy to properly pass headers like "X-Forwarded-Proto" and "Host".
// It maps to ini:"USE_HOST_HEADER" in [server] and defaults to false
UseHostHeader bool
// AppDataPath is the default path for storing data.
// It maps to ini:"APP_DATA_PATH" in [server] and defaults to AppWorkPath + "/data"
AppDataPath string
Expand Down Expand Up @@ -277,6 +281,7 @@ func loadServerFrom(rootCfg ConfigProvider) {
// This value is empty if site does not have sub-url.
AppSubURL = strings.TrimSuffix(appURL.Path, "/")
UseSubURLPath = sec.Key("USE_SUB_URL_PATH").MustBool(false)
UseHostHeader = sec.Key("USE_HOST_HEADER").MustBool(false)
StaticURLPrefix = strings.TrimSuffix(sec.Key("STATIC_URL_PREFIX").MustString(AppSubURL), "/")

// Check if Domain differs from AppURL domain than update it to AppURL's domain
Expand Down
Loading