1
0

controller.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. // Copyright 2014 beego Author. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package beego
  15. import (
  16. "bytes"
  17. "errors"
  18. "html/template"
  19. "io"
  20. "mime/multipart"
  21. "net/http"
  22. "net/url"
  23. "os"
  24. "reflect"
  25. "strconv"
  26. "strings"
  27. "github.com/astaxie/beego/context"
  28. "github.com/astaxie/beego/session"
  29. )
  30. //commonly used mime-types
  31. const (
  32. applicationJSON = "application/json"
  33. applicationXML = "application/xml"
  34. textXML = "text/xml"
  35. )
  36. var (
  37. // ErrAbort custom error when user stop request handler manually.
  38. ErrAbort = errors.New("User stop run")
  39. // GlobalControllerRouter store comments with controller. pkgpath+controller:comments
  40. GlobalControllerRouter = make(map[string][]ControllerComments)
  41. )
  42. // ControllerComments store the comment for the controller method
  43. type ControllerComments struct {
  44. Method string
  45. Router string
  46. AllowHTTPMethods []string
  47. Params []map[string]string
  48. }
  49. // Controller defines some basic http request handler operations, such as
  50. // http context, template and view, session and xsrf.
  51. type Controller struct {
  52. // context data
  53. Ctx *context.Context
  54. Data map[interface{}]interface{}
  55. // route controller info
  56. controllerName string
  57. actionName string
  58. methodMapping map[string]func() //method:routertree
  59. gotofunc string
  60. AppController interface{}
  61. // template data
  62. TplName string
  63. ViewPath string
  64. Layout string
  65. LayoutSections map[string]string // the key is the section name and the value is the template name
  66. TplPrefix string
  67. TplExt string
  68. EnableRender bool
  69. // xsrf data
  70. _xsrfToken string
  71. XSRFExpire int
  72. EnableXSRF bool
  73. // session
  74. CruSession session.Store
  75. }
  76. // ControllerInterface is an interface to uniform all controller handler.
  77. type ControllerInterface interface {
  78. Init(ct *context.Context, controllerName, actionName string, app interface{})
  79. Prepare()
  80. Get()
  81. Post()
  82. Delete()
  83. Put()
  84. Head()
  85. Patch()
  86. Options()
  87. Finish()
  88. Render() error
  89. XSRFToken() string
  90. CheckXSRFCookie() bool
  91. HandlerFunc(fn string) bool
  92. URLMapping()
  93. }
  94. // Init generates default values of controller operations.
  95. func (c *Controller) Init(ctx *context.Context, controllerName, actionName string, app interface{}) {
  96. c.Layout = ""
  97. c.TplName = ""
  98. c.controllerName = controllerName
  99. c.actionName = actionName
  100. c.Ctx = ctx
  101. c.TplExt = "tpl"
  102. c.AppController = app
  103. c.EnableRender = true
  104. c.EnableXSRF = true
  105. c.Data = ctx.Input.Data()
  106. c.methodMapping = make(map[string]func())
  107. }
  108. // Prepare runs after Init before request function execution.
  109. func (c *Controller) Prepare() {}
  110. // Finish runs after request function execution.
  111. func (c *Controller) Finish() {}
  112. // Get adds a request function to handle GET request.
  113. func (c *Controller) Get() {
  114. http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
  115. }
  116. // Post adds a request function to handle POST request.
  117. func (c *Controller) Post() {
  118. http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
  119. }
  120. // Delete adds a request function to handle DELETE request.
  121. func (c *Controller) Delete() {
  122. http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
  123. }
  124. // Put adds a request function to handle PUT request.
  125. func (c *Controller) Put() {
  126. http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
  127. }
  128. // Head adds a request function to handle HEAD request.
  129. func (c *Controller) Head() {
  130. http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
  131. }
  132. // Patch adds a request function to handle PATCH request.
  133. func (c *Controller) Patch() {
  134. http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
  135. }
  136. // Options adds a request function to handle OPTIONS request.
  137. func (c *Controller) Options() {
  138. http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
  139. }
  140. // HandlerFunc call function with the name
  141. func (c *Controller) HandlerFunc(fnname string) bool {
  142. if v, ok := c.methodMapping[fnname]; ok {
  143. v()
  144. return true
  145. }
  146. return false
  147. }
  148. // URLMapping register the internal Controller router.
  149. func (c *Controller) URLMapping() {}
  150. // Mapping the method to function
  151. func (c *Controller) Mapping(method string, fn func()) {
  152. c.methodMapping[method] = fn
  153. }
  154. // Render sends the response with rendered template bytes as text/html type.
  155. func (c *Controller) Render() error {
  156. if !c.EnableRender {
  157. return nil
  158. }
  159. rb, err := c.RenderBytes()
  160. if err != nil {
  161. return err
  162. }
  163. if c.Ctx.ResponseWriter.Header().Get("Content-Type") == "" {
  164. c.Ctx.Output.Header("Content-Type", "text/html; charset=utf-8")
  165. }
  166. return c.Ctx.Output.Body(rb)
  167. }
  168. // RenderString returns the rendered template string. Do not send out response.
  169. func (c *Controller) RenderString() (string, error) {
  170. b, e := c.RenderBytes()
  171. return string(b), e
  172. }
  173. // RenderBytes returns the bytes of rendered template string. Do not send out response.
  174. func (c *Controller) RenderBytes() ([]byte, error) {
  175. buf, err := c.renderTemplate()
  176. //if the controller has set layout, then first get the tplName's content set the content to the layout
  177. if err == nil && c.Layout != "" {
  178. c.Data["LayoutContent"] = template.HTML(buf.String())
  179. if c.LayoutSections != nil {
  180. for sectionName, sectionTpl := range c.LayoutSections {
  181. if sectionTpl == "" {
  182. c.Data[sectionName] = ""
  183. continue
  184. }
  185. buf.Reset()
  186. err = ExecuteViewPathTemplate(&buf, sectionTpl, c.viewPath(), c.Data)
  187. if err != nil {
  188. return nil, err
  189. }
  190. c.Data[sectionName] = template.HTML(buf.String())
  191. }
  192. }
  193. buf.Reset()
  194. ExecuteViewPathTemplate(&buf, c.Layout, c.viewPath() ,c.Data)
  195. }
  196. return buf.Bytes(), err
  197. }
  198. func (c *Controller) renderTemplate() (bytes.Buffer, error) {
  199. var buf bytes.Buffer
  200. if c.TplName == "" {
  201. c.TplName = strings.ToLower(c.controllerName) + "/" + strings.ToLower(c.actionName) + "." + c.TplExt
  202. }
  203. if c.TplPrefix != "" {
  204. c.TplName = c.TplPrefix + c.TplName
  205. }
  206. if BConfig.RunMode == DEV {
  207. buildFiles := []string{c.TplName}
  208. if c.Layout != "" {
  209. buildFiles = append(buildFiles, c.Layout)
  210. if c.LayoutSections != nil {
  211. for _, sectionTpl := range c.LayoutSections {
  212. if sectionTpl == "" {
  213. continue
  214. }
  215. buildFiles = append(buildFiles, sectionTpl)
  216. }
  217. }
  218. }
  219. BuildTemplate(c.viewPath() , buildFiles...)
  220. }
  221. return buf, ExecuteViewPathTemplate(&buf, c.TplName, c.viewPath(), c.Data)
  222. }
  223. func (c *Controller) viewPath() string {
  224. if c.ViewPath == "" {
  225. return BConfig.WebConfig.ViewsPath
  226. }
  227. return c.ViewPath
  228. }
  229. // Redirect sends the redirection response to url with status code.
  230. func (c *Controller) Redirect(url string, code int) {
  231. c.Ctx.Redirect(code, url)
  232. }
  233. // Abort stops controller handler and show the error data if code is defined in ErrorMap or code string.
  234. func (c *Controller) Abort(code string) {
  235. status, err := strconv.Atoi(code)
  236. if err != nil {
  237. status = 200
  238. }
  239. c.CustomAbort(status, code)
  240. }
  241. // CustomAbort stops controller handler and show the error data, it's similar Aborts, but support status code and body.
  242. func (c *Controller) CustomAbort(status int, body string) {
  243. // first panic from ErrorMaps, it is user defined error functions.
  244. if _, ok := ErrorMaps[body]; ok {
  245. c.Ctx.Output.Status = status
  246. panic(body)
  247. }
  248. // last panic user string
  249. c.Ctx.ResponseWriter.WriteHeader(status)
  250. c.Ctx.ResponseWriter.Write([]byte(body))
  251. panic(ErrAbort)
  252. }
  253. // StopRun makes panic of USERSTOPRUN error and go to recover function if defined.
  254. func (c *Controller) StopRun() {
  255. panic(ErrAbort)
  256. }
  257. // URLFor does another controller handler in this request function.
  258. // it goes to this controller method if endpoint is not clear.
  259. func (c *Controller) URLFor(endpoint string, values ...interface{}) string {
  260. if len(endpoint) == 0 {
  261. return ""
  262. }
  263. if endpoint[0] == '.' {
  264. return URLFor(reflect.Indirect(reflect.ValueOf(c.AppController)).Type().Name()+endpoint, values...)
  265. }
  266. return URLFor(endpoint, values...)
  267. }
  268. // ServeJSON sends a json response with encoding charset.
  269. func (c *Controller) ServeJSON(encoding ...bool) {
  270. var (
  271. hasIndent = true
  272. hasEncoding = false
  273. )
  274. if BConfig.RunMode == PROD {
  275. hasIndent = false
  276. }
  277. if len(encoding) > 0 && encoding[0] == true {
  278. hasEncoding = true
  279. }
  280. c.Ctx.Output.JSON(c.Data["json"], hasIndent, hasEncoding)
  281. }
  282. // ServeJSONP sends a jsonp response.
  283. func (c *Controller) ServeJSONP() {
  284. hasIndent := true
  285. if BConfig.RunMode == PROD {
  286. hasIndent = false
  287. }
  288. c.Ctx.Output.JSONP(c.Data["jsonp"], hasIndent)
  289. }
  290. // ServeXML sends xml response.
  291. func (c *Controller) ServeXML() {
  292. hasIndent := true
  293. if BConfig.RunMode == PROD {
  294. hasIndent = false
  295. }
  296. c.Ctx.Output.XML(c.Data["xml"], hasIndent)
  297. }
  298. // ServeFormatted serve Xml OR Json, depending on the value of the Accept header
  299. func (c *Controller) ServeFormatted() {
  300. accept := c.Ctx.Input.Header("Accept")
  301. switch accept {
  302. case applicationJSON:
  303. c.ServeJSON()
  304. case applicationXML, textXML:
  305. c.ServeXML()
  306. default:
  307. c.ServeJSON()
  308. }
  309. }
  310. // Input returns the input data map from POST or PUT request body and query string.
  311. func (c *Controller) Input() url.Values {
  312. if c.Ctx.Request.Form == nil {
  313. c.Ctx.Request.ParseForm()
  314. }
  315. return c.Ctx.Request.Form
  316. }
  317. // ParseForm maps input data map to obj struct.
  318. func (c *Controller) ParseForm(obj interface{}) error {
  319. return ParseForm(c.Input(), obj)
  320. }
  321. // GetString returns the input value by key string or the default value while it's present and input is blank
  322. func (c *Controller) GetString(key string, def ...string) string {
  323. if v := c.Ctx.Input.Query(key); v != "" {
  324. return v
  325. }
  326. if len(def) > 0 {
  327. return def[0]
  328. }
  329. return ""
  330. }
  331. // GetStrings returns the input string slice by key string or the default value while it's present and input is blank
  332. // it's designed for multi-value input field such as checkbox(input[type=checkbox]), multi-selection.
  333. func (c *Controller) GetStrings(key string, def ...[]string) []string {
  334. var defv []string
  335. if len(def) > 0 {
  336. defv = def[0]
  337. }
  338. if f := c.Input(); f == nil {
  339. return defv
  340. } else if vs := f[key]; len(vs) > 0 {
  341. return vs
  342. }
  343. return defv
  344. }
  345. // GetInt returns input as an int or the default value while it's present and input is blank
  346. func (c *Controller) GetInt(key string, def ...int) (int, error) {
  347. strv := c.Ctx.Input.Query(key)
  348. if len(strv) == 0 && len(def) > 0 {
  349. return def[0], nil
  350. }
  351. return strconv.Atoi(strv)
  352. }
  353. // GetInt8 return input as an int8 or the default value while it's present and input is blank
  354. func (c *Controller) GetInt8(key string, def ...int8) (int8, error) {
  355. strv := c.Ctx.Input.Query(key)
  356. if len(strv) == 0 && len(def) > 0 {
  357. return def[0], nil
  358. }
  359. i64, err := strconv.ParseInt(strv, 10, 8)
  360. return int8(i64), err
  361. }
  362. // GetUint8 return input as an uint8 or the default value while it's present and input is blank
  363. func (c *Controller) GetUint8(key string, def ...uint8) (uint8, error) {
  364. strv := c.Ctx.Input.Query(key)
  365. if len(strv) == 0 && len(def) > 0 {
  366. return def[0], nil
  367. }
  368. u64, err := strconv.ParseUint(strv, 10, 8)
  369. return uint8(u64), err
  370. }
  371. // GetInt16 returns input as an int16 or the default value while it's present and input is blank
  372. func (c *Controller) GetInt16(key string, def ...int16) (int16, error) {
  373. strv := c.Ctx.Input.Query(key)
  374. if len(strv) == 0 && len(def) > 0 {
  375. return def[0], nil
  376. }
  377. i64, err := strconv.ParseInt(strv, 10, 16)
  378. return int16(i64), err
  379. }
  380. // GetUint16 returns input as an uint16 or the default value while it's present and input is blank
  381. func (c *Controller) GetUint16(key string, def ...uint16) (uint16, error) {
  382. strv := c.Ctx.Input.Query(key)
  383. if len(strv) == 0 && len(def) > 0 {
  384. return def[0], nil
  385. }
  386. u64, err := strconv.ParseUint(strv, 10, 16)
  387. return uint16(u64), err
  388. }
  389. // GetInt32 returns input as an int32 or the default value while it's present and input is blank
  390. func (c *Controller) GetInt32(key string, def ...int32) (int32, error) {
  391. strv := c.Ctx.Input.Query(key)
  392. if len(strv) == 0 && len(def) > 0 {
  393. return def[0], nil
  394. }
  395. i64, err := strconv.ParseInt(strv, 10, 32)
  396. return int32(i64), err
  397. }
  398. // GetUint32 returns input as an uint32 or the default value while it's present and input is blank
  399. func (c *Controller) GetUint32(key string, def ...uint32) (uint32, error) {
  400. strv := c.Ctx.Input.Query(key)
  401. if len(strv) == 0 && len(def) > 0 {
  402. return def[0], nil
  403. }
  404. u64, err := strconv.ParseUint(strv, 10, 32)
  405. return uint32(u64), err
  406. }
  407. // GetInt64 returns input value as int64 or the default value while it's present and input is blank.
  408. func (c *Controller) GetInt64(key string, def ...int64) (int64, error) {
  409. strv := c.Ctx.Input.Query(key)
  410. if len(strv) == 0 && len(def) > 0 {
  411. return def[0], nil
  412. }
  413. return strconv.ParseInt(strv, 10, 64)
  414. }
  415. // GetUint64 returns input value as uint64 or the default value while it's present and input is blank.
  416. func (c *Controller) GetUint64(key string, def ...uint64) (uint64, error) {
  417. strv := c.Ctx.Input.Query(key)
  418. if len(strv) == 0 && len(def) > 0 {
  419. return def[0], nil
  420. }
  421. return strconv.ParseUint(strv, 10, 64)
  422. }
  423. // GetBool returns input value as bool or the default value while it's present and input is blank.
  424. func (c *Controller) GetBool(key string, def ...bool) (bool, error) {
  425. strv := c.Ctx.Input.Query(key)
  426. if len(strv) == 0 && len(def) > 0 {
  427. return def[0], nil
  428. }
  429. return strconv.ParseBool(strv)
  430. }
  431. // GetFloat returns input value as float64 or the default value while it's present and input is blank.
  432. func (c *Controller) GetFloat(key string, def ...float64) (float64, error) {
  433. strv := c.Ctx.Input.Query(key)
  434. if len(strv) == 0 && len(def) > 0 {
  435. return def[0], nil
  436. }
  437. return strconv.ParseFloat(strv, 64)
  438. }
  439. // GetFile returns the file data in file upload field named as key.
  440. // it returns the first one of multi-uploaded files.
  441. func (c *Controller) GetFile(key string) (multipart.File, *multipart.FileHeader, error) {
  442. return c.Ctx.Request.FormFile(key)
  443. }
  444. // GetFiles return multi-upload files
  445. // files, err:=c.GetFiles("myfiles")
  446. // if err != nil {
  447. // http.Error(w, err.Error(), http.StatusNoContent)
  448. // return
  449. // }
  450. // for i, _ := range files {
  451. // //for each fileheader, get a handle to the actual file
  452. // file, err := files[i].Open()
  453. // defer file.Close()
  454. // if err != nil {
  455. // http.Error(w, err.Error(), http.StatusInternalServerError)
  456. // return
  457. // }
  458. // //create destination file making sure the path is writeable.
  459. // dst, err := os.Create("upload/" + files[i].Filename)
  460. // defer dst.Close()
  461. // if err != nil {
  462. // http.Error(w, err.Error(), http.StatusInternalServerError)
  463. // return
  464. // }
  465. // //copy the uploaded file to the destination file
  466. // if _, err := io.Copy(dst, file); err != nil {
  467. // http.Error(w, err.Error(), http.StatusInternalServerError)
  468. // return
  469. // }
  470. // }
  471. func (c *Controller) GetFiles(key string) ([]*multipart.FileHeader, error) {
  472. if files, ok := c.Ctx.Request.MultipartForm.File[key]; ok {
  473. return files, nil
  474. }
  475. return nil, http.ErrMissingFile
  476. }
  477. // SaveToFile saves uploaded file to new path.
  478. // it only operates the first one of mutil-upload form file field.
  479. func (c *Controller) SaveToFile(fromfile, tofile string) error {
  480. file, _, err := c.Ctx.Request.FormFile(fromfile)
  481. if err != nil {
  482. return err
  483. }
  484. defer file.Close()
  485. f, err := os.OpenFile(tofile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
  486. if err != nil {
  487. return err
  488. }
  489. defer f.Close()
  490. io.Copy(f, file)
  491. return nil
  492. }
  493. // StartSession starts session and load old session data info this controller.
  494. func (c *Controller) StartSession() session.Store {
  495. if c.CruSession == nil {
  496. c.CruSession = c.Ctx.Input.CruSession
  497. }
  498. return c.CruSession
  499. }
  500. // SetSession puts value into session.
  501. func (c *Controller) SetSession(name interface{}, value interface{}) {
  502. if c.CruSession == nil {
  503. c.StartSession()
  504. }
  505. c.CruSession.Set(name, value)
  506. }
  507. // GetSession gets value from session.
  508. func (c *Controller) GetSession(name interface{}) interface{} {
  509. if c.CruSession == nil {
  510. c.StartSession()
  511. }
  512. return c.CruSession.Get(name)
  513. }
  514. // DelSession removes value from session.
  515. func (c *Controller) DelSession(name interface{}) {
  516. if c.CruSession == nil {
  517. c.StartSession()
  518. }
  519. c.CruSession.Delete(name)
  520. }
  521. // SessionRegenerateID regenerates session id for this session.
  522. // the session data have no changes.
  523. func (c *Controller) SessionRegenerateID() {
  524. if c.CruSession != nil {
  525. c.CruSession.SessionRelease(c.Ctx.ResponseWriter)
  526. }
  527. c.CruSession = GlobalSessions.SessionRegenerateID(c.Ctx.ResponseWriter, c.Ctx.Request)
  528. c.Ctx.Input.CruSession = c.CruSession
  529. }
  530. // DestroySession cleans session data and session cookie.
  531. func (c *Controller) DestroySession() {
  532. c.Ctx.Input.CruSession.Flush()
  533. c.Ctx.Input.CruSession = nil
  534. GlobalSessions.SessionDestroy(c.Ctx.ResponseWriter, c.Ctx.Request)
  535. }
  536. // IsAjax returns this request is ajax or not.
  537. func (c *Controller) IsAjax() bool {
  538. return c.Ctx.Input.IsAjax()
  539. }
  540. // GetSecureCookie returns decoded cookie value from encoded browser cookie values.
  541. func (c *Controller) GetSecureCookie(Secret, key string) (string, bool) {
  542. return c.Ctx.GetSecureCookie(Secret, key)
  543. }
  544. // SetSecureCookie puts value into cookie after encoded the value.
  545. func (c *Controller) SetSecureCookie(Secret, name, value string, others ...interface{}) {
  546. c.Ctx.SetSecureCookie(Secret, name, value, others...)
  547. }
  548. // XSRFToken creates a CSRF token string and returns.
  549. func (c *Controller) XSRFToken() string {
  550. if c._xsrfToken == "" {
  551. expire := int64(BConfig.WebConfig.XSRFExpire)
  552. if c.XSRFExpire > 0 {
  553. expire = int64(c.XSRFExpire)
  554. }
  555. c._xsrfToken = c.Ctx.XSRFToken(BConfig.WebConfig.XSRFKey, expire)
  556. }
  557. return c._xsrfToken
  558. }
  559. // CheckXSRFCookie checks xsrf token in this request is valid or not.
  560. // the token can provided in request header "X-Xsrftoken" and "X-CsrfToken"
  561. // or in form field value named as "_xsrf".
  562. func (c *Controller) CheckXSRFCookie() bool {
  563. if !c.EnableXSRF {
  564. return true
  565. }
  566. return c.Ctx.CheckXSRFCookie()
  567. }
  568. // XSRFFormHTML writes an input field contains xsrf token value.
  569. func (c *Controller) XSRFFormHTML() string {
  570. return `<input type="hidden" name="_xsrf" value="` +
  571. c.XSRFToken() + `" />`
  572. }
  573. // GetControllerAndAction gets the executing controller name and action name.
  574. func (c *Controller) GetControllerAndAction() (string, string) {
  575. return c.controllerName, c.actionName
  576. }