gitea源码

middleware.go 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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/gtprof"
  10. "code.gitea.io/gitea/modules/httplib"
  11. "code.gitea.io/gitea/modules/reqctx"
  12. "code.gitea.io/gitea/modules/setting"
  13. "code.gitea.io/gitea/modules/web/routing"
  14. "code.gitea.io/gitea/services/context"
  15. "gitea.com/go-chi/session"
  16. "github.com/chi-middleware/proxy"
  17. "github.com/go-chi/chi/v5"
  18. )
  19. // ProtocolMiddlewares returns HTTP protocol related middlewares, and it provides a global panic recovery
  20. func ProtocolMiddlewares() (handlers []any) {
  21. // the order is important
  22. handlers = append(handlers, ChiRoutePathHandler()) // make sure chi has correct paths
  23. handlers = append(handlers, RequestContextHandler()) // prepare the context and panic recovery
  24. if setting.ReverseProxyLimit > 0 && len(setting.ReverseProxyTrustedProxies) > 0 {
  25. handlers = append(handlers, ForwardedHeadersHandler(setting.ReverseProxyLimit, setting.ReverseProxyTrustedProxies))
  26. }
  27. if setting.IsRouteLogEnabled() {
  28. handlers = append(handlers, routing.NewLoggerHandler())
  29. }
  30. if setting.IsAccessLogEnabled() {
  31. handlers = append(handlers, context.AccessLogger())
  32. }
  33. return handlers
  34. }
  35. func RequestContextHandler() func(h http.Handler) http.Handler {
  36. return func(next http.Handler) http.Handler {
  37. return http.HandlerFunc(func(respOrig http.ResponseWriter, req *http.Request) {
  38. // this response writer might not be the same as the one in context.Base.Resp
  39. // because there might be a "gzip writer" in the middle, so the "written size" here is the compressed size
  40. respWriter := context.WrapResponseWriter(respOrig)
  41. profDesc := fmt.Sprintf("HTTP: %s %s", req.Method, req.RequestURI)
  42. ctx, finished := reqctx.NewRequestContext(req.Context(), profDesc)
  43. defer finished()
  44. ctx, span := gtprof.GetTracer().Start(ctx, gtprof.TraceSpanHTTP)
  45. req = req.WithContext(ctx)
  46. defer func() {
  47. chiCtx := chi.RouteContext(req.Context())
  48. span.SetAttributeString(gtprof.TraceAttrHTTPRoute, chiCtx.RoutePattern())
  49. span.End()
  50. }()
  51. defer func() {
  52. if err := recover(); err != nil {
  53. RenderPanicErrorPage(respWriter, req, err) // it should never panic
  54. }
  55. }()
  56. ds := reqctx.GetRequestDataStore(ctx)
  57. req = req.WithContext(cache.WithCacheContext(ctx))
  58. ds.SetContextValue(httplib.RequestContextKey, req)
  59. ds.AddCleanUp(func() {
  60. if req.MultipartForm != nil {
  61. _ = req.MultipartForm.RemoveAll() // remove the temp files buffered to tmp directory
  62. }
  63. })
  64. next.ServeHTTP(respWriter, req)
  65. })
  66. }
  67. }
  68. func ChiRoutePathHandler() func(h http.Handler) http.Handler {
  69. // make sure chi uses EscapedPath(RawPath) as RoutePath, then "%2f" could be handled correctly
  70. return func(next http.Handler) http.Handler {
  71. return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
  72. chiCtx := chi.RouteContext(req.Context())
  73. if req.URL.RawPath == "" {
  74. chiCtx.RoutePath = req.URL.EscapedPath()
  75. } else {
  76. chiCtx.RoutePath = req.URL.RawPath
  77. }
  78. next.ServeHTTP(resp, req)
  79. })
  80. }
  81. }
  82. func ForwardedHeadersHandler(limit int, trustedProxies []string) func(h http.Handler) http.Handler {
  83. opt := proxy.NewForwardedHeadersOptions().WithForwardLimit(limit).ClearTrustedProxies()
  84. for _, n := range trustedProxies {
  85. if !strings.Contains(n, "/") {
  86. opt.AddTrustedProxy(n)
  87. } else {
  88. opt.AddTrustedNetwork(n)
  89. }
  90. }
  91. return proxy.ForwardedHeaders(opt)
  92. }
  93. func Sessioner() func(next http.Handler) http.Handler {
  94. return session.Sessioner(session.Options{
  95. Provider: setting.SessionConfig.Provider,
  96. ProviderConfig: setting.SessionConfig.ProviderConfig,
  97. CookieName: setting.SessionConfig.CookieName,
  98. CookiePath: setting.SessionConfig.CookiePath,
  99. Gclifetime: setting.SessionConfig.Gclifetime,
  100. Maxlifetime: setting.SessionConfig.Maxlifetime,
  101. Secure: setting.SessionConfig.Secure,
  102. SameSite: setting.SessionConfig.SameSite,
  103. Domain: setting.SessionConfig.Domain,
  104. })
  105. }