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 4.7KB

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