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.

203 lines
5.8 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
8 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
8 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. // Copyright 2014 The Gogs 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 context
  5. import (
  6. "fmt"
  7. "html"
  8. "html/template"
  9. "io"
  10. "net/http"
  11. "strings"
  12. "time"
  13. "code.gitea.io/gitea/models"
  14. "code.gitea.io/gitea/modules/auth"
  15. "code.gitea.io/gitea/modules/base"
  16. "code.gitea.io/gitea/modules/log"
  17. "code.gitea.io/gitea/modules/setting"
  18. "github.com/go-macaron/cache"
  19. "github.com/go-macaron/csrf"
  20. "github.com/go-macaron/i18n"
  21. "github.com/go-macaron/session"
  22. macaron "gopkg.in/macaron.v1"
  23. )
  24. // Context represents context of a request.
  25. type Context struct {
  26. *macaron.Context
  27. Cache cache.Cache
  28. csrf csrf.CSRF
  29. Flash *session.Flash
  30. Session session.Store
  31. User *models.User
  32. IsSigned bool
  33. IsBasicAuth bool
  34. Repo *Repository
  35. Org *Organization
  36. }
  37. // HasAPIError returns true if error occurs in form validation.
  38. func (ctx *Context) HasAPIError() bool {
  39. hasErr, ok := ctx.Data["HasError"]
  40. if !ok {
  41. return false
  42. }
  43. return hasErr.(bool)
  44. }
  45. // GetErrMsg returns error message
  46. func (ctx *Context) GetErrMsg() string {
  47. return ctx.Data["ErrorMsg"].(string)
  48. }
  49. // HasError returns true if error occurs in form validation.
  50. func (ctx *Context) HasError() bool {
  51. hasErr, ok := ctx.Data["HasError"]
  52. if !ok {
  53. return false
  54. }
  55. ctx.Flash.ErrorMsg = ctx.Data["ErrorMsg"].(string)
  56. ctx.Data["Flash"] = ctx.Flash
  57. return hasErr.(bool)
  58. }
  59. // HasValue returns true if value of given name exists.
  60. func (ctx *Context) HasValue(name string) bool {
  61. _, ok := ctx.Data[name]
  62. return ok
  63. }
  64. // HTML calls Context.HTML and converts template name to string.
  65. func (ctx *Context) HTML(status int, name base.TplName) {
  66. log.Debug("Template: %s", name)
  67. ctx.Context.HTML(status, string(name))
  68. }
  69. // RenderWithErr used for page has form validation but need to prompt error to users.
  70. func (ctx *Context) RenderWithErr(msg string, tpl base.TplName, form interface{}) {
  71. if form != nil {
  72. auth.AssignForm(form, ctx.Data)
  73. }
  74. ctx.Flash.ErrorMsg = msg
  75. ctx.Data["Flash"] = ctx.Flash
  76. ctx.HTML(200, tpl)
  77. }
  78. // Handle handles and logs error by given status.
  79. func (ctx *Context) Handle(status int, title string, err error) {
  80. if err != nil {
  81. log.Error(4, "%s: %v", title, err)
  82. if macaron.Env != macaron.PROD {
  83. ctx.Data["ErrorMsg"] = err
  84. }
  85. }
  86. switch status {
  87. case 404:
  88. ctx.Data["Title"] = "Page Not Found"
  89. case 500:
  90. ctx.Data["Title"] = "Internal Server Error"
  91. }
  92. ctx.HTML(status, base.TplName(fmt.Sprintf("status/%d", status)))
  93. }
  94. // NotFoundOrServerError use error check function to determine if the error
  95. // is about not found. It responses with 404 status code for not found error,
  96. // or error context description for logging purpose of 500 server error.
  97. func (ctx *Context) NotFoundOrServerError(title string, errck func(error) bool, err error) {
  98. if errck(err) {
  99. ctx.Handle(404, title, err)
  100. return
  101. }
  102. ctx.Handle(500, title, err)
  103. }
  104. // HandleText handles HTTP status code
  105. func (ctx *Context) HandleText(status int, title string) {
  106. if (status/100 == 4) || (status/100 == 5) {
  107. log.Error(4, "%s", title)
  108. }
  109. ctx.PlainText(status, []byte(title))
  110. }
  111. // ServeContent serves content to http request
  112. func (ctx *Context) ServeContent(name string, r io.ReadSeeker, params ...interface{}) {
  113. modtime := time.Now()
  114. for _, p := range params {
  115. switch v := p.(type) {
  116. case time.Time:
  117. modtime = v
  118. }
  119. }
  120. ctx.Resp.Header().Set("Content-Description", "File Transfer")
  121. ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
  122. ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+name)
  123. ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary")
  124. ctx.Resp.Header().Set("Expires", "0")
  125. ctx.Resp.Header().Set("Cache-Control", "must-revalidate")
  126. ctx.Resp.Header().Set("Pragma", "public")
  127. http.ServeContent(ctx.Resp, ctx.Req.Request, name, modtime, r)
  128. }
  129. // Contexter initializes a classic context for a request.
  130. func Contexter() macaron.Handler {
  131. return func(c *macaron.Context, l i18n.Locale, cache cache.Cache, sess session.Store, f *session.Flash, x csrf.CSRF) {
  132. ctx := &Context{
  133. Context: c,
  134. Cache: cache,
  135. csrf: x,
  136. Flash: f,
  137. Session: sess,
  138. Repo: &Repository{
  139. PullRequest: &PullRequest{},
  140. },
  141. Org: &Organization{},
  142. }
  143. // Compute current URL for real-time change language.
  144. ctx.Data["Link"] = setting.AppSubURL + strings.TrimSuffix(ctx.Req.URL.Path, "/")
  145. ctx.Data["PageStartTime"] = time.Now()
  146. // Get user from session if logined.
  147. ctx.User, ctx.IsBasicAuth = auth.SignedInUser(ctx.Context, ctx.Session)
  148. if ctx.User != nil {
  149. ctx.IsSigned = true
  150. ctx.Data["IsSigned"] = ctx.IsSigned
  151. ctx.Data["SignedUser"] = ctx.User
  152. ctx.Data["SignedUserID"] = ctx.User.ID
  153. ctx.Data["SignedUserName"] = ctx.User.Name
  154. ctx.Data["IsAdmin"] = ctx.User.IsAdmin
  155. } else {
  156. ctx.Data["SignedUserID"] = 0
  157. ctx.Data["SignedUserName"] = ""
  158. }
  159. // If request sends files, parse them here otherwise the Query() can't be parsed and the CsrfToken will be invalid.
  160. if ctx.Req.Method == "POST" && strings.Contains(ctx.Req.Header.Get("Content-Type"), "multipart/form-data") {
  161. if err := ctx.Req.ParseMultipartForm(setting.AttachmentMaxSize << 20); err != nil && !strings.Contains(err.Error(), "EOF") { // 32MB max size
  162. ctx.Handle(500, "ParseMultipartForm", err)
  163. return
  164. }
  165. }
  166. ctx.Resp.Header().Set(`X-Frame-Options`, `SAMEORIGIN`)
  167. ctx.Data["CsrfToken"] = html.EscapeString(x.GetToken())
  168. ctx.Data["CsrfTokenHtml"] = template.HTML(`<input type="hidden" name="_csrf" value="` + ctx.Data["CsrfToken"].(string) + `">`)
  169. log.Debug("Session ID: %s", sess.ID())
  170. log.Debug("CSRF Token: %v", ctx.Data["CsrfToken"])
  171. ctx.Data["ShowRegistrationButton"] = setting.Service.ShowRegistrationButton
  172. ctx.Data["ShowFooterBranding"] = setting.ShowFooterBranding
  173. ctx.Data["ShowFooterVersion"] = setting.ShowFooterVersion
  174. c.Map(ctx)
  175. }
  176. }