context.go 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. package gin
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "github.com/gin-gonic/gin/binding"
  7. "github.com/gin-gonic/gin/render"
  8. "github.com/julienschmidt/httprouter"
  9. "log"
  10. "net/http"
  11. )
  12. const (
  13. ErrorTypeInternal = 1 << iota
  14. ErrorTypeExternal = 1 << iota
  15. ErrorTypeAll = 0xffffffff
  16. )
  17. // Used internally to collect errors that occurred during an http request.
  18. type errorMsg struct {
  19. Err string `json:"error"`
  20. Type uint32 `json:"-"`
  21. Meta interface{} `json:"meta"`
  22. }
  23. type errorMsgs []errorMsg
  24. func (a errorMsgs) ByType(typ uint32) errorMsgs {
  25. if len(a) == 0 {
  26. return a
  27. }
  28. result := make(errorMsgs, 0, len(a))
  29. for _, msg := range a {
  30. if msg.Type&typ > 0 {
  31. result = append(result, msg)
  32. }
  33. }
  34. return result
  35. }
  36. func (a errorMsgs) String() string {
  37. if len(a) == 0 {
  38. return ""
  39. }
  40. var buffer bytes.Buffer
  41. for i, msg := range a {
  42. text := fmt.Sprintf("Error #%02d: %s \n Meta: %v\n", (i + 1), msg.Err, msg.Meta)
  43. buffer.WriteString(text)
  44. }
  45. return buffer.String()
  46. }
  47. // Context is the most important part of gin. It allows us to pass variables between middleware,
  48. // manage the flow, validate the JSON of a request and render a JSON response for example.
  49. type Context struct {
  50. writermem responseWriter
  51. Request *http.Request
  52. Writer ResponseWriter
  53. Keys map[string]interface{}
  54. Errors errorMsgs
  55. Params httprouter.Params
  56. Engine *Engine
  57. handlers []HandlerFunc
  58. index int8
  59. }
  60. /************************************/
  61. /********** ROUTES GROUPING *********/
  62. /************************************/
  63. func (engine *Engine) createContext(w http.ResponseWriter, req *http.Request, params httprouter.Params, handlers []HandlerFunc) *Context {
  64. c := engine.cache.Get().(*Context)
  65. c.writermem.reset(w)
  66. c.Request = req
  67. c.Params = params
  68. c.handlers = handlers
  69. c.Keys = nil
  70. c.index = -1
  71. c.Errors = c.Errors[0:0]
  72. return c
  73. }
  74. /************************************/
  75. /****** FLOW AND ERROR MANAGEMENT****/
  76. /************************************/
  77. func (c *Context) Copy() *Context {
  78. var cp Context = *c
  79. cp.index = AbortIndex
  80. cp.handlers = nil
  81. return &cp
  82. }
  83. // Next should be used only in the middlewares.
  84. // It executes the pending handlers in the chain inside the calling handler.
  85. // See example in github.
  86. func (c *Context) Next() {
  87. c.index++
  88. s := int8(len(c.handlers))
  89. for ; c.index < s; c.index++ {
  90. c.handlers[c.index](c)
  91. }
  92. }
  93. // Forces the system to do not continue calling the pending handlers.
  94. // For example, the first handler checks if the request is authorized. If it's not, context.Abort(401) should be called.
  95. // The rest of pending handlers would never be called for that request.
  96. func (c *Context) Abort(code int) {
  97. if code >= 0 {
  98. c.Writer.WriteHeader(code)
  99. }
  100. c.index = AbortIndex
  101. }
  102. // Fail is the same as Abort plus an error message.
  103. // Calling `context.Fail(500, err)` is equivalent to:
  104. // ```
  105. // context.Error("Operation aborted", err)
  106. // context.Abort(500)
  107. // ```
  108. func (c *Context) Fail(code int, err error) {
  109. c.Error(err, "Operation aborted")
  110. c.Abort(code)
  111. }
  112. func (c *Context) ErrorTyped(err error, typ uint32, meta interface{}) {
  113. c.Errors = append(c.Errors, errorMsg{
  114. Err: err.Error(),
  115. Type: typ,
  116. Meta: meta,
  117. })
  118. }
  119. // Attaches an error to the current context. The error is pushed to a list of errors.
  120. // It's a good idea to call Error for each error that occurred during the resolution of a request.
  121. // A middleware can be used to collect all the errors and push them to a database together, print a log, or append it in the HTTP response.
  122. func (c *Context) Error(err error, meta interface{}) {
  123. c.ErrorTyped(err, ErrorTypeExternal, meta)
  124. }
  125. func (c *Context) LastError() error {
  126. s := len(c.Errors)
  127. if s > 0 {
  128. return errors.New(c.Errors[s-1].Err)
  129. } else {
  130. return nil
  131. }
  132. }
  133. /************************************/
  134. /******** METADATA MANAGEMENT********/
  135. /************************************/
  136. // Sets a new pair key/value just for the specified context.
  137. // It also lazy initializes the hashmap.
  138. func (c *Context) Set(key string, item interface{}) {
  139. if c.Keys == nil {
  140. c.Keys = make(map[string]interface{})
  141. }
  142. c.Keys[key] = item
  143. }
  144. // Get returns the value for the given key or an error if the key does not exist.
  145. func (c *Context) Get(key string) (interface{}, error) {
  146. if c.Keys != nil {
  147. item, ok := c.Keys[key]
  148. if ok {
  149. return item, nil
  150. }
  151. }
  152. return nil, errors.New("Key does not exist.")
  153. }
  154. // MustGet returns the value for the given key or panics if the value doesn't exist.
  155. func (c *Context) MustGet(key string) interface{} {
  156. value, err := c.Get(key)
  157. if err != nil || value == nil {
  158. log.Panicf("Key %s doesn't exist", key)
  159. }
  160. return value
  161. }
  162. /************************************/
  163. /******** ENCOGING MANAGEMENT********/
  164. /************************************/
  165. // This function checks the Content-Type to select a binding engine automatically,
  166. // Depending the "Content-Type" header different bindings are used:
  167. // "application/json" --> JSON binding
  168. // "application/xml" --> XML binding
  169. // else --> returns an error
  170. // if Parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input. It decodes the json payload into the struct specified as a pointer.Like ParseBody() but this method also writes a 400 error if the json is not valid.
  171. func (c *Context) Bind(obj interface{}) bool {
  172. var b binding.Binding
  173. ctype := filterFlags(c.Request.Header.Get("Content-Type"))
  174. switch {
  175. case c.Request.Method == "GET" || ctype == MIMEPOSTForm:
  176. b = binding.Form
  177. case ctype == MIMEJSON:
  178. b = binding.JSON
  179. case ctype == MIMEXML || ctype == MIMEXML2:
  180. b = binding.XML
  181. default:
  182. c.Fail(400, errors.New("unknown content-type: "+ctype))
  183. return false
  184. }
  185. return c.BindWith(obj, b)
  186. }
  187. func (c *Context) BindWith(obj interface{}, b binding.Binding) bool {
  188. if err := b.Bind(c.Request, obj); err != nil {
  189. c.Fail(400, err)
  190. return false
  191. }
  192. return true
  193. }
  194. func (c *Context) Render(code int, render render.Render, obj ...interface{}) {
  195. if err := render.Render(c.Writer, code, obj...); err != nil {
  196. c.ErrorTyped(err, ErrorTypeInternal, obj)
  197. c.Abort(500)
  198. }
  199. }
  200. // Serializes the given struct as JSON into the response body in a fast and efficient way.
  201. // It also sets the Content-Type as "application/json".
  202. func (c *Context) JSON(code int, obj interface{}) {
  203. c.Render(code, render.JSON, obj)
  204. }
  205. // Serializes the given struct as XML into the response body in a fast and efficient way.
  206. // It also sets the Content-Type as "application/xml".
  207. func (c *Context) XML(code int, obj interface{}) {
  208. c.Render(code, render.XML, obj)
  209. }
  210. // Renders the HTTP template specified by its file name.
  211. // It also updates the HTTP code and sets the Content-Type as "text/html".
  212. // See http://golang.org/doc/articles/wiki/
  213. func (c *Context) HTML(code int, name string, obj interface{}) {
  214. c.Render(code, c.Engine.HTMLRender, name, obj)
  215. }
  216. // Writes the given string into the response body and sets the Content-Type to "text/plain".
  217. func (c *Context) String(code int, format string, values ...interface{}) {
  218. c.Render(code, render.Plain, format, values)
  219. }
  220. // Returns a HTTP redirect to the specific location.
  221. func (c *Context) Redirect(code int, location string) {
  222. if code >= 300 && code <= 308 {
  223. c.Render(code, render.Redirect, location)
  224. } else {
  225. panic(fmt.Sprintf("Cannot send a redirect with status code %d", code))
  226. }
  227. }
  228. // Writes some data into the body stream and updates the HTTP code.
  229. func (c *Context) Data(code int, contentType string, data []byte) {
  230. if len(contentType) > 0 {
  231. c.Writer.Header().Set("Content-Type", contentType)
  232. }
  233. if code >= 0 {
  234. c.Writer.WriteHeader(code)
  235. }
  236. c.Writer.Write(data)
  237. }
  238. // Writes the specified file into the body stream
  239. func (c *Context) File(filepath string) {
  240. http.ServeFile(c.Writer, c.Request, filepath)
  241. }