You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

middleware.go 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package common
  4. import (
  5. "fmt"
  6. "net/http"
  7. "strings"
  8. "code.gitea.io/gitea/modules/cache"
  9. "code.gitea.io/gitea/modules/context"
  10. "code.gitea.io/gitea/modules/process"
  11. "code.gitea.io/gitea/modules/setting"
  12. "code.gitea.io/gitea/modules/web/middleware"
  13. "code.gitea.io/gitea/modules/web/routing"
  14. "gitea.com/go-chi/session"
  15. "github.com/chi-middleware/proxy"
  16. chi "github.com/go-chi/chi/v5"
  17. )
  18. // ProtocolMiddlewares returns HTTP protocol related middlewares, and it provides a global panic recovery
  19. func ProtocolMiddlewares() (handlers []any) {
  20. // first, normalize the URL path
  21. handlers = append(handlers, stripSlashesMiddleware)
  22. // prepare the ContextData and panic recovery
  23. handlers = append(handlers, func(next http.Handler) http.Handler {
  24. return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
  25. defer func() {
  26. if err := recover(); err != nil {
  27. RenderPanicErrorPage(resp, req, err) // it should never panic
  28. }
  29. }()
  30. req = req.WithContext(middleware.WithContextData(req.Context()))
  31. next.ServeHTTP(resp, req)
  32. })
  33. })
  34. // wrap the request and response, use the process context and add it to the process manager
  35. handlers = append(handlers, func(next http.Handler) http.Handler {
  36. return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
  37. ctx, _, finished := process.GetManager().AddTypedContext(req.Context(), fmt.Sprintf("%s: %s", req.Method, req.RequestURI), process.RequestProcessType, true)
  38. defer finished()
  39. next.ServeHTTP(context.WrapResponseWriter(resp), req.WithContext(cache.WithCacheContext(ctx)))
  40. })
  41. })
  42. if setting.ReverseProxyLimit > 0 {
  43. opt := proxy.NewForwardedHeadersOptions().
  44. WithForwardLimit(setting.ReverseProxyLimit).
  45. ClearTrustedProxies()
  46. for _, n := range setting.ReverseProxyTrustedProxies {
  47. if !strings.Contains(n, "/") {
  48. opt.AddTrustedProxy(n)
  49. } else {
  50. opt.AddTrustedNetwork(n)
  51. }
  52. }
  53. handlers = append(handlers, proxy.ForwardedHeaders(opt))
  54. }
  55. if setting.IsRouteLogEnabled() {
  56. handlers = append(handlers, routing.NewLoggerHandler())
  57. }
  58. if setting.IsAccessLogEnabled() {
  59. handlers = append(handlers, context.AccessLogger())
  60. }
  61. return handlers
  62. }
  63. func stripSlashesMiddleware(next http.Handler) http.Handler {
  64. return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
  65. // First of all escape the URL RawPath to ensure that all routing is done using a correctly escaped URL
  66. req.URL.RawPath = req.URL.EscapedPath()
  67. urlPath := req.URL.RawPath
  68. rctx := chi.RouteContext(req.Context())
  69. if rctx != nil && rctx.RoutePath != "" {
  70. urlPath = rctx.RoutePath
  71. }
  72. sanitizedPath := &strings.Builder{}
  73. prevWasSlash := false
  74. for _, chr := range strings.TrimRight(urlPath, "/") {
  75. if chr != '/' || !prevWasSlash {
  76. sanitizedPath.WriteRune(chr)
  77. }
  78. prevWasSlash = chr == '/'
  79. }
  80. if rctx == nil {
  81. req.URL.Path = sanitizedPath.String()
  82. } else {
  83. rctx.RoutePath = sanitizedPath.String()
  84. }
  85. next.ServeHTTP(resp, req)
  86. })
  87. }
  88. func Sessioner() func(next http.Handler) http.Handler {
  89. return session.Sessioner(session.Options{
  90. Provider: setting.SessionConfig.Provider,
  91. ProviderConfig: setting.SessionConfig.ProviderConfig,
  92. CookieName: setting.SessionConfig.CookieName,
  93. CookiePath: setting.SessionConfig.CookiePath,
  94. Gclifetime: setting.SessionConfig.Gclifetime,
  95. Maxlifetime: setting.SessionConfig.Maxlifetime,
  96. Secure: setting.SessionConfig.Secure,
  97. SameSite: setting.SessionConfig.SameSite,
  98. Domain: setting.SessionConfig.Domain,
  99. })
  100. }