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.

base.go 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package web
  4. import (
  5. goctx "context"
  6. "errors"
  7. "fmt"
  8. "io"
  9. "net/http"
  10. "os"
  11. "path"
  12. "strings"
  13. "code.gitea.io/gitea/modules/context"
  14. "code.gitea.io/gitea/modules/httpcache"
  15. "code.gitea.io/gitea/modules/log"
  16. "code.gitea.io/gitea/modules/setting"
  17. "code.gitea.io/gitea/modules/storage"
  18. "code.gitea.io/gitea/modules/templates"
  19. "code.gitea.io/gitea/modules/web/middleware"
  20. "code.gitea.io/gitea/modules/web/routing"
  21. "code.gitea.io/gitea/services/auth"
  22. "gitea.com/go-chi/session"
  23. )
  24. func storageHandler(storageSetting setting.Storage, prefix string, objStore storage.ObjectStorage) func(next http.Handler) http.Handler {
  25. prefix = strings.Trim(prefix, "/")
  26. funcInfo := routing.GetFuncInfo(storageHandler, prefix)
  27. return func(next http.Handler) http.Handler {
  28. if storageSetting.ServeDirect {
  29. return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  30. if req.Method != "GET" && req.Method != "HEAD" {
  31. next.ServeHTTP(w, req)
  32. return
  33. }
  34. if !strings.HasPrefix(req.URL.Path, "/"+prefix+"/") {
  35. next.ServeHTTP(w, req)
  36. return
  37. }
  38. routing.UpdateFuncInfo(req.Context(), funcInfo)
  39. rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
  40. rPath = path.Clean("/" + strings.ReplaceAll(rPath, "\\", "/"))[1:]
  41. u, err := objStore.URL(rPath, path.Base(rPath))
  42. if err != nil {
  43. if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) {
  44. log.Warn("Unable to find %s %s", prefix, rPath)
  45. http.Error(w, "file not found", http.StatusNotFound)
  46. return
  47. }
  48. log.Error("Error whilst getting URL for %s %s. Error: %v", prefix, rPath, err)
  49. http.Error(w, fmt.Sprintf("Error whilst getting URL for %s %s", prefix, rPath), http.StatusInternalServerError)
  50. return
  51. }
  52. http.Redirect(
  53. w,
  54. req,
  55. u.String(),
  56. http.StatusTemporaryRedirect,
  57. )
  58. })
  59. }
  60. return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  61. if req.Method != "GET" && req.Method != "HEAD" {
  62. next.ServeHTTP(w, req)
  63. return
  64. }
  65. if !strings.HasPrefix(req.URL.Path, "/"+prefix+"/") {
  66. next.ServeHTTP(w, req)
  67. return
  68. }
  69. routing.UpdateFuncInfo(req.Context(), funcInfo)
  70. rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
  71. rPath = path.Clean("/" + strings.ReplaceAll(rPath, "\\", "/"))[1:]
  72. if rPath == "" {
  73. http.Error(w, "file not found", http.StatusNotFound)
  74. return
  75. }
  76. fi, err := objStore.Stat(rPath)
  77. if err == nil && httpcache.HandleTimeCache(req, w, fi) {
  78. return
  79. }
  80. // If we have matched and access to release or issue
  81. fr, err := objStore.Open(rPath)
  82. if err != nil {
  83. if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) {
  84. log.Warn("Unable to find %s %s", prefix, rPath)
  85. http.Error(w, "file not found", http.StatusNotFound)
  86. return
  87. }
  88. log.Error("Error whilst opening %s %s. Error: %v", prefix, rPath, err)
  89. http.Error(w, fmt.Sprintf("Error whilst opening %s %s", prefix, rPath), http.StatusInternalServerError)
  90. return
  91. }
  92. defer fr.Close()
  93. _, err = io.Copy(w, fr)
  94. if err != nil {
  95. log.Error("Error whilst rendering %s %s. Error: %v", prefix, rPath, err)
  96. http.Error(w, fmt.Sprintf("Error whilst rendering %s %s", prefix, rPath), http.StatusInternalServerError)
  97. return
  98. }
  99. })
  100. }
  101. }
  102. type dataStore map[string]interface{}
  103. func (d *dataStore) GetData() map[string]interface{} {
  104. return *d
  105. }
  106. // Recovery returns a middleware that recovers from any panics and writes a 500 and a log if so.
  107. // This error will be created with the gitea 500 page.
  108. func Recovery(ctx goctx.Context) func(next http.Handler) http.Handler {
  109. _, rnd := templates.HTMLRenderer(ctx)
  110. return func(next http.Handler) http.Handler {
  111. return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  112. defer func() {
  113. if err := recover(); err != nil {
  114. routing.UpdatePanicError(req.Context(), err)
  115. combinedErr := fmt.Sprintf("PANIC: %v\n%s", err, log.Stack(2))
  116. log.Error("%s", combinedErr)
  117. sessionStore := session.GetSession(req)
  118. lc := middleware.Locale(w, req)
  119. store := dataStore{
  120. "Language": lc.Language(),
  121. "CurrentURL": setting.AppSubURL + req.URL.RequestURI(),
  122. "locale": lc,
  123. }
  124. user := context.GetContextUser(req)
  125. if user == nil {
  126. // Get user from session if logged in - do not attempt to sign-in
  127. user = auth.SessionUser(sessionStore)
  128. }
  129. if user != nil {
  130. store["IsSigned"] = true
  131. store["SignedUser"] = user
  132. store["SignedUserID"] = user.ID
  133. store["SignedUserName"] = user.Name
  134. store["IsAdmin"] = user.IsAdmin
  135. } else {
  136. store["SignedUserID"] = int64(0)
  137. store["SignedUserName"] = ""
  138. }
  139. httpcache.AddCacheControlToHeader(w.Header(), 0, "no-transform")
  140. w.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions)
  141. if !setting.IsProd {
  142. store["ErrorMsg"] = combinedErr
  143. }
  144. err = rnd.HTML(w, http.StatusInternalServerError, "status/500", templates.BaseVars().Merge(store))
  145. if err != nil {
  146. log.Error("%v", err)
  147. }
  148. }
  149. }()
  150. next.ServeHTTP(w, req)
  151. })
  152. }
  153. }