mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-03 04:29:41 +00:00
fix(api): accept fully-qualified refs in contents API (#38650)
`GET/POST` repository contents endpoints resolve the `ref` query parameter through `ResolveRefCommit`, which previously only accepted short branch/tag names or commit IDs. Clients that pass fully-qualified Git refs (GitHub-compatible), e.g. `ref=refs%2Fheads%2Fmain` or `ref=refs%2Ftags%2Fv1.0`, received 404 "object does not exist". This change accepts fully-qualified **`refs/heads/*`** and **`refs/tags/*`** only, then falls back to the existing short-name and SHA logic. Other `refs/*` prefixes (e.g. `refs/pull/`, `refs/for/`) are rejected. Fixes #38197 --------- Co-authored-by: roman s <roman.sukach@dust-labs.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
+40
-12
@@ -5,6 +5,7 @@ package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
git_model "gitea.dev/models/git"
|
||||
repo_model "gitea.dev/models/repo"
|
||||
@@ -20,23 +21,50 @@ type RefCommit struct {
|
||||
CommitID string
|
||||
}
|
||||
|
||||
// ResolveRefCommit resolve ref to a commit if exist
|
||||
// ResolveRefCommit resolve ref to a commit if it exists.
|
||||
// inputRef may be a short branch/tag name, a commit ID, or a fully-qualified
|
||||
// git ref (e.g. refs/heads/main, refs/tags/v1.0) for GitHub client compatibility.
|
||||
func ResolveRefCommit(ctx reqctx.RequestContext, repo *repo_model.Repository, inputRef string, minCommitIDLen ...int) (_ *RefCommit, err error) {
|
||||
refCommit := RefCommit{InputRef: inputRef}
|
||||
|
||||
var testRefBranch, testRefTag git.RefName
|
||||
if strings.HasPrefix(inputRef, "refs/") {
|
||||
// Fully-qualified refs first so clients can pass unambiguous names.
|
||||
testRef := git.RefName(inputRef)
|
||||
if testRef.IsBranch() {
|
||||
testRefBranch = testRef
|
||||
} else if testRef.IsTag() {
|
||||
testRefTag = testRef
|
||||
}
|
||||
} else {
|
||||
testRefBranch, testRefTag = git.RefNameFromBranch(inputRef), git.RefNameFromTag(inputRef)
|
||||
}
|
||||
|
||||
if testRefBranch != "" {
|
||||
if exist, _ := git_model.IsBranchExist(ctx, repo.ID, testRefBranch.ShortName()); exist {
|
||||
refCommit.RefName = testRefBranch
|
||||
}
|
||||
}
|
||||
if testRefTag != "" {
|
||||
// TODO: use git model instead of git command in the future? Model seems to be faster.
|
||||
if git.IsTagExist(ctx, repo, testRefTag.ShortName()) {
|
||||
refCommit.RefName = testRefTag
|
||||
}
|
||||
}
|
||||
if refCommit.RefName == "" {
|
||||
if git.IsStringLikelyCommitID(git.ObjectFormatFromName(repo.ObjectFormatName), inputRef, minCommitIDLen...) {
|
||||
refCommit.RefName = git.RefNameFromCommit(inputRef)
|
||||
}
|
||||
}
|
||||
|
||||
if refCommit.RefName == "" {
|
||||
return nil, git.ErrNotExist{ID: inputRef}
|
||||
}
|
||||
|
||||
gitRepo, err := git.RepositoryFromRequestContextOrOpen(ctx, repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
refCommit := RefCommit{InputRef: inputRef}
|
||||
if exist, _ := git_model.IsBranchExist(ctx, repo.ID, inputRef); exist {
|
||||
refCommit.RefName = git.RefNameFromBranch(inputRef)
|
||||
} else if git.IsTagExist(ctx, repo, inputRef) {
|
||||
refCommit.RefName = git.RefNameFromTag(inputRef)
|
||||
} else if git.IsStringLikelyCommitID(git.ObjectFormatFromName(repo.ObjectFormatName), inputRef, minCommitIDLen...) {
|
||||
refCommit.RefName = git.RefNameFromCommit(inputRef)
|
||||
}
|
||||
if refCommit.RefName == "" {
|
||||
return nil, git.ErrNotExist{ID: inputRef}
|
||||
}
|
||||
if refCommit.Commit, err = gitRepo.GetCommit(ctx, refCommit.RefName.String()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user