mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-05-25 11:22:16 +00:00
Refactor "route" related code, fix Safari cookie bug (#24330)
Fix #24176 Clean some misuses of route package, clean some legacy FIXMEs --------- Co-authored-by: Giteabot <teabot@gitea.io>
This commit is contained in:
parent
1c875ef5be
commit
92fd3fc4fd
14 changed files with 264 additions and 253 deletions
|
@ -6,16 +6,10 @@ package web
|
|||
import (
|
||||
gocontext "context"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/modules/cache"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/httpcache"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/metrics"
|
||||
"code.gitea.io/gitea/modules/public"
|
||||
|
@ -26,6 +20,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/validation"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/modules/web/routing"
|
||||
"code.gitea.io/gitea/routers/common"
|
||||
"code.gitea.io/gitea/routers/web/admin"
|
||||
"code.gitea.io/gitea/routers/web/auth"
|
||||
"code.gitea.io/gitea/routers/web/devtest"
|
||||
|
@ -48,7 +43,6 @@ import (
|
|||
_ "code.gitea.io/gitea/modules/session" // to registers all internal adapters
|
||||
|
||||
"gitea.com/go-chi/captcha"
|
||||
"gitea.com/go-chi/session"
|
||||
"github.com/NYTimes/gziphandler"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/go-chi/cors"
|
||||
|
@ -103,45 +97,18 @@ func buildAuthGroup() *auth_service.Group {
|
|||
func Routes(ctx gocontext.Context) *web.Route {
|
||||
routes := web.NewRoute()
|
||||
|
||||
routes.Use(web.MiddlewareWithPrefix("/assets/", CorsHandler(), public.AssetsHandlerFunc("/assets/")))
|
||||
|
||||
sessioner := session.Sessioner(session.Options{
|
||||
Provider: setting.SessionConfig.Provider,
|
||||
ProviderConfig: setting.SessionConfig.ProviderConfig,
|
||||
CookieName: setting.SessionConfig.CookieName,
|
||||
CookiePath: setting.SessionConfig.CookiePath,
|
||||
Gclifetime: setting.SessionConfig.Gclifetime,
|
||||
Maxlifetime: setting.SessionConfig.Maxlifetime,
|
||||
Secure: setting.SessionConfig.Secure,
|
||||
SameSite: setting.SessionConfig.SameSite,
|
||||
Domain: setting.SessionConfig.Domain,
|
||||
})
|
||||
routes.Use(sessioner)
|
||||
|
||||
ctx, _ = templates.HTMLRenderer(ctx)
|
||||
|
||||
routes.Use(Recovery(ctx))
|
||||
|
||||
// We use r.Route here over r.Use because this prevents requests that are not for avatars having to go through this additional handler
|
||||
routes.Head("/", misc.DummyOK) // for health check - doesn't need to be passed through gzip handler
|
||||
routes.RouteMethods("/assets/*", "GET, HEAD", CorsHandler(), public.AssetsHandlerFunc("/assets/"))
|
||||
routes.RouteMethods("/avatars/*", "GET, HEAD", storageHandler(setting.Avatar.Storage, "avatars", storage.Avatars))
|
||||
routes.RouteMethods("/repo-avatars/*", "GET, HEAD", storageHandler(setting.RepoAvatar.Storage, "repo-avatars", storage.RepoAvatars))
|
||||
routes.RouteMethods("/apple-touch-icon.png", "GET, HEAD", misc.StaticRedirect("/assets/img/apple-touch-icon.png"))
|
||||
routes.RouteMethods("/favicon.ico", "GET, HEAD", misc.StaticRedirect("/assets/img/favicon.png"))
|
||||
|
||||
// for health check - doesn't need to be passed through gzip handler
|
||||
routes.Head("/", func(w http.ResponseWriter, req *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
// this png is very likely to always be below the limit for gzip so it doesn't need to pass through gzip
|
||||
routes.Get("/apple-touch-icon.png", func(w http.ResponseWriter, req *http.Request) {
|
||||
http.Redirect(w, req, path.Join(setting.StaticURLPrefix, "/assets/img/apple-touch-icon.png"), http.StatusPermanentRedirect)
|
||||
})
|
||||
|
||||
// redirect default favicon to the path of the custom favicon with a default as a fallback
|
||||
routes.Get("/favicon.ico", func(w http.ResponseWriter, req *http.Request) {
|
||||
http.Redirect(w, req, path.Join(setting.StaticURLPrefix, "/assets/img/favicon.png"), http.StatusMovedPermanently)
|
||||
})
|
||||
|
||||
common := []interface{}{}
|
||||
ctx, _ = templates.HTMLRenderer(ctx)
|
||||
common := []any{
|
||||
common.Sessioner(),
|
||||
RecoveryWith500Page(ctx),
|
||||
}
|
||||
|
||||
if setting.EnableGzip {
|
||||
h, err := gziphandler.GzipHandlerWithOpts(gziphandler.MinSize(GzipMinSize))
|
||||
|
@ -157,42 +124,18 @@ func Routes(ctx gocontext.Context) *web.Route {
|
|||
}
|
||||
|
||||
if setting.HasRobotsTxt {
|
||||
routes.Get("/robots.txt", append(common, func(w http.ResponseWriter, req *http.Request) {
|
||||
filePath := path.Join(setting.CustomPath, "robots.txt")
|
||||
fi, err := os.Stat(filePath)
|
||||
if err == nil && httpcache.HandleTimeCache(req, w, fi) {
|
||||
return
|
||||
}
|
||||
http.ServeFile(w, req, filePath)
|
||||
})...)
|
||||
routes.Get("/robots.txt", append(common, misc.RobotsTxt)...)
|
||||
}
|
||||
|
||||
// prometheus metrics endpoint - do not need to go through contexter
|
||||
if setting.Metrics.Enabled {
|
||||
c := metrics.NewCollector()
|
||||
prometheus.MustRegister(c)
|
||||
|
||||
prometheus.MustRegister(metrics.NewCollector())
|
||||
routes.Get("/metrics", append(common, Metrics)...)
|
||||
}
|
||||
|
||||
routes.Get("/ssh_info", func(rw http.ResponseWriter, req *http.Request) {
|
||||
if !git.SupportProcReceive {
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
rw.Header().Set("content-type", "text/json;charset=UTF-8")
|
||||
_, err := rw.Write([]byte(`{"type":"gitea","version":1}`))
|
||||
if err != nil {
|
||||
log.Error("fail to write result: err: %v", err)
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
routes.Get("/ssh_info", misc.SSHInfo)
|
||||
routes.Get("/api/healthz", healthcheck.Check)
|
||||
|
||||
// Removed: toolbox.Toolboxer middleware will provide debug information which seems unnecessary
|
||||
common = append(common, context.Contexter(ctx))
|
||||
|
||||
group := buildAuthGroup()
|
||||
|
@ -207,7 +150,7 @@ func Routes(ctx gocontext.Context) *web.Route {
|
|||
common = append(common, middleware.GetHead)
|
||||
|
||||
if setting.API.EnableSwagger {
|
||||
// Note: The route moved from apiroutes because it's in fact want to render a web page
|
||||
// Note: The route is here but no in API routes because it renders a web page
|
||||
routes.Get("/api/swagger", append(common, misc.Swagger)...) // Render V1 by default
|
||||
}
|
||||
|
||||
|
@ -217,17 +160,14 @@ func Routes(ctx gocontext.Context) *web.Route {
|
|||
common = append(common, goGet)
|
||||
|
||||
others := web.NewRoute()
|
||||
for _, middle := range common {
|
||||
others.Use(middle)
|
||||
}
|
||||
|
||||
RegisterRoutes(others)
|
||||
others.Use(common...)
|
||||
registerRoutes(others)
|
||||
routes.Mount("", others)
|
||||
return routes
|
||||
}
|
||||
|
||||
// RegisterRoutes register routes
|
||||
func RegisterRoutes(m *web.Route) {
|
||||
// registerRoutes register routes
|
||||
func registerRoutes(m *web.Route) {
|
||||
reqSignIn := auth_service.VerifyAuthWithOptions(&auth_service.VerifyOptions{SignInRequired: true})
|
||||
ignSignIn := auth_service.VerifyAuthWithOptions(&auth_service.VerifyOptions{SignInRequired: setting.Service.RequireSignInView})
|
||||
ignExploreSignIn := auth_service.VerifyAuthWithOptions(&auth_service.VerifyOptions{SignInRequired: setting.Service.RequireSignInView || setting.Service.Explore.RequireSigninView})
|
||||
|
@ -354,8 +294,8 @@ func RegisterRoutes(m *web.Route) {
|
|||
m.Get("/nodeinfo", NodeInfoLinks)
|
||||
m.Get("/webfinger", WebfingerQuery)
|
||||
}, federationEnabled)
|
||||
m.Get("/change-password", func(w http.ResponseWriter, req *http.Request) {
|
||||
http.Redirect(w, req, "/user/settings/account", http.StatusTemporaryRedirect)
|
||||
m.Get("/change-password", func(ctx *context.Context) {
|
||||
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -664,53 +604,7 @@ func RegisterRoutes(m *web.Route) {
|
|||
// ***** END: Admin *****
|
||||
|
||||
m.Group("", func() {
|
||||
m.Get("/favicon.ico", func(ctx *context.Context) {
|
||||
ctx.SetServeHeaders(&context.ServeHeaderOptions{
|
||||
Filename: "favicon.png",
|
||||
})
|
||||
http.ServeFile(ctx.Resp, ctx.Req, path.Join(setting.StaticRootPath, "public/img/favicon.png"))
|
||||
})
|
||||
m.Get("/{username}", func(ctx *context.Context) {
|
||||
// WORKAROUND to support usernames with "." in it
|
||||
// https://github.com/go-chi/chi/issues/781
|
||||
username := ctx.Params("username")
|
||||
reloadParam := func(suffix string) (success bool) {
|
||||
ctx.SetParams("username", strings.TrimSuffix(username, suffix))
|
||||
context_service.UserAssignmentWeb()(ctx)
|
||||
return !ctx.Written()
|
||||
}
|
||||
switch {
|
||||
case strings.HasSuffix(username, ".png"):
|
||||
if reloadParam(".png") {
|
||||
user.AvatarByUserName(ctx)
|
||||
}
|
||||
case strings.HasSuffix(username, ".keys"):
|
||||
if reloadParam(".keys") {
|
||||
user.ShowSSHKeys(ctx)
|
||||
}
|
||||
case strings.HasSuffix(username, ".gpg"):
|
||||
if reloadParam(".gpg") {
|
||||
user.ShowGPGKeys(ctx)
|
||||
}
|
||||
case strings.HasSuffix(username, ".rss"):
|
||||
feedEnabled(ctx)
|
||||
if !ctx.Written() && reloadParam(".rss") {
|
||||
context_service.UserAssignmentWeb()(ctx)
|
||||
feed.ShowUserFeedRSS(ctx)
|
||||
}
|
||||
case strings.HasSuffix(username, ".atom"):
|
||||
feedEnabled(ctx)
|
||||
if !ctx.Written() && reloadParam(".atom") {
|
||||
feed.ShowUserFeedAtom(ctx)
|
||||
}
|
||||
default:
|
||||
context_service.UserAssignmentWeb()(ctx)
|
||||
if !ctx.Written() {
|
||||
ctx.Data["EnableFeed"] = setting.Other.EnableFeed
|
||||
user.Profile(ctx)
|
||||
}
|
||||
}
|
||||
})
|
||||
m.Get("/{username}", user.UsernameSubRoute)
|
||||
m.Get("/attachments/{uuid}", repo.GetAttachment)
|
||||
}, ignSignIn)
|
||||
|
||||
|
@ -1233,21 +1127,7 @@ func RegisterRoutes(m *web.Route) {
|
|||
m.Group("/releases", func() {
|
||||
m.Get("/edit/*", repo.EditRelease)
|
||||
m.Post("/edit/*", web.Bind(forms.EditReleaseForm{}), repo.EditReleasePost)
|
||||
}, reqSignIn, repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoReleaseWriter, func(ctx *context.Context) {
|
||||
var err error
|
||||
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetBranchCommit", err)
|
||||
return
|
||||
}
|
||||
ctx.Repo.CommitsCount, err = ctx.Repo.GetCommitsCount()
|
||||
if err != nil {
|
||||
ctx.ServerError("GetCommitsCount", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
|
||||
ctx.Repo.GitRepo.LastCommitCache = git.NewLastCommitCache(ctx.Repo.CommitsCount, ctx.Repo.Repository.FullName(), ctx.Repo.GitRepo, cache.GetCache())
|
||||
})
|
||||
}, reqSignIn, repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoReleaseWriter, repo.CommitInfoCache)
|
||||
}, ignSignIn, context.RepoAssignment, context.UnitTypes(), reqRepoReleaseReader)
|
||||
|
||||
// to maintain compatibility with old attachments
|
||||
|
@ -1326,18 +1206,10 @@ func RegisterRoutes(m *web.Route) {
|
|||
m.Group("/wiki", func() {
|
||||
m.Combo("/").
|
||||
Get(repo.Wiki).
|
||||
Post(context.RepoMustNotBeArchived(),
|
||||
reqSignIn,
|
||||
reqRepoWikiWriter,
|
||||
web.Bind(forms.NewWikiForm{}),
|
||||
repo.WikiPost)
|
||||
Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
|
||||
m.Combo("/*").
|
||||
Get(repo.Wiki).
|
||||
Post(context.RepoMustNotBeArchived(),
|
||||
reqSignIn,
|
||||
reqRepoWikiWriter,
|
||||
web.Bind(forms.NewWikiForm{}),
|
||||
repo.WikiPost)
|
||||
Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
|
||||
m.Get("/commit/{sha:[a-f0-9]{7,40}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
|
||||
m.Get("/commit/{sha:[a-f0-9]{7,40}}.{ext:patch|diff}", repo.RawDiff)
|
||||
}, repo.MustEnableWiki, func(ctx *context.Context) {
|
||||
|
@ -1468,8 +1340,7 @@ func RegisterRoutes(m *web.Route) {
|
|||
m.Group("", func() {
|
||||
m.Get("/forks", repo.Forks)
|
||||
}, context.RepoRef(), reqRepoCodeReader)
|
||||
m.Get("/commit/{sha:([a-f0-9]{7,40})}.{ext:patch|diff}",
|
||||
repo.MustBeNotEmpty, reqRepoCodeReader, repo.RawDiff)
|
||||
m.Get("/commit/{sha:([a-f0-9]{7,40})}.{ext:patch|diff}", repo.MustBeNotEmpty, reqRepoCodeReader, repo.RawDiff)
|
||||
}, ignSignIn, context.RepoAssignment, context.UnitTypes())
|
||||
|
||||
m.Post("/{username}/{reponame}/lastcommit/*", ignSignInAndCsrf, context.RepoAssignment, context.UnitTypes(), context.RepoRefByType(context.RepoRefCommit), reqRepoCodeReader, repo.LastCommit)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue