gitea源码

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. // Copyright 2025 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package common
  4. import (
  5. "net/http"
  6. "strings"
  7. user_model "code.gitea.io/gitea/models/user"
  8. "code.gitea.io/gitea/modules/reqctx"
  9. "code.gitea.io/gitea/modules/setting"
  10. "code.gitea.io/gitea/modules/web/middleware"
  11. "github.com/go-chi/chi/v5"
  12. )
  13. func BlockExpensive() func(next http.Handler) http.Handler {
  14. if !setting.Service.BlockAnonymousAccessExpensive {
  15. return nil
  16. }
  17. return func(next http.Handler) http.Handler {
  18. return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  19. ret := determineRequestPriority(reqctx.FromContext(req.Context()))
  20. if !ret.SignedIn {
  21. if ret.Expensive || ret.LongPolling {
  22. http.Redirect(w, req, setting.AppSubURL+"/user/login", http.StatusSeeOther)
  23. return
  24. }
  25. }
  26. next.ServeHTTP(w, req)
  27. })
  28. }
  29. }
  30. func isRoutePathExpensive(routePattern string) bool {
  31. if strings.HasPrefix(routePattern, "/user/") || strings.HasPrefix(routePattern, "/login/") {
  32. return false
  33. }
  34. expensivePaths := []string{
  35. // code related
  36. "/{username}/{reponame}/archive/",
  37. "/{username}/{reponame}/blame/",
  38. "/{username}/{reponame}/commit/",
  39. "/{username}/{reponame}/commits/",
  40. "/{username}/{reponame}/graph",
  41. "/{username}/{reponame}/media/",
  42. "/{username}/{reponame}/raw/",
  43. "/{username}/{reponame}/src/",
  44. // issue & PR related (no trailing slash)
  45. "/{username}/{reponame}/issues",
  46. "/{username}/{reponame}/{type:issues}",
  47. "/{username}/{reponame}/pulls",
  48. "/{username}/{reponame}/{type:pulls}",
  49. // wiki
  50. "/{username}/{reponame}/wiki/",
  51. // activity
  52. "/{username}/{reponame}/activity/",
  53. }
  54. for _, path := range expensivePaths {
  55. if strings.HasPrefix(routePattern, path) {
  56. return true
  57. }
  58. }
  59. return false
  60. }
  61. func isRoutePathForLongPolling(routePattern string) bool {
  62. return routePattern == "/user/events"
  63. }
  64. func determineRequestPriority(reqCtx reqctx.RequestContext) (ret struct {
  65. SignedIn bool
  66. Expensive bool
  67. LongPolling bool
  68. },
  69. ) {
  70. chiRoutePath := chi.RouteContext(reqCtx).RoutePattern()
  71. if _, ok := reqCtx.GetData()[middleware.ContextDataKeySignedUser].(*user_model.User); ok {
  72. ret.SignedIn = true
  73. } else {
  74. ret.Expensive = isRoutePathExpensive(chiRoutePath)
  75. ret.LongPolling = isRoutePathForLongPolling(chiRoutePath)
  76. }
  77. return ret
  78. }