@@ -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