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.

211 lines
5.6 KiB

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
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
  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 middleware
  5. import (
  6. "fmt"
  7. "html/template"
  8. "io"
  9. "net/http"
  10. "path"
  11. "strings"
  12. "time"
  13. "github.com/Unknwon/macaron"
  14. "github.com/macaron-contrib/cache"
  15. "github.com/macaron-contrib/csrf"
  16. "github.com/macaron-contrib/i18n"
  17. "github.com/macaron-contrib/session"
  18. "github.com/gogits/gogs/models"
  19. "github.com/gogits/gogs/modules/auth"
  20. "github.com/gogits/gogs/modules/base"
  21. "github.com/gogits/gogs/modules/git"
  22. "github.com/gogits/gogs/modules/log"
  23. "github.com/gogits/gogs/modules/setting"
  24. )
  25. // Context represents context of a request.
  26. type Context struct {
  27. *macaron.Context
  28. i18n.Locale
  29. Cache cache.Cache
  30. csrf csrf.CSRF
  31. Flash *session.Flash
  32. Session session.Store
  33. User *models.User
  34. IsSigned bool
  35. Repo struct {
  36. IsOwner bool
  37. IsTrueOwner bool
  38. IsWatching bool
  39. IsBranch bool
  40. IsTag bool
  41. IsCommit bool
  42. HasAccess bool
  43. Repository *models.Repository
  44. Owner *models.User
  45. Commit *git.Commit
  46. Tag *git.Tag
  47. GitRepo *git.Repository
  48. BranchName string
  49. TagName string
  50. CommitId string
  51. RepoLink string
  52. CloneLink struct {
  53. SSH string
  54. HTTPS string
  55. Git string
  56. }
  57. CommitsCount int
  58. Mirror *models.Mirror
  59. }
  60. }
  61. // Query querys form parameter.
  62. func (ctx *Context) Query(name string) string {
  63. ctx.Req.ParseForm()
  64. return ctx.Req.Form.Get(name)
  65. }
  66. // HasError returns true if error occurs in form validation.
  67. func (ctx *Context) HasApiError() bool {
  68. hasErr, ok := ctx.Data["HasError"]
  69. if !ok {
  70. return false
  71. }
  72. return hasErr.(bool)
  73. }
  74. func (ctx *Context) GetErrMsg() string {
  75. return ctx.Data["ErrorMsg"].(string)
  76. }
  77. // HasError returns true if error occurs in form validation.
  78. func (ctx *Context) HasError() bool {
  79. hasErr, ok := ctx.Data["HasError"]
  80. if !ok {
  81. return false
  82. }
  83. ctx.Flash.ErrorMsg = ctx.Data["ErrorMsg"].(string)
  84. ctx.Data["Flash"] = ctx.Flash
  85. return hasErr.(bool)
  86. }
  87. // HTML calls render.HTML underlying but reduce one argument.
  88. func (ctx *Context) HTML(status int, name base.TplName) {
  89. ctx.Render.HTML(status, string(name), ctx.Data)
  90. }
  91. // RenderWithErr used for page has form validation but need to prompt error to users.
  92. func (ctx *Context) RenderWithErr(msg string, tpl base.TplName, form interface{}) {
  93. if form != nil {
  94. auth.AssignForm(form, ctx.Data)
  95. }
  96. ctx.Flash.ErrorMsg = msg
  97. ctx.Data["Flash"] = ctx.Flash
  98. ctx.HTML(200, tpl)
  99. }
  100. // Handle handles and logs error by given status.
  101. func (ctx *Context) Handle(status int, title string, err error) {
  102. if err != nil {
  103. log.Error(4, "%s: %v", title, err)
  104. if macaron.Env != macaron.PROD {
  105. ctx.Data["ErrorMsg"] = err
  106. }
  107. }
  108. switch status {
  109. case 404:
  110. ctx.Data["Title"] = "Page Not Found"
  111. case 500:
  112. ctx.Data["Title"] = "Internal Server Error"
  113. }
  114. ctx.HTML(status, base.TplName(fmt.Sprintf("status/%d", status)))
  115. }
  116. func (ctx *Context) ServeFile(file string, names ...string) {
  117. var name string
  118. if len(names) > 0 {
  119. name = names[0]
  120. } else {
  121. name = path.Base(file)
  122. }
  123. ctx.Resp.Header().Set("Content-Description", "File Transfer")
  124. ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
  125. ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+name)
  126. ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary")
  127. ctx.Resp.Header().Set("Expires", "0")
  128. ctx.Resp.Header().Set("Cache-Control", "must-revalidate")
  129. ctx.Resp.Header().Set("Pragma", "public")
  130. http.ServeFile(ctx.Resp, ctx.Req, file)
  131. }
  132. func (ctx *Context) ServeContent(name string, r io.ReadSeeker, params ...interface{}) {
  133. modtime := time.Now()
  134. for _, p := range params {
  135. switch v := p.(type) {
  136. case time.Time:
  137. modtime = v
  138. }
  139. }
  140. ctx.Resp.Header().Set("Content-Description", "File Transfer")
  141. ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
  142. ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+name)
  143. ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary")
  144. ctx.Resp.Header().Set("Expires", "0")
  145. ctx.Resp.Header().Set("Cache-Control", "must-revalidate")
  146. ctx.Resp.Header().Set("Pragma", "public")
  147. http.ServeContent(ctx.Resp, ctx.Req, name, modtime, r)
  148. }
  149. // Contexter initializes a classic context for a request.
  150. func Contexter() macaron.Handler {
  151. return func(c *macaron.Context, l i18n.Locale, cache cache.Cache, sess session.Store, f *session.Flash, x csrf.CSRF) {
  152. ctx := &Context{
  153. Context: c,
  154. Locale: l,
  155. Cache: cache,
  156. csrf: x,
  157. Flash: f,
  158. Session: sess,
  159. }
  160. // Compute current URL for real-time change language.
  161. link := ctx.Req.RequestURI
  162. i := strings.Index(link, "?")
  163. if i > -1 {
  164. link = link[:i]
  165. }
  166. ctx.Data["Link"] = link
  167. ctx.Data["PageStartTime"] = time.Now()
  168. // Get user from session if logined.
  169. ctx.User = auth.SignedInUser(ctx.Req.Header, ctx.Session)
  170. if ctx.User != nil {
  171. ctx.IsSigned = true
  172. ctx.Data["IsSigned"] = ctx.IsSigned
  173. ctx.Data["SignedUser"] = ctx.User
  174. ctx.Data["IsAdmin"] = ctx.User.IsAdmin
  175. }
  176. // If request sends files, parse them here otherwise the Query() can't be parsed and the CsrfToken will be invalid.
  177. if ctx.Req.Method == "POST" && strings.Contains(ctx.Req.Header.Get("Content-Type"), "multipart/form-data") {
  178. if err := ctx.Req.ParseMultipartForm(setting.AttachmentMaxSize << 20); err != nil && !strings.Contains(err.Error(), "EOF") { // 32MB max size
  179. ctx.Handle(500, "ParseMultipartForm", err)
  180. return
  181. }
  182. }
  183. ctx.Data["CsrfToken"] = x.GetToken()
  184. ctx.Data["CsrfTokenHtml"] = template.HTML(`<input type="hidden" name="_csrf" value="` + x.GetToken() + `">`)
  185. c.Map(ctx)
  186. }
  187. }