0
0
Fork 0
mirror of https://github.com/go-gitea/gitea synced 2024-11-25 04:52:47 +01:00

Fix duplicate sub-path for avatars (#31365) (#31368)

Backport #31365, only backport necessary changes.
This commit is contained in:
wxiaoguang 2024-06-15 11:44:44 +08:00 committed by GitHub
parent 188e515efc
commit 52925e9c7c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 86 additions and 16 deletions

View file

@ -0,0 +1,28 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repo
import (
"testing"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
"github.com/stretchr/testify/assert"
)
func TestRepoAvatarLink(t *testing.T) {
defer test.MockVariableValue(&setting.AppURL, "https://localhost/")()
defer test.MockVariableValue(&setting.AppSubURL, "")()
repo := &Repository{ID: 1, Avatar: "avatar.png"}
link := repo.AvatarLink(db.DefaultContext)
assert.Equal(t, "https://localhost/repo-avatars/avatar.png", link)
setting.AppURL = "https://localhost/sub-path/"
setting.AppSubURL = "/sub-path"
link = repo.AvatarLink(db.DefaultContext)
assert.Equal(t, "https://localhost/sub-path/repo-avatars/avatar.png", link)
}

View file

@ -89,9 +89,11 @@ func (u *User) AvatarLinkWithSize(ctx context.Context, size int) string {
return avatars.GenerateEmailAvatarFastLink(ctx, u.AvatarEmail, size) return avatars.GenerateEmailAvatarFastLink(ctx, u.AvatarEmail, size)
} }
// AvatarLink returns the full avatar url with http host. TODO: refactor it to a relative URL, but it is still used in API response at the moment // AvatarLink returns the full avatar url with http host.
// TODO: refactor it to a relative URL, but it is still used in API response at the moment
func (u *User) AvatarLink(ctx context.Context) string { func (u *User) AvatarLink(ctx context.Context) string {
return httplib.MakeAbsoluteURL(ctx, u.AvatarLinkWithSize(ctx, 0)) relLink := u.AvatarLinkWithSize(ctx, 0) // it can't be empty
return httplib.MakeAbsoluteURL(ctx, relLink)
} }
// IsUploadAvatarChanged returns true if the current user's avatar would be changed with the provided data // IsUploadAvatarChanged returns true if the current user's avatar would be changed with the provided data

View file

@ -0,0 +1,28 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package user
import (
"testing"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
"github.com/stretchr/testify/assert"
)
func TestUserAvatarLink(t *testing.T) {
defer test.MockVariableValue(&setting.AppURL, "https://localhost/")()
defer test.MockVariableValue(&setting.AppSubURL, "")()
u := &User{ID: 1, Avatar: "avatar.png"}
link := u.AvatarLink(db.DefaultContext)
assert.Equal(t, "https://localhost/avatars/avatar.png", link)
setting.AppURL = "https://localhost/sub-path/"
setting.AppSubURL = "/sub-path"
link = u.AvatarLink(db.DefaultContext)
assert.Equal(t, "https://localhost/sub-path/avatars/avatar.png", link)
}

View file

@ -57,11 +57,16 @@ func getForwardedHost(req *http.Request) string {
return req.Header.Get("X-Forwarded-Host") return req.Header.Get("X-Forwarded-Host")
} }
// GuessCurrentAppURL tries to guess the current full URL by http headers. It always has a '/' suffix, exactly the same as setting.AppURL // GuessCurrentAppURL tries to guess the current full app URL (with sub-path) by http headers. It always has a '/' suffix, exactly the same as setting.AppURL
func GuessCurrentAppURL(ctx context.Context) string { func GuessCurrentAppURL(ctx context.Context) string {
return GuessCurrentHostURL(ctx) + setting.AppSubURL + "/"
}
// 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 {
req, ok := ctx.Value(RequestContextKey).(*http.Request) req, ok := ctx.Value(RequestContextKey).(*http.Request)
if !ok { if !ok {
return setting.AppURL return strings.TrimSuffix(setting.AppURL, setting.AppSubURL+"/")
} }
// If no scheme provided by reverse proxy, then do not guess the AppURL, use the configured one. // If no scheme provided by reverse proxy, then do not guess the AppURL, use the configured one.
// At the moment, if site admin doesn't configure the proxy headers correctly, then Gitea would guess wrong. // At the moment, if site admin doesn't configure the proxy headers correctly, then Gitea would guess wrong.
@ -74,20 +79,27 @@ func GuessCurrentAppURL(ctx context.Context) string {
// So in the future maybe it should introduce a new config option, to let site admin decide how to guess the AppURL. // So in the future maybe it should introduce a new config option, to let site admin decide how to guess the AppURL.
reqScheme := getRequestScheme(req) reqScheme := getRequestScheme(req)
if reqScheme == "" { if reqScheme == "" {
return setting.AppURL return strings.TrimSuffix(setting.AppURL, setting.AppSubURL+"/")
} }
reqHost := getForwardedHost(req) reqHost := getForwardedHost(req)
if reqHost == "" { if reqHost == "" {
reqHost = req.Host reqHost = req.Host
} }
return reqScheme + "://" + reqHost + setting.AppSubURL + "/" return reqScheme + "://" + reqHost
} }
func MakeAbsoluteURL(ctx context.Context, s string) string { // MakeAbsoluteURL tries to make a link to an absolute URL:
if IsRelativeURL(s) { // * If link is empty, it returns the current app URL.
return GuessCurrentAppURL(ctx) + strings.TrimPrefix(s, "/") // * If link is absolute, it returns the link.
// * Otherwise, it returns the current host URL + link, the link itself should have correct sub-path (AppSubURL) if needed.
func MakeAbsoluteURL(ctx context.Context, link string) string {
if link == "" {
return GuessCurrentAppURL(ctx)
} }
return s if !IsRelativeURL(link) {
return link
}
return GuessCurrentHostURL(ctx) + "/" + strings.TrimPrefix(link, "/")
} }
func IsCurrentGiteaSiteURL(ctx context.Context, s string) bool { func IsCurrentGiteaSiteURL(ctx context.Context, s string) bool {

View file

@ -46,14 +46,14 @@ func TestMakeAbsoluteURL(t *testing.T) {
ctx := context.Background() ctx := context.Background()
assert.Equal(t, "http://cfg-host/sub/", MakeAbsoluteURL(ctx, "")) assert.Equal(t, "http://cfg-host/sub/", MakeAbsoluteURL(ctx, ""))
assert.Equal(t, "http://cfg-host/sub/foo", MakeAbsoluteURL(ctx, "foo")) assert.Equal(t, "http://cfg-host/foo", MakeAbsoluteURL(ctx, "foo"))
assert.Equal(t, "http://cfg-host/sub/foo", MakeAbsoluteURL(ctx, "/foo")) assert.Equal(t, "http://cfg-host/foo", MakeAbsoluteURL(ctx, "/foo"))
assert.Equal(t, "http://other/foo", MakeAbsoluteURL(ctx, "http://other/foo")) assert.Equal(t, "http://other/foo", MakeAbsoluteURL(ctx, "http://other/foo"))
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{ ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
Host: "user-host", Host: "user-host",
}) })
assert.Equal(t, "http://cfg-host/sub/foo", MakeAbsoluteURL(ctx, "/foo")) assert.Equal(t, "http://cfg-host/foo", MakeAbsoluteURL(ctx, "/foo"))
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{ ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
Host: "user-host", Host: "user-host",
@ -61,7 +61,7 @@ func TestMakeAbsoluteURL(t *testing.T) {
"X-Forwarded-Host": {"forwarded-host"}, "X-Forwarded-Host": {"forwarded-host"},
}, },
}) })
assert.Equal(t, "http://cfg-host/sub/foo", MakeAbsoluteURL(ctx, "/foo")) assert.Equal(t, "http://cfg-host/foo", MakeAbsoluteURL(ctx, "/foo"))
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{ ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
Host: "user-host", Host: "user-host",
@ -70,7 +70,7 @@ func TestMakeAbsoluteURL(t *testing.T) {
"X-Forwarded-Proto": {"https"}, "X-Forwarded-Proto": {"https"},
}, },
}) })
assert.Equal(t, "https://forwarded-host/sub/foo", MakeAbsoluteURL(ctx, "/foo")) assert.Equal(t, "https://forwarded-host/foo", MakeAbsoluteURL(ctx, "/foo"))
} }
func TestIsCurrentGiteaSiteURL(t *testing.T) { func TestIsCurrentGiteaSiteURL(t *testing.T) {

View file

@ -117,7 +117,7 @@ func apiErrorDefined(ctx *context.Context, err *namedError) {
func apiUnauthorizedError(ctx *context.Context) { func apiUnauthorizedError(ctx *context.Context) {
// container registry requires that the "/v2" must be in the root, so the sub-path in AppURL should be removed // container registry requires that the "/v2" must be in the root, so the sub-path in AppURL should be removed
realmURL := strings.TrimSuffix(httplib.GuessCurrentAppURL(ctx), setting.AppSubURL+"/") + "/v2/token" realmURL := httplib.GuessCurrentHostURL(ctx) + "/v2/token"
ctx.Resp.Header().Add("WWW-Authenticate", `Bearer realm="`+realmURL+`",service="container_registry",scope="*"`) ctx.Resp.Header().Add("WWW-Authenticate", `Bearer realm="`+realmURL+`",service="container_registry",scope="*"`)
apiErrorDefined(ctx, errUnauthorized) apiErrorDefined(ctx, errUnauthorized)
} }