Make URL scheme unambiguous (#2408)

* Make URL scheme unambiguous

Redirect old routes to new routes

* Fix redirects to new URL scheme, and update template

* Fix branches/_new endpoints, and update integration test
This commit is contained in:
Ethan Koenig 2017-10-29 19:04:25 -07:00 committed by Lunny Xiao
parent 6e98812ecf
commit 513375c429
20 changed files with 279 additions and 144 deletions

View file

@ -14,6 +14,7 @@ import (
"code.gitea.io/git"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"github.com/Unknwon/com"
@ -117,6 +118,20 @@ func (r *Repository) GetCommitsCount() (int64, error) {
})
}
// BranchNameSubURL sub-URL for the BranchName field
func (r *Repository) BranchNameSubURL() string {
switch {
case r.IsViewBranch:
return "branch/" + r.BranchName
case r.IsViewTag:
return "tag/" + r.BranchName
case r.IsViewCommit:
return "commit/" + r.BranchName
}
log.Error(4, "Unknown view type for repo: %v", r)
return ""
}
// GetEditorconfig returns the .editorconfig definition if found in the
// HEAD of the default repo branch.
func (r *Repository) GetEditorconfig() (*editorconfig.Editorconfig, error) {
@ -444,8 +459,81 @@ func RepoAssignment() macaron.Handler {
}
}
// RepoRef handles repository reference name including those contain `/`.
// RepoRefType type of repo reference
type RepoRefType int
const (
// RepoRefLegacy unknown type, make educated guess and redirect.
// for backward compatibility with previous URL scheme
RepoRefLegacy RepoRefType = iota
// RepoRefBranch branch
RepoRefBranch
// RepoRefTag tag
RepoRefTag
// RepoRefCommit commit
RepoRefCommit
)
// RepoRef handles repository reference names when the ref name is not
// explicitly given
func RepoRef() macaron.Handler {
// since no ref name is explicitly specified, ok to just use branch
return RepoRefByType(RepoRefBranch)
}
func getRefNameFromPath(ctx *Context, path string, isExist func(string) bool) string {
refName := ""
parts := strings.Split(path, "/")
for i, part := range parts {
refName = strings.TrimPrefix(refName+"/"+part, "/")
if isExist(refName) {
ctx.Repo.TreePath = strings.Join(parts[i+1:], "/")
return refName
}
}
return ""
}
func getRefName(ctx *Context, pathType RepoRefType) string {
path := ctx.Params("*")
switch pathType {
case RepoRefLegacy:
if refName := getRefName(ctx, RepoRefBranch); len(refName) > 0 {
return refName
}
if refName := getRefName(ctx, RepoRefTag); len(refName) > 0 {
return refName
}
return getRefName(ctx, RepoRefCommit)
case RepoRefBranch:
return getRefNameFromPath(ctx, path, ctx.Repo.GitRepo.IsBranchExist)
case RepoRefTag:
return getRefNameFromPath(ctx, path, ctx.Repo.GitRepo.IsTagExist)
case RepoRefCommit:
parts := strings.Split(path, "/")
if len(parts) > 0 && len(parts[0]) == 40 {
ctx.Repo.TreePath = strings.Join(parts[1:], "/")
return parts[0]
}
default:
log.Error(4, "Unrecognized path type: %v", path)
}
return ""
}
// URL to redirect to for deprecated URL scheme
func repoRefRedirect(ctx *Context) string {
urlPath := ctx.Req.URL.String()
idx := strings.LastIndex(urlPath, ctx.Params("*"))
if idx < 0 {
idx = len(urlPath)
}
return path.Join(urlPath[:idx], ctx.Repo.BranchNameSubURL())
}
// RepoRefByType handles repository reference name for a specific type
// of repository reference
func RepoRefByType(refType RepoRefType) macaron.Handler {
return func(ctx *Context) {
// Empty repository does not have reference information.
if ctx.Repo.Repository.IsBare {
@ -470,6 +558,7 @@ func RepoRef() macaron.Handler {
// Get default branch.
if len(ctx.Params("*")) == 0 {
refName = ctx.Repo.Repository.DefaultBranch
ctx.Repo.BranchName = refName
if !ctx.Repo.GitRepo.IsBranchExist(refName) {
brs, err := ctx.Repo.GitRepo.GetBranches()
if err != nil {
@ -492,25 +581,8 @@ func RepoRef() macaron.Handler {
ctx.Repo.IsViewBranch = true
} else {
hasMatched := false
parts := strings.Split(ctx.Params("*"), "/")
for i, part := range parts {
refName = strings.TrimPrefix(refName+"/"+part, "/")
if ctx.Repo.GitRepo.IsBranchExist(refName) ||
ctx.Repo.GitRepo.IsTagExist(refName) {
if i < len(parts)-1 {
ctx.Repo.TreePath = strings.Join(parts[i+1:], "/")
}
hasMatched = true
break
}
}
if !hasMatched && len(parts[0]) == 40 {
refName = parts[0]
ctx.Repo.TreePath = strings.Join(parts[1:], "/")
}
refName = getRefName(ctx, refType)
ctx.Repo.BranchName = refName
if ctx.Repo.GitRepo.IsBranchExist(refName) {
ctx.Repo.IsViewBranch = true
@ -542,10 +614,16 @@ func RepoRef() macaron.Handler {
ctx.Handle(404, "RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refName))
return
}
if refType == RepoRefLegacy {
// redirect from old URL scheme to new URL scheme
ctx.Redirect(repoRefRedirect(ctx))
return
}
}
ctx.Repo.BranchName = refName
ctx.Data["BranchName"] = ctx.Repo.BranchName
ctx.Data["BranchNameSubURL"] = ctx.Repo.BranchNameSubURL()
ctx.Data["CommitID"] = ctx.Repo.CommitID
ctx.Data["TreePath"] = ctx.Repo.TreePath
ctx.Data["IsViewBranch"] = ctx.Repo.IsViewBranch