You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

context.go 7.6 kB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
9 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
9 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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. "html"
  7. "html/template"
  8. "io"
  9. "net/http"
  10. "path"
  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/Unknwon/com"
  19. "github.com/go-macaron/cache"
  20. "github.com/go-macaron/csrf"
  21. "github.com/go-macaron/i18n"
  22. "github.com/go-macaron/session"
  23. macaron "gopkg.in/macaron.v1"
  24. )
  25. // Context represents context of a request.
  26. type Context struct {
  27. *macaron.Context
  28. Cache cache.Cache
  29. csrf csrf.CSRF
  30. Flash *session.Flash
  31. Session session.Store
  32. Link string // current request URL
  33. EscapedLink string
  34. User *models.User
  35. IsSigned bool
  36. IsBasicAuth bool
  37. Repo *Repository
  38. Org *Organization
  39. }
  40. // HasAPIError returns true if error occurs in form validation.
  41. func (ctx *Context) HasAPIError() bool {
  42. hasErr, ok := ctx.Data["HasError"]
  43. if !ok {
  44. return false
  45. }
  46. return hasErr.(bool)
  47. }
  48. // GetErrMsg returns error message
  49. func (ctx *Context) GetErrMsg() string {
  50. return ctx.Data["ErrorMsg"].(string)
  51. }
  52. // HasError returns true if error occurs in form validation.
  53. func (ctx *Context) HasError() bool {
  54. hasErr, ok := ctx.Data["HasError"]
  55. if !ok {
  56. return false
  57. }
  58. ctx.Flash.ErrorMsg = ctx.Data["ErrorMsg"].(string)
  59. ctx.Data["Flash"] = ctx.Flash
  60. return hasErr.(bool)
  61. }
  62. // HasValue returns true if value of given name exists.
  63. func (ctx *Context) HasValue(name string) bool {
  64. _, ok := ctx.Data[name]
  65. return ok
  66. }
  67. // HTML calls Context.HTML and converts template name to string.
  68. func (ctx *Context) HTML(status int, name base.TplName) {
  69. log.Debug("Template: %s", name)
  70. ctx.Context.HTML(status, string(name))
  71. }
  72. // RenderWithErr used for page has form validation but need to prompt error to users.
  73. func (ctx *Context) RenderWithErr(msg string, tpl base.TplName, form interface{}) {
  74. if form != nil {
  75. auth.AssignForm(form, ctx.Data)
  76. }
  77. ctx.Flash.ErrorMsg = msg
  78. ctx.Data["Flash"] = ctx.Flash
  79. ctx.HTML(200, tpl)
  80. }
  81. // NotFound displays a 404 (Not Found) page and prints the given error, if any.
  82. func (ctx *Context) NotFound(title string, err error) {
  83. if err != nil {
  84. log.Error(4, "%s: %v", title, err)
  85. if macaron.Env != macaron.PROD {
  86. ctx.Data["ErrorMsg"] = err
  87. }
  88. }
  89. ctx.Data["Title"] = "Page Not Found"
  90. ctx.HTML(http.StatusNotFound, base.TplName("status/404"))
  91. }
  92. // ServerError displays a 500 (Internal Server Error) page and prints the given
  93. // error, if any.
  94. func (ctx *Context) ServerError(title string, err error) {
  95. if err != nil {
  96. log.Error(4, "%s: %v", title, err)
  97. if macaron.Env != macaron.PROD {
  98. ctx.Data["ErrorMsg"] = err
  99. }
  100. }
  101. ctx.Data["Title"] = "Internal Server Error"
  102. ctx.HTML(404, base.TplName("status/500"))
  103. }
  104. // NotFoundOrServerError use error check function to determine if the error
  105. // is about not found. It responses with 404 status code for not found error,
  106. // or error context description for logging purpose of 500 server error.
  107. func (ctx *Context) NotFoundOrServerError(title string, errck func(error) bool, err error) {
  108. if errck(err) {
  109. ctx.NotFound(title, err)
  110. return
  111. }
  112. ctx.ServerError(title, err)
  113. }
  114. // HandleText handles HTTP status code
  115. func (ctx *Context) HandleText(status int, title string) {
  116. if (status/100 == 4) || (status/100 == 5) {
  117. log.Error(4, "%s", title)
  118. }
  119. ctx.PlainText(status, []byte(title))
  120. }
  121. // ServeContent serves content to http request
  122. func (ctx *Context) ServeContent(name string, r io.ReadSeeker, params ...interface{}) {
  123. modtime := time.Now()
  124. for _, p := range params {
  125. switch v := p.(type) {
  126. case time.Time:
  127. modtime = v
  128. }
  129. }
  130. ctx.Resp.Header().Set("Content-Description", "File Transfer")
  131. ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
  132. ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+name)
  133. ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary")
  134. ctx.Resp.Header().Set("Expires", "0")
  135. ctx.Resp.Header().Set("Cache-Control", "must-revalidate")
  136. ctx.Resp.Header().Set("Pragma", "public")
  137. http.ServeContent(ctx.Resp, ctx.Req.Request, name, modtime, r)
  138. }
  139. // Contexter initializes a classic context for a request.
  140. func Contexter() macaron.Handler {
  141. return func(c *macaron.Context, l i18n.Locale, cache cache.Cache, sess session.Store, f *session.Flash, x csrf.CSRF) {
  142. ctx := &Context{
  143. Context: c,
  144. Cache: cache,
  145. csrf: x,
  146. Flash: f,
  147. Session: sess,
  148. Link: setting.AppSubURL + strings.TrimSuffix(c.Req.URL.EscapedPath(), "/"),
  149. Repo: &Repository{
  150. PullRequest: &PullRequest{},
  151. },
  152. Org: &Organization{},
  153. }
  154. c.Data["Link"] = ctx.Link
  155. ctx.Data["PageStartTime"] = time.Now()
  156. // Quick responses appropriate go-get meta with status 200
  157. // regardless of if user have access to the repository,
  158. // or the repository does not exist at all.
  159. // This is particular a workaround for "go get" command which does not respect
  160. // .netrc file.
  161. if ctx.Query("go-get") == "1" {
  162. ownerName := c.Params(":username")
  163. repoName := c.Params(":reponame")
  164. branchName := "master"
  165. repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName)
  166. if err == nil && len(repo.DefaultBranch) > 0 {
  167. branchName = repo.DefaultBranch
  168. }
  169. prefix := setting.AppURL + path.Join(ownerName, repoName, "src", "branch", branchName)
  170. c.PlainText(http.StatusOK, []byte(com.Expand(`
  171. <html>
  172. <head>
  173. <meta name="go-import" content="{GoGetImport} git {CloneLink}">
  174. <meta name="go-source" content="{GoGetImport} _ {GoDocDirectory} {GoDocFile}">
  175. </head>
  176. <body>
  177. go get {GoGetImport}
  178. </body>
  179. </html>
  180. `, map[string]string{
  181. "GoGetImport": ComposeGoGetImport(ownerName, strings.TrimSuffix(repoName, ".git")),
  182. "CloneLink": models.ComposeHTTPSCloneURL(ownerName, repoName),
  183. "GoDocDirectory": prefix + "{/dir}",
  184. "GoDocFile": prefix + "{/dir}/{file}#L{line}",
  185. })))
  186. return
  187. }
  188. // Get user from session if logged in.
  189. ctx.User, ctx.IsBasicAuth = auth.SignedInUser(ctx.Context, ctx.Session)
  190. if ctx.User != nil {
  191. ctx.IsSigned = true
  192. ctx.Data["IsSigned"] = ctx.IsSigned
  193. ctx.Data["SignedUser"] = ctx.User
  194. ctx.Data["SignedUserID"] = ctx.User.ID
  195. ctx.Data["SignedUserName"] = ctx.User.Name
  196. ctx.Data["IsAdmin"] = ctx.User.IsAdmin
  197. } else {
  198. ctx.Data["SignedUserID"] = int64(0)
  199. ctx.Data["SignedUserName"] = ""
  200. }
  201. // If request sends files, parse them here otherwise the Query() can't be parsed and the CsrfToken will be invalid.
  202. if ctx.Req.Method == "POST" && strings.Contains(ctx.Req.Header.Get("Content-Type"), "multipart/form-data") {
  203. if err := ctx.Req.ParseMultipartForm(setting.AttachmentMaxSize << 20); err != nil && !strings.Contains(err.Error(), "EOF") { // 32MB max size
  204. ctx.ServerError("ParseMultipartForm", err)
  205. return
  206. }
  207. }
  208. ctx.Resp.Header().Set(`X-Frame-Options`, `SAMEORIGIN`)
  209. ctx.Data["CsrfToken"] = html.EscapeString(x.GetToken())
  210. ctx.Data["CsrfTokenHtml"] = template.HTML(`<input type="hidden" name="_csrf" value="` + ctx.Data["CsrfToken"].(string) + `">`)
  211. log.Debug("Session ID: %s", sess.ID())
  212. log.Debug("CSRF Token: %v", ctx.Data["CsrfToken"])
  213. ctx.Data["ShowRegistrationButton"] = setting.Service.ShowRegistrationButton
  214. ctx.Data["ShowFooterBranding"] = setting.ShowFooterBranding
  215. ctx.Data["ShowFooterVersion"] = setting.ShowFooterVersion
  216. ctx.Data["EnableOpenIDSignIn"] = setting.Service.EnableOpenIDSignIn
  217. c.Map(ctx)
  218. }
  219. }