@@ -756,19 +756,11 @@ func RepoAssignment(ctx *Context) context.CancelFunc {
756756type RepoRefType int
757757
758758const (
759- // RepoRefLegacy unknown type, make educated guess and redirect.
760- // for backward compatibility with previous URL scheme
761- RepoRefLegacy RepoRefType = iota
762- // RepoRefAny is for usage where educated guess is needed
763- // but redirect can not be made
764- RepoRefAny
765- // RepoRefBranch branch
759+ // RepoRefUnknown is for legacy support, makes the code to "guess" the ref type
760+ RepoRefUnknown RepoRefType = iota
766761 RepoRefBranch
767- // RepoRefTag tag
768762 RepoRefTag
769- // RepoRefCommit commit
770763 RepoRefCommit
771- // RepoRefBlob blob
772764 RepoRefBlob
773765)
774766
@@ -781,22 +773,6 @@ func RepoRef() func(*Context) context.CancelFunc {
781773 return RepoRefByType (RepoRefBranch )
782774}
783775
784- // RefTypeIncludesBranches returns true if ref type can be a branch
785- func (rt RepoRefType ) RefTypeIncludesBranches () bool {
786- if rt == RepoRefLegacy || rt == RepoRefAny || rt == RepoRefBranch {
787- return true
788- }
789- return false
790- }
791-
792- // RefTypeIncludesTags returns true if ref type can be a tag
793- func (rt RepoRefType ) RefTypeIncludesTags () bool {
794- if rt == RepoRefLegacy || rt == RepoRefAny || rt == RepoRefTag {
795- return true
796- }
797- return false
798- }
799-
800776func getRefNameFromPath (repo * Repository , path string , isExist func (string ) bool ) string {
801777 refName := ""
802778 parts := strings .Split (path , "/" )
@@ -810,28 +786,50 @@ func getRefNameFromPath(repo *Repository, path string, isExist func(string) bool
810786 return ""
811787}
812788
789+ func isStringLikelyCommitID (objFmt git.ObjectFormat , s string , minLength ... int ) bool {
790+ minLen := util .OptionalArg (minLength , objFmt .FullLength ())
791+ if len (s ) < minLen || len (s ) > objFmt .FullLength () {
792+ return false
793+ }
794+ for _ , c := range s {
795+ isHex := (c >= '0' && c <= '9' ) || (c >= 'a' && c <= 'f' )
796+ if ! isHex {
797+ return false
798+ }
799+ }
800+ return true
801+ }
802+
803+ func getRefNameLegacy (ctx * Base , repo * Repository , optionalExtraRef ... string ) (string , RepoRefType ) {
804+ extraRef := util .OptionalArg (optionalExtraRef )
805+ reqPath := ctx .PathParam ("*" )
806+ reqPath = path .Join (extraRef , reqPath )
807+
808+ if refName := getRefName (ctx , repo , RepoRefBranch ); refName != "" {
809+ return refName , RepoRefBranch
810+ }
811+ if refName := getRefName (ctx , repo , RepoRefTag ); refName != "" {
812+ return refName , RepoRefTag
813+ }
814+
815+ // For legacy support only full commit sha
816+ parts := strings .Split (reqPath , "/" )
817+ if isStringLikelyCommitID (git .ObjectFormatFromName (repo .Repository .ObjectFormatName ), parts [0 ]) {
818+ // FIXME: this logic is different from other types. Ideally, it should also try to GetCommit to check if it exists
819+ repo .TreePath = strings .Join (parts [1 :], "/" )
820+ return parts [0 ], RepoRefCommit
821+ }
822+
823+ if refName := getRefName (ctx , repo , RepoRefBlob ); len (refName ) > 0 {
824+ return refName , RepoRefBlob
825+ }
826+ repo .TreePath = reqPath
827+ return repo .Repository .DefaultBranch , RepoRefBranch
828+ }
829+
813830func getRefName (ctx * Base , repo * Repository , pathType RepoRefType ) string {
814831 path := ctx .PathParam ("*" )
815832 switch pathType {
816- case RepoRefLegacy , RepoRefAny :
817- if refName := getRefName (ctx , repo , RepoRefBranch ); len (refName ) > 0 {
818- return refName
819- }
820- if refName := getRefName (ctx , repo , RepoRefTag ); len (refName ) > 0 {
821- return refName
822- }
823- // For legacy and API support only full commit sha
824- parts := strings .Split (path , "/" )
825-
826- if len (parts ) > 0 && len (parts [0 ]) == git .ObjectFormatFromName (repo .Repository .ObjectFormatName ).FullLength () {
827- repo .TreePath = strings .Join (parts [1 :], "/" )
828- return parts [0 ]
829- }
830- if refName := getRefName (ctx , repo , RepoRefBlob ); len (refName ) > 0 {
831- return refName
832- }
833- repo .TreePath = path
834- return repo .Repository .DefaultBranch
835833 case RepoRefBranch :
836834 ref := getRefNameFromPath (repo , path , repo .GitRepo .IsBranchExist )
837835 if len (ref ) == 0 {
@@ -866,13 +864,13 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
866864 return getRefNameFromPath (repo , path , repo .GitRepo .IsTagExist )
867865 case RepoRefCommit :
868866 parts := strings .Split (path , "/" )
869-
870- if len ( parts ) > 0 && len ( parts [ 0 ]) >= 7 && len ( parts [ 0 ]) <= repo . GetObjectFormat (). FullLength () {
867+ if isStringLikelyCommitID ( repo . GetObjectFormat (), parts [ 0 ], 7 ) {
868+ // FIXME: this logic is different from other types. Ideally, it should also try to GetCommit to check if it exists
871869 repo .TreePath = strings .Join (parts [1 :], "/" )
872870 return parts [0 ]
873871 }
874872
875- if len ( parts ) > 0 && parts [0 ] == headRefName {
873+ if parts [0 ] == headRefName {
876874 // HEAD ref points to last default branch commit
877875 commit , err := repo .GitRepo .GetBranchCommit (repo .Repository .DefaultBranch )
878876 if err != nil {
@@ -888,14 +886,19 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
888886 }
889887 return path
890888 default :
891- log . Error ("Unrecognized path type: %v" , path )
889+ panic ( fmt . Sprintf ("Unrecognized path type: %v" , pathType ) )
892890 }
893891 return ""
894892}
895893
894+ type RepoRefByTypeOptions struct {
895+ IgnoreNotExistErr bool
896+ }
897+
896898// RepoRefByType handles repository reference name for a specific type
897899// of repository reference
898- func RepoRefByType (refType RepoRefType , ignoreNotExistErr ... bool ) func (* Context ) context.CancelFunc {
900+ func RepoRefByType (refType RepoRefType , opts ... RepoRefByTypeOptions ) func (* Context ) context.CancelFunc {
901+ opt := util .OptionalArg (opts )
899902 return func (ctx * Context ) (cancel context.CancelFunc ) {
900903 // Empty repository does not have reference information.
901904 if ctx .Repo .Repository .IsEmpty {
@@ -956,7 +959,12 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
956959 }
957960 ctx .Repo .IsViewBranch = true
958961 } else {
959- refName = getRefName (ctx .Base , ctx .Repo , refType )
962+ guessLegacyPath := refType == RepoRefUnknown
963+ if guessLegacyPath {
964+ refName , refType = getRefNameLegacy (ctx .Base , ctx .Repo )
965+ } else {
966+ refName = getRefName (ctx .Base , ctx .Repo , refType )
967+ }
960968 ctx .Repo .RefName = refName
961969 isRenamedBranch , has := ctx .Data ["IsRenamedBranch" ].(bool )
962970 if isRenamedBranch && has {
@@ -967,7 +975,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
967975 return cancel
968976 }
969977
970- if refType . RefTypeIncludesBranches () && ctx .Repo .GitRepo .IsBranchExist (refName ) {
978+ if refType == RepoRefBranch && ctx .Repo .GitRepo .IsBranchExist (refName ) {
971979 ctx .Repo .IsViewBranch = true
972980 ctx .Repo .BranchName = refName
973981
@@ -977,7 +985,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
977985 return cancel
978986 }
979987 ctx .Repo .CommitID = ctx .Repo .Commit .ID .String ()
980- } else if refType . RefTypeIncludesTags () && ctx .Repo .GitRepo .IsTagExist (refName ) {
988+ } else if refType == RepoRefTag && ctx .Repo .GitRepo .IsTagExist (refName ) {
981989 ctx .Repo .IsViewTag = true
982990 ctx .Repo .TagName = refName
983991
@@ -991,7 +999,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
991999 return cancel
9921000 }
9931001 ctx .Repo .CommitID = ctx .Repo .Commit .ID .String ()
994- } else if len ( refName ) >= 7 && len ( refName ) <= ctx .Repo .GetObjectFormat (). FullLength ( ) {
1002+ } else if isStringLikelyCommitID ( ctx .Repo .GetObjectFormat (), refName , 7 ) {
9951003 ctx .Repo .IsViewCommit = true
9961004 ctx .Repo .CommitID = refName
9971005
@@ -1006,14 +1014,14 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
10061014 util .URLJoin (setting .AppURL , strings .Replace (ctx .Req .URL .RequestURI (), util .PathEscapeSegments (refName ), url .PathEscape (ctx .Repo .Commit .ID .String ()), 1 ))))
10071015 }
10081016 } else {
1009- if len ( ignoreNotExistErr ) > 0 && ignoreNotExistErr [ 0 ] {
1017+ if opt . IgnoreNotExistErr {
10101018 return cancel
10111019 }
10121020 ctx .NotFound ("RepoRef invalid repo" , fmt .Errorf ("branch or tag not exist: %s" , refName ))
10131021 return cancel
10141022 }
10151023
1016- if refType == RepoRefLegacy {
1024+ if guessLegacyPath {
10171025 // redirect from old URL scheme to new URL scheme
10181026 prefix := strings .TrimPrefix (setting .AppSubURL + strings .ToLower (strings .TrimSuffix (ctx .Req .URL .Path , ctx .PathParam ("*" ))), strings .ToLower (ctx .Repo .RepoLink ))
10191027 redirect := path .Join (
0 commit comments