@@ -20,6 +20,8 @@ import (
2020 unit_model "code.gitea.io/gitea/models/unit"
2121 user_model "code.gitea.io/gitea/models/user"
2222 "code.gitea.io/gitea/modules/git"
23+ giturl "code.gitea.io/gitea/modules/git/url"
24+ "code.gitea.io/gitea/modules/httplib"
2325 "code.gitea.io/gitea/modules/log"
2426 repo_module "code.gitea.io/gitea/modules/repository"
2527 "code.gitea.io/gitea/modules/setting"
@@ -302,8 +304,33 @@ func handleRepoEmptyOrBroken(ctx *context.Context) {
302304 ctx .Redirect (link )
303305}
304306
307+ func handleRepoViewSubmodule (ctx * context.Context , submodule * git.SubModule ) {
308+ submoduleRepoURL , err := giturl .ParseRepositoryURL (ctx , submodule .URL )
309+ if err != nil {
310+ HandleGitError (ctx , "prepareToRenderDirOrFile: ParseRepositoryURL" , err )
311+ return
312+ }
313+ submoduleURL := giturl .MakeRepositoryWebLink (submoduleRepoURL )
314+ if httplib .IsCurrentGiteaSiteURL (ctx , submoduleURL ) {
315+ ctx .RedirectToCurrentSite (submoduleURL )
316+ } else {
317+ // don't auto-redirect to external URL, to avoid open redirect or phishing
318+ ctx .Data ["NotFoundPrompt" ] = submoduleURL
319+ ctx .NotFound (nil )
320+ }
321+ }
322+
305323func prepareToRenderDirOrFile (entry * git.TreeEntry ) func (ctx * context.Context ) {
306324 return func (ctx * context.Context ) {
325+ if entry .IsSubModule () {
326+ submodule , err := ctx .Repo .Commit .GetSubModule (entry .Name ())
327+ if err != nil {
328+ HandleGitError (ctx , "prepareToRenderDirOrFile: GetSubModule" , err )
329+ return
330+ }
331+ handleRepoViewSubmodule (ctx , submodule )
332+ return
333+ }
307334 if entry .IsDir () {
308335 prepareToRenderDirectory (ctx )
309336 } else {
0 commit comments