This commit is contained in:
wxiaoguang 2024-06-15 13:59:05 +08:00
parent 516ff5bc8a
commit cda64789a2
4 changed files with 50 additions and 30 deletions

View File

@ -19,10 +19,24 @@ import (
"gitea.com/go-chi/session"
"github.com/chi-middleware/proxy"
"github.com/go-chi/chi/v5"
)
// ProtocolMiddlewares returns HTTP protocol related middlewares, and it provides a global panic recovery
func ProtocolMiddlewares() (handlers []any) {
// make sure chi uses EscapedPath(RawPath) as RoutePath, then "%2f" could be handled correctly
handlers = append(handlers, func(next http.Handler) http.Handler {
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
ctx := chi.RouteContext(req.Context())
if req.URL.RawPath == "" {
ctx.RoutePath = req.URL.EscapedPath()
} else {
ctx.RoutePath = req.URL.RawPath
}
next.ServeHTTP(resp, req)
})
})
// prepare the ContextData and panic recovery
handlers = append(handlers, func(next http.Handler) http.Handler {
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {

View File

@ -18,6 +18,7 @@ import (
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/modules/web/middleware"
@ -142,23 +143,27 @@ func (b *Base) RemoteAddr() string {
return b.Req.RemoteAddr
}
// Params returns the param on route
func (b *Base) Params(p string) string {
s, _ := url.PathUnescape(chi.URLParam(b.Req, strings.TrimPrefix(p, ":")))
// Params returns the param in request path, eg: "/{var}" => "/a%2fb", then `var == "a/b"`
func (b *Base) Params(name string) string {
s, err := url.PathUnescape(b.PathParamRaw(name))
if err != nil && !setting.IsProd {
panic("Failed to unescape path param: " + err.Error() + ", there seems to be a double-unescaping bug")
}
return s
}
func (b *Base) PathParamRaw(p string) string {
return chi.URLParam(b.Req, strings.TrimPrefix(p, ":"))
// PathParamRaw returns the raw param in request path, eg: "/{var}" => "/a%2fb", then `var == "a%2fb"`
func (b *Base) PathParamRaw(name string) string {
return chi.URLParam(b.Req, strings.TrimPrefix(name, ":"))
}
// ParamsInt64 returns the param on route as int64
// ParamsInt64 returns the param in request path as int64
func (b *Base) ParamsInt64(p string) int64 {
v, _ := strconv.ParseInt(b.Params(p), 10, 64)
return v
}
// SetParams set params into routes
// SetParams set request path params into routes
func (b *Base) SetParams(k, v string) {
chiCtx := chi.RouteContext(b)
chiCtx.URLParams.Add(strings.TrimPrefix(k, ":"), url.PathEscape(v))

View File

@ -1006,12 +1006,12 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
if refType == RepoRefLegacy {
// redirect from old URL scheme to new URL scheme
prefix := strings.TrimPrefix(setting.AppSubURL+strings.ToLower(strings.TrimSuffix(ctx.Req.URL.Path, ctx.Params("*"))), strings.ToLower(ctx.Repo.RepoLink))
ctx.Redirect(path.Join(
redirect := path.Join(
ctx.Repo.RepoLink,
util.PathEscapeSegments(prefix),
ctx.Repo.BranchNameSubURL(),
util.PathEscapeSegments(ctx.Repo.TreePath)))
util.PathEscapeSegments(ctx.Repo.TreePath))
ctx.Redirect(redirect)
return cancel
}
}

View File

@ -4,6 +4,7 @@
package integration
import (
"fmt"
"net/http"
"net/url"
"path"
@ -14,22 +15,6 @@ import (
"github.com/stretchr/testify/assert"
)
func testSrcRouteRedirect(t *testing.T, session *TestSession, user, repo, route, expectedLocation string, expectedStatus int) {
prefix := path.Join("/", user, repo, "src")
// Make request
req := NewRequest(t, "GET", path.Join(prefix, route))
resp := session.MakeRequest(t, req, http.StatusSeeOther)
// Check Location header
location := resp.Header().Get("Location")
assert.Equal(t, path.Join(prefix, expectedLocation), location)
// Perform redirect
req = NewRequest(t, "GET", location)
session.MakeRequest(t, req, expectedStatus)
}
func setDefaultBranch(t *testing.T, session *TestSession, user, repo, branch string) {
location := path.Join("/", user, repo, "settings/branches")
csrf := GetCSRF(t, session, location)
@ -41,7 +26,7 @@ func setDefaultBranch(t *testing.T, session *TestSession, user, repo, branch str
session.MakeRequest(t, req, http.StatusSeeOther)
}
func TestNonasciiBranches(t *testing.T) {
func TestNonAsciiBranches(t *testing.T) {
testRedirects := []struct {
from string
to string
@ -98,6 +83,7 @@ func TestNonasciiBranches(t *testing.T) {
to: "branch/%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81",
status: http.StatusOK,
},
// Tags
{
from: "Тэг",
@ -119,6 +105,7 @@ func TestNonasciiBranches(t *testing.T) {
to: "tag/%E3%82%BF%E3%82%B0/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.md",
status: http.StatusOK,
},
// Files
{
from: "README.md",
@ -135,6 +122,7 @@ func TestNonasciiBranches(t *testing.T) {
to: "branch/Plus+Is+Not+Space/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.md",
status: http.StatusNotFound, // it's not on default branch
},
// Same but url-encoded (few tests)
{
from: "%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81",
@ -205,10 +193,23 @@ func TestNonasciiBranches(t *testing.T) {
session := loginUser(t, user)
setDefaultBranch(t, session, user, repo, "Plus+Is+Not+Space")
defer setDefaultBranch(t, session, user, repo, "master")
for _, test := range testRedirects {
testSrcRouteRedirect(t, session, user, repo, test.from, test.to, test.status)
}
t.Run(test.from, func(t *testing.T) {
req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/src/%s", user, repo, test.from))
resp := session.MakeRequest(t, req, http.StatusSeeOther)
if resp.Code != http.StatusSeeOther {
return
}
setDefaultBranch(t, session, user, repo, "master")
redirectLocation := resp.Header().Get("Location")
if !assert.Equal(t, fmt.Sprintf("/%s/%s/src/%s", user, repo, test.to), redirectLocation) {
return
}
req = NewRequest(t, "GET", redirectLocation)
session.MakeRequest(t, req, test.status)
})
}
}