@@ -25,6 +25,7 @@ import (
25
25
"code.gitea.io/gitea/modules/cache"
26
26
"code.gitea.io/gitea/modules/git"
27
27
"code.gitea.io/gitea/modules/gitrepo"
28
+ "code.gitea.io/gitea/modules/httplib"
28
29
code_indexer "code.gitea.io/gitea/modules/indexer/code"
29
30
"code.gitea.io/gitea/modules/log"
30
31
"code.gitea.io/gitea/modules/optional"
@@ -306,11 +307,9 @@ func RetrieveTemplateRepo(ctx *Context, repo *repo_model.Repository) {
306
307
}
307
308
308
309
// ComposeGoGetImport returns go-get-import meta content.
309
- func ComposeGoGetImport (owner , repo string ) string {
310
- /// setting.AppUrl is guaranteed to be parse as url
311
- appURL , _ := url .Parse (setting .AppURL )
312
-
313
- return path .Join (appURL .Host , setting .AppSubURL , url .PathEscape (owner ), url .PathEscape (repo ))
310
+ func ComposeGoGetImport (ctx context.Context , owner , repo string ) string {
311
+ curAppURL , _ := url .Parse (httplib .GuessCurrentAppURL (ctx ))
312
+ return path .Join (curAppURL .Host , setting .AppSubURL , url .PathEscape (owner ), url .PathEscape (repo ))
314
313
}
315
314
316
315
// EarlyResponseForGoGetMeta responses appropriate go-get meta with status 200
@@ -332,7 +331,7 @@ func EarlyResponseForGoGetMeta(ctx *Context) {
332
331
} else {
333
332
cloneURL = repo_model .ComposeHTTPSCloneURL (username , reponame )
334
333
}
335
- goImportContent := fmt .Sprintf ("%s git %s" , ComposeGoGetImport (username , reponame ), cloneURL )
334
+ goImportContent := fmt .Sprintf ("%s git %s" , ComposeGoGetImport (ctx , username , reponame ), cloneURL )
336
335
htmlMeta := fmt .Sprintf (`<meta name="go-import" content="%s">` , html .EscapeString (goImportContent ))
337
336
ctx .PlainText (http .StatusOK , htmlMeta )
338
337
}
@@ -744,7 +743,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc {
744
743
}
745
744
746
745
if ctx .FormString ("go-get" ) == "1" {
747
- ctx .Data ["GoGetImport" ] = ComposeGoGetImport (owner .Name , repo .Name )
746
+ ctx .Data ["GoGetImport" ] = ComposeGoGetImport (ctx , owner .Name , repo .Name )
748
747
fullURLPrefix := repo .HTMLURL () + "/src/branch/" + util .PathEscapeSegments (ctx .Repo .BranchName )
749
748
ctx .Data ["GoDocDirectory" ] = fullURLPrefix + "{/dir}"
750
749
ctx .Data ["GoDocFile" ] = fullURLPrefix + "{/dir}/{file}#L{line}"
@@ -756,19 +755,11 @@ func RepoAssignment(ctx *Context) context.CancelFunc {
756
755
type RepoRefType int
757
756
758
757
const (
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
758
+ // RepoRefUnknown is for legacy support, makes the code to "guess" the ref type
759
+ RepoRefUnknown RepoRefType = iota
766
760
RepoRefBranch
767
- // RepoRefTag tag
768
761
RepoRefTag
769
- // RepoRefCommit commit
770
762
RepoRefCommit
771
- // RepoRefBlob blob
772
763
RepoRefBlob
773
764
)
774
765
@@ -781,22 +772,6 @@ func RepoRef() func(*Context) context.CancelFunc {
781
772
return RepoRefByType (RepoRefBranch )
782
773
}
783
774
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
-
800
775
func getRefNameFromPath (repo * Repository , path string , isExist func (string ) bool ) string {
801
776
refName := ""
802
777
parts := strings .Split (path , "/" )
@@ -810,28 +785,50 @@ func getRefNameFromPath(repo *Repository, path string, isExist func(string) bool
810
785
return ""
811
786
}
812
787
788
+ func isStringLikelyCommitID (objFmt git.ObjectFormat , s string , minLength ... int ) bool {
789
+ minLen := util .OptionalArg (minLength , objFmt .FullLength ())
790
+ if len (s ) < minLen || len (s ) > objFmt .FullLength () {
791
+ return false
792
+ }
793
+ for _ , c := range s {
794
+ isHex := (c >= '0' && c <= '9' ) || (c >= 'a' && c <= 'f' )
795
+ if ! isHex {
796
+ return false
797
+ }
798
+ }
799
+ return true
800
+ }
801
+
802
+ func getRefNameLegacy (ctx * Base , repo * Repository , optionalExtraRef ... string ) (string , RepoRefType ) {
803
+ extraRef := util .OptionalArg (optionalExtraRef )
804
+ reqPath := ctx .PathParam ("*" )
805
+ reqPath = path .Join (extraRef , reqPath )
806
+
807
+ if refName := getRefName (ctx , repo , RepoRefBranch ); refName != "" {
808
+ return refName , RepoRefBranch
809
+ }
810
+ if refName := getRefName (ctx , repo , RepoRefTag ); refName != "" {
811
+ return refName , RepoRefTag
812
+ }
813
+
814
+ // For legacy support only full commit sha
815
+ parts := strings .Split (reqPath , "/" )
816
+ if isStringLikelyCommitID (git .ObjectFormatFromName (repo .Repository .ObjectFormatName ), parts [0 ]) {
817
+ // FIXME: this logic is different from other types. Ideally, it should also try to GetCommit to check if it exists
818
+ repo .TreePath = strings .Join (parts [1 :], "/" )
819
+ return parts [0 ], RepoRefCommit
820
+ }
821
+
822
+ if refName := getRefName (ctx , repo , RepoRefBlob ); len (refName ) > 0 {
823
+ return refName , RepoRefBlob
824
+ }
825
+ repo .TreePath = reqPath
826
+ return repo .Repository .DefaultBranch , RepoRefBranch
827
+ }
828
+
813
829
func getRefName (ctx * Base , repo * Repository , pathType RepoRefType ) string {
814
830
path := ctx .PathParam ("*" )
815
831
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
835
832
case RepoRefBranch :
836
833
ref := getRefNameFromPath (repo , path , repo .GitRepo .IsBranchExist )
837
834
if len (ref ) == 0 {
@@ -866,13 +863,13 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
866
863
return getRefNameFromPath (repo , path , repo .GitRepo .IsTagExist )
867
864
case RepoRefCommit :
868
865
parts := strings .Split (path , "/" )
869
-
870
- if len ( parts ) > 0 && len ( parts [ 0 ]) >= 7 && len ( parts [ 0 ]) <= repo . GetObjectFormat (). FullLength () {
866
+ if isStringLikelyCommitID ( repo . GetObjectFormat (), parts [ 0 ], 7 ) {
867
+ // FIXME: this logic is different from other types. Ideally, it should also try to GetCommit to check if it exists
871
868
repo .TreePath = strings .Join (parts [1 :], "/" )
872
869
return parts [0 ]
873
870
}
874
871
875
- if len ( parts ) > 0 && parts [0 ] == headRefName {
872
+ if parts [0 ] == headRefName {
876
873
// HEAD ref points to last default branch commit
877
874
commit , err := repo .GitRepo .GetBranchCommit (repo .Repository .DefaultBranch )
878
875
if err != nil {
@@ -888,15 +885,21 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
888
885
}
889
886
return path
890
887
default :
891
- log . Error ("Unrecognized path type: %v" , path )
888
+ panic ( fmt . Sprintf ("Unrecognized path type: %v" , pathType ) )
892
889
}
893
890
return ""
894
891
}
895
892
893
+ type RepoRefByTypeOptions struct {
894
+ IgnoreNotExistErr bool
895
+ }
896
+
896
897
// RepoRefByType handles repository reference name for a specific type
897
898
// of repository reference
898
- func RepoRefByType (refType RepoRefType , ignoreNotExistErr ... bool ) func (* Context ) context.CancelFunc {
899
+ func RepoRefByType (detectRefType RepoRefType , opts ... RepoRefByTypeOptions ) func (* Context ) context.CancelFunc {
900
+ opt := util .OptionalArg (opts )
899
901
return func (ctx * Context ) (cancel context.CancelFunc ) {
902
+ refType := detectRefType
900
903
// Empty repository does not have reference information.
901
904
if ctx .Repo .Repository .IsEmpty {
902
905
// assume the user is viewing the (non-existent) default branch
@@ -956,7 +959,12 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
956
959
}
957
960
ctx .Repo .IsViewBranch = true
958
961
} 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
+ }
960
968
ctx .Repo .RefName = refName
961
969
isRenamedBranch , has := ctx .Data ["IsRenamedBranch" ].(bool )
962
970
if isRenamedBranch && has {
@@ -967,7 +975,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
967
975
return cancel
968
976
}
969
977
970
- if refType . RefTypeIncludesBranches () && ctx .Repo .GitRepo .IsBranchExist (refName ) {
978
+ if refType == RepoRefBranch && ctx .Repo .GitRepo .IsBranchExist (refName ) {
971
979
ctx .Repo .IsViewBranch = true
972
980
ctx .Repo .BranchName = refName
973
981
@@ -977,7 +985,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
977
985
return cancel
978
986
}
979
987
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 ) {
981
989
ctx .Repo .IsViewTag = true
982
990
ctx .Repo .TagName = refName
983
991
@@ -991,7 +999,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
991
999
return cancel
992
1000
}
993
1001
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 ) {
995
1003
ctx .Repo .IsViewCommit = true
996
1004
ctx .Repo .CommitID = refName
997
1005
@@ -1002,18 +1010,18 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
1002
1010
}
1003
1011
// If short commit ID add canonical link header
1004
1012
if len (refName ) < ctx .Repo .GetObjectFormat ().FullLength () {
1005
- ctx . RespHeader (). Set ( "Link" , fmt . Sprintf ( "<%s>; rel= \" canonical \" " ,
1006
- util . URLJoin ( setting . AppURL , strings . Replace ( ctx .Req . URL . RequestURI (), util . PathEscapeSegments ( refName ), url . PathEscape ( ctx . Repo . Commit . ID . String ()), 1 )) ))
1013
+ canonicalURL := util . URLJoin ( httplib . GuessCurrentAppURL ( ctx ), strings . Replace ( ctx . Req . URL . RequestURI (), util . PathEscapeSegments ( refName ), url . PathEscape ( ctx . Repo . Commit . ID . String ()), 1 ))
1014
+ ctx .RespHeader (). Set ( "Link" , fmt . Sprintf ( `<%s>; rel="canonical"` , canonicalURL ))
1007
1015
}
1008
1016
} else {
1009
- if len ( ignoreNotExistErr ) > 0 && ignoreNotExistErr [ 0 ] {
1017
+ if opt . IgnoreNotExistErr {
1010
1018
return cancel
1011
1019
}
1012
1020
ctx .NotFound ("RepoRef invalid repo" , fmt .Errorf ("branch or tag not exist: %s" , refName ))
1013
1021
return cancel
1014
1022
}
1015
1023
1016
- if refType == RepoRefLegacy {
1024
+ if guessLegacyPath {
1017
1025
// redirect from old URL scheme to new URL scheme
1018
1026
prefix := strings .TrimPrefix (setting .AppSubURL + strings .ToLower (strings .TrimSuffix (ctx .Req .URL .Path , ctx .PathParam ("*" ))), strings .ToLower (ctx .Repo .RepoLink ))
1019
1027
redirect := path .Join (
0 commit comments