diff --git a/modules/git/ref.go b/modules/git/ref.go
index 0ac6094e3da53..a6e53ced8317c 100644
--- a/modules/git/ref.go
+++ b/modules/git/ref.go
@@ -5,9 +5,9 @@ package git
import (
"regexp"
+ "slices"
"strings"
- "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
)
@@ -85,20 +85,6 @@ func RefNameFromCommit(shortName string) RefName {
return RefName(shortName)
}
-func RefNameFromTypeAndShortName(tp RefType, shortName string) RefName {
- switch tp {
- case RefTypeBranch:
- return RefNameFromBranch(shortName)
- case RefTypeTag:
- return RefNameFromTag(shortName)
- case RefTypeCommit:
- return RefNameFromCommit(shortName)
- default:
- setting.PanicInDevOrTesting("Unknown RefType: %v", tp)
- return ""
- }
-}
-
func (ref RefName) String() string {
return string(ref)
}
@@ -235,3 +221,11 @@ func (ref RefName) RefWebLinkPath() string {
}
return string(refType) + "/" + util.PathEscapeSegments(ref.ShortName())
}
+
+func RefNameFromUserInput(ref string, allowedTypes ...RefType) RefName {
+ refName := RefName(ref)
+ if !slices.Contains(allowedTypes, refName.RefType()) {
+ return ""
+ }
+ return refName
+}
diff --git a/routers/web/repo/find.go b/routers/web/repo/find.go
index 530d75ff1b151..2a505971b8975 100644
--- a/routers/web/repo/find.go
+++ b/routers/web/repo/find.go
@@ -5,7 +5,9 @@ package repo
import (
"net/http"
+ "net/url"
+ "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/context"
@@ -18,8 +20,8 @@ const (
// FindFiles render the page to find repository files
func FindFiles(ctx *context.Context) {
path := ctx.PathParam("*")
- ctx.Data["TreeLink"] = ctx.Repo.RepoLink + "/src/" + util.PathEscapeSegments(path)
- ctx.Data["DataLink"] = ctx.Repo.RepoLink + "/tree-list/" + util.PathEscapeSegments(path) +
- "?ref_type=" + ctx.FormTrim("ref_type") + "&ref_name=" + ctx.FormTrim("ref_name")
+ ref := git.RefNameFromUserInput(ctx.FormTrim("ref"), git.RefTypeBranch, git.RefTypeTag, git.RefTypeCommit)
+ ctx.Data["TreeLink"] = ctx.Repo.RepoLink + "/src/" + ref.RefWebLinkPath() + "/" + util.PathEscapeSegments(path)
+ ctx.Data["DataLink"] = ctx.Repo.RepoLink + "/tree-list/" + util.PathEscapeSegments(path) + "?ref=" + url.QueryEscape(ctx.FormTrim("ref"))
ctx.HTML(http.StatusOK, tplFindFiles)
}
diff --git a/routers/web/repo/treelist.go b/routers/web/repo/treelist.go
index d11af4669f90c..6c3e0d83751fa 100644
--- a/routers/web/repo/treelist.go
+++ b/routers/web/repo/treelist.go
@@ -15,7 +15,12 @@ import (
// TreeList get all files' entries of a repository
func TreeList(ctx *context.Context) {
- tree, err := ctx.Repo.Commit.SubTree("/")
+ _, commit, err := ctx.Repo.GetRefCommit(ctx.FormString("ref"), git.RefTypeBranch, git.RefTypeTag, git.RefTypeCommit)
+ if err != nil {
+ ctx.ServerError("GetRefCommit", err)
+ return
+ }
+ tree, err := commit.SubTree("/")
if err != nil {
ctx.ServerError("Repo.Commit.SubTree", err)
return
diff --git a/routers/web/web.go b/routers/web/web.go
index 30a0c74f7a5f5..687664e81aeb7 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -1158,8 +1158,7 @@ func registerRoutes(m *web.Router) {
m.Group("/{username}/{reponame}", func() {
m.Get("/find/*", repo.FindFiles)
m.Get("/find", repo.FindFiles)
- m.Get("/tree-list/*", context.RepoRefByQueries(), repo.TreeList)
- m.Get("/tree-list", context.RepoRefByQueries(), repo.TreeList)
+ m.Get("/tree-list", repo.TreeList)
m.Get("/compare", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff)
m.Combo("/compare/*", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists).
Get(repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff).
diff --git a/services/context/repo.go b/services/context/repo.go
index 21aeca5111db4..e05580b922431 100644
--- a/services/context/repo.go
+++ b/services/context/repo.go
@@ -91,6 +91,22 @@ func (r *Repository) GetObjectFormat() git.ObjectFormat {
return git.ObjectFormatFromName(r.Repository.ObjectFormatName)
}
+func (r *Repository) GetRefCommit(ref string, allowedTypes ...git.RefType) (git.RefName, *git.Commit, error) {
+ refName := git.RefNameFromUserInput(ref, allowedTypes...)
+ if refName == "" {
+ return "", nil, errors.New("invalid ref")
+ }
+ commitID, err := r.GitRepo.GetRefCommitID(refName.String())
+ if err != nil {
+ return "", nil, err
+ }
+ commit, err := r.GitRepo.GetCommit(commitID)
+ if err != nil {
+ return "", nil, err
+ }
+ return refName, commit, nil
+}
+
// RepoMustNotBeArchived checks if a repo is archived
func RepoMustNotBeArchived() func(ctx *Context) {
return func(ctx *Context) {
@@ -780,6 +796,20 @@ type RepoRefByTypeOptions struct {
IgnoreNotExistErr bool
}
+func repoRefFullName(typ git.RefType, shortName string) git.RefName {
+ switch typ {
+ case git.RefTypeBranch:
+ return git.RefNameFromBranch(shortName)
+ case git.RefTypeTag:
+ return git.RefNameFromTag(shortName)
+ case git.RefTypeCommit:
+ return git.RefNameFromCommit(shortName)
+ default:
+ setting.PanicInDevOrTesting("Unknown RepoRefType: %v", typ)
+ return git.RefNameFromBranch("main") // just a dummy result, it shouldn't happen
+ }
+}
+
// RepoRefByType handles repository reference name for a specific type
// of repository reference
func RepoRefByType(detectRefType git.RefType, opts ...RepoRefByTypeOptions) func(*Context) {
@@ -842,7 +872,7 @@ func RepoRefByType(detectRefType git.RefType, opts ...RepoRefByTypeOptions) func
} else {
refShortName = getRefName(ctx.Base, ctx.Repo, reqPath, refType)
}
- ctx.Repo.RefFullName = git.RefNameFromTypeAndShortName(refType, refShortName)
+ ctx.Repo.RefFullName = repoRefFullName(refType, refShortName)
isRenamedBranch, has := ctx.Data["IsRenamedBranch"].(bool)
if isRenamedBranch && has {
renamedBranchName := ctx.Data["RenamedBranchName"].(string)
@@ -939,57 +969,6 @@ func RepoRefByType(detectRefType git.RefType, opts ...RepoRefByTypeOptions) func
}
}
-func RepoRefByQueries() func(ctx *Context) {
- return func(ctx *Context) {
- if ctx.Repo.Repository.IsEmpty {
- // assume the user is viewing the (non-existent) default branch
- ctx.Repo.IsViewBranch = true
- ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
- ctx.Repo.RefFullName = git.RefNameFromBranch(ctx.Repo.BranchName)
- return
- }
-
- var err error
- if ctx.Repo.GitRepo == nil {
- ctx.Repo.GitRepo, err = gitrepo.RepositoryFromRequestContextOrOpen(ctx, ctx.Repo.Repository)
- if err != nil {
- ctx.ServerError(fmt.Sprintf("Open Repository %v failed", ctx.Repo.Repository.FullName()), err)
- return
- }
- }
-
- ctx.Repo.RefFullName = git.RefNameFromTypeAndShortName(git.RefType(ctx.FormTrim("ref_type")), ctx.FormTrim("ref_name"))
- if ctx.Repo.RefFullName == "" {
- ctx.Error(http.StatusBadRequest, "invalid ref type or name")
- return
- }
-
- switch ctx.Repo.RefFullName.RefType() {
- case git.RefTypeBranch:
- ctx.Repo.IsViewBranch = true
- ctx.Repo.BranchName = ctx.Repo.RefFullName.ShortName()
- case git.RefTypeTag:
- ctx.Repo.IsViewTag = true
- ctx.Repo.TagName = ctx.Repo.RefFullName.ShortName()
- case git.RefTypeCommit:
- ctx.Repo.IsViewCommit = true
- ctx.Repo.CommitID = ctx.Repo.RefFullName.ShortName()
- }
-
- ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(ctx.Repo.RefFullName.String())
- if err != nil {
- if git.IsErrNotExist(err) {
- ctx.NotFound("GetCommit", err)
- } else {
- ctx.ServerError("GetCommit", err)
- }
- return
- }
- ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
- ctx.Repo.TreePath = ctx.PathParam("*")
- }
-}
-
// GitHookService checks if repository Git hooks service has been enabled.
func GitHookService() func(ctx *Context) {
return func(ctx *Context) {
diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl
index a0c181a7d79d7..0a49687093ae1 100644
--- a/templates/repo/home.tmpl
+++ b/templates/repo/home.tmpl
@@ -62,7 +62,8 @@
{{if $isTreePathRoot}}
- {{ctx.Locale.Tr "repo.find_file.go_to_file"}}
+ {{/* FIXME: it should still use RefTypeNameSubURL, otherwise the link is ugly */}}
+ {{ctx.Locale.Tr "repo.find_file.go_to_file"}}
{{end}}
{{if and .CanWriteCode .IsViewBranch (not .Repository.IsMirror) (not .Repository.IsArchived) (not .IsViewFile)}}