1// Copyright 2014 Manu Martinez-Almeida. 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 5package gin 6 7import ( 8 "errors" 9 "io" 10 "io/ioutil" 11 "math" 12 "mime/multipart" 13 "net" 14 "net/http" 15 "net/url" 16 "os" 17 "strings" 18 "time" 19 20 "github.com/gin-contrib/sse" 21 "github.com/gin-gonic/gin/binding" 22 "github.com/gin-gonic/gin/render" 23) 24 25// Content-Type MIME of the most common data formats. 26const ( 27 MIMEJSON = binding.MIMEJSON 28 MIMEHTML = binding.MIMEHTML 29 MIMEXML = binding.MIMEXML 30 MIMEXML2 = binding.MIMEXML2 31 MIMEPlain = binding.MIMEPlain 32 MIMEPOSTForm = binding.MIMEPOSTForm 33 MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm 34 BodyBytesKey = "_gin-gonic/gin/bodybyteskey" 35) 36 37const abortIndex int8 = math.MaxInt8 / 2 38 39// Context is the most important part of gin. It allows us to pass variables between middleware, 40// manage the flow, validate the JSON of a request and render a JSON response for example. 41type Context struct { 42 writermem responseWriter 43 Request *http.Request 44 Writer ResponseWriter 45 46 Params Params 47 handlers HandlersChain 48 index int8 49 50 engine *Engine 51 52 // Keys is a key/value pair exclusively for the context of each request. 53 Keys map[string]interface{} 54 55 // Errors is a list of errors attached to all the handlers/middlewares who used this context. 56 Errors errorMsgs 57 58 // Accepted defines a list of manually accepted formats for content negotiation. 59 Accepted []string 60} 61 62/************************************/ 63/********** CONTEXT CREATION ********/ 64/************************************/ 65 66func (c *Context) reset() { 67 c.Writer = &c.writermem 68 c.Params = c.Params[0:0] 69 c.handlers = nil 70 c.index = -1 71 c.Keys = nil 72 c.Errors = c.Errors[0:0] 73 c.Accepted = nil 74} 75 76// Copy returns a copy of the current context that can be safely used outside the request's scope. 77// This has to be used when the context has to be passed to a goroutine. 78func (c *Context) Copy() *Context { 79 var cp = *c 80 cp.writermem.ResponseWriter = nil 81 cp.Writer = &cp.writermem 82 cp.index = abortIndex 83 cp.handlers = nil 84 return &cp 85} 86 87// HandlerName returns the main handler's name. For example if the handler is "handleGetUsers()", 88// this function will return "main.handleGetUsers". 89func (c *Context) HandlerName() string { 90 return nameOfFunction(c.handlers.Last()) 91} 92 93// Handler returns the main handler. 94func (c *Context) Handler() HandlerFunc { 95 return c.handlers.Last() 96} 97 98/************************************/ 99/*********** FLOW CONTROL ***********/ 100/************************************/ 101 102// Next should be used only inside middleware. 103// It executes the pending handlers in the chain inside the calling handler. 104// See example in GitHub. 105func (c *Context) Next() { 106 c.index++ 107 for s := int8(len(c.handlers)); c.index < s; c.index++ { 108 c.handlers[c.index](c) 109 } 110} 111 112// IsAborted returns true if the current context was aborted. 113func (c *Context) IsAborted() bool { 114 return c.index >= abortIndex 115} 116 117// Abort prevents pending handlers from being called. Note that this will not stop the current handler. 118// Let's say you have an authorization middleware that validates that the current request is authorized. 119// If the authorization fails (ex: the password does not match), call Abort to ensure the remaining handlers 120// for this request are not called. 121func (c *Context) Abort() { 122 c.index = abortIndex 123} 124 125// AbortWithStatus calls `Abort()` and writes the headers with the specified status code. 126// For example, a failed attempt to authenticate a request could use: context.AbortWithStatus(401). 127func (c *Context) AbortWithStatus(code int) { 128 c.Status(code) 129 c.Writer.WriteHeaderNow() 130 c.Abort() 131} 132 133// AbortWithStatusJSON calls `Abort()` and then `JSON` internally. 134// This method stops the chain, writes the status code and return a JSON body. 135// It also sets the Content-Type as "application/json". 136func (c *Context) AbortWithStatusJSON(code int, jsonObj interface{}) { 137 c.Abort() 138 c.JSON(code, jsonObj) 139} 140 141// AbortWithError calls `AbortWithStatus()` and `Error()` internally. 142// This method stops the chain, writes the status code and pushes the specified error to `c.Errors`. 143// See Context.Error() for more details. 144func (c *Context) AbortWithError(code int, err error) *Error { 145 c.AbortWithStatus(code) 146 return c.Error(err) 147} 148 149/************************************/ 150/********* ERROR MANAGEMENT *********/ 151/************************************/ 152 153// Error attaches an error to the current context. The error is pushed to a list of errors. 154// It's a good idea to call Error for each error that occurred during the resolution of a request. 155// A middleware can be used to collect all the errors and push them to a database together, 156// print a log, or append it in the HTTP response. 157// Error will panic if err is nil. 158func (c *Context) Error(err error) *Error { 159 if err == nil { 160 panic("err is nil") 161 } 162 163 parsedError, ok := err.(*Error) 164 if !ok { 165 parsedError = &Error{ 166 Err: err, 167 Type: ErrorTypePrivate, 168 } 169 } 170 171 c.Errors = append(c.Errors, parsedError) 172 return parsedError 173} 174 175/************************************/ 176/******** METADATA MANAGEMENT********/ 177/************************************/ 178 179// Set is used to store a new key/value pair exclusively for this context. 180// It also lazy initializes c.Keys if it was not used previously. 181func (c *Context) Set(key string, value interface{}) { 182 if c.Keys == nil { 183 c.Keys = make(map[string]interface{}) 184 } 185 c.Keys[key] = value 186} 187 188// Get returns the value for the given key, ie: (value, true). 189// If the value does not exists it returns (nil, false) 190func (c *Context) Get(key string) (value interface{}, exists bool) { 191 value, exists = c.Keys[key] 192 return 193} 194 195// MustGet returns the value for the given key if it exists, otherwise it panics. 196func (c *Context) MustGet(key string) interface{} { 197 if value, exists := c.Get(key); exists { 198 return value 199 } 200 panic("Key \"" + key + "\" does not exist") 201} 202 203// GetString returns the value associated with the key as a string. 204func (c *Context) GetString(key string) (s string) { 205 if val, ok := c.Get(key); ok && val != nil { 206 s, _ = val.(string) 207 } 208 return 209} 210 211// GetBool returns the value associated with the key as a boolean. 212func (c *Context) GetBool(key string) (b bool) { 213 if val, ok := c.Get(key); ok && val != nil { 214 b, _ = val.(bool) 215 } 216 return 217} 218 219// GetInt returns the value associated with the key as an integer. 220func (c *Context) GetInt(key string) (i int) { 221 if val, ok := c.Get(key); ok && val != nil { 222 i, _ = val.(int) 223 } 224 return 225} 226 227// GetInt64 returns the value associated with the key as an integer. 228func (c *Context) GetInt64(key string) (i64 int64) { 229 if val, ok := c.Get(key); ok && val != nil { 230 i64, _ = val.(int64) 231 } 232 return 233} 234 235// GetFloat64 returns the value associated with the key as a float64. 236func (c *Context) GetFloat64(key string) (f64 float64) { 237 if val, ok := c.Get(key); ok && val != nil { 238 f64, _ = val.(float64) 239 } 240 return 241} 242 243// GetTime returns the value associated with the key as time. 244func (c *Context) GetTime(key string) (t time.Time) { 245 if val, ok := c.Get(key); ok && val != nil { 246 t, _ = val.(time.Time) 247 } 248 return 249} 250 251// GetDuration returns the value associated with the key as a duration. 252func (c *Context) GetDuration(key string) (d time.Duration) { 253 if val, ok := c.Get(key); ok && val != nil { 254 d, _ = val.(time.Duration) 255 } 256 return 257} 258 259// GetStringSlice returns the value associated with the key as a slice of strings. 260func (c *Context) GetStringSlice(key string) (ss []string) { 261 if val, ok := c.Get(key); ok && val != nil { 262 ss, _ = val.([]string) 263 } 264 return 265} 266 267// GetStringMap returns the value associated with the key as a map of interfaces. 268func (c *Context) GetStringMap(key string) (sm map[string]interface{}) { 269 if val, ok := c.Get(key); ok && val != nil { 270 sm, _ = val.(map[string]interface{}) 271 } 272 return 273} 274 275// GetStringMapString returns the value associated with the key as a map of strings. 276func (c *Context) GetStringMapString(key string) (sms map[string]string) { 277 if val, ok := c.Get(key); ok && val != nil { 278 sms, _ = val.(map[string]string) 279 } 280 return 281} 282 283// GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings. 284func (c *Context) GetStringMapStringSlice(key string) (smss map[string][]string) { 285 if val, ok := c.Get(key); ok && val != nil { 286 smss, _ = val.(map[string][]string) 287 } 288 return 289} 290 291/************************************/ 292/************ INPUT DATA ************/ 293/************************************/ 294 295// Param returns the value of the URL param. 296// It is a shortcut for c.Params.ByName(key) 297// router.GET("/user/:id", func(c *gin.Context) { 298// // a GET request to /user/john 299// id := c.Param("id") // id == "john" 300// }) 301func (c *Context) Param(key string) string { 302 return c.Params.ByName(key) 303} 304 305// Query returns the keyed url query value if it exists, 306// otherwise it returns an empty string `("")`. 307// It is shortcut for `c.Request.URL.Query().Get(key)` 308// GET /path?id=1234&name=Manu&value= 309// c.Query("id") == "1234" 310// c.Query("name") == "Manu" 311// c.Query("value") == "" 312// c.Query("wtf") == "" 313func (c *Context) Query(key string) string { 314 value, _ := c.GetQuery(key) 315 return value 316} 317 318// DefaultQuery returns the keyed url query value if it exists, 319// otherwise it returns the specified defaultValue string. 320// See: Query() and GetQuery() for further information. 321// GET /?name=Manu&lastname= 322// c.DefaultQuery("name", "unknown") == "Manu" 323// c.DefaultQuery("id", "none") == "none" 324// c.DefaultQuery("lastname", "none") == "" 325func (c *Context) DefaultQuery(key, defaultValue string) string { 326 if value, ok := c.GetQuery(key); ok { 327 return value 328 } 329 return defaultValue 330} 331 332// GetQuery is like Query(), it returns the keyed url query value 333// if it exists `(value, true)` (even when the value is an empty string), 334// otherwise it returns `("", false)`. 335// It is shortcut for `c.Request.URL.Query().Get(key)` 336// GET /?name=Manu&lastname= 337// ("Manu", true) == c.GetQuery("name") 338// ("", false) == c.GetQuery("id") 339// ("", true) == c.GetQuery("lastname") 340func (c *Context) GetQuery(key string) (string, bool) { 341 if values, ok := c.GetQueryArray(key); ok { 342 return values[0], ok 343 } 344 return "", false 345} 346 347// QueryArray returns a slice of strings for a given query key. 348// The length of the slice depends on the number of params with the given key. 349func (c *Context) QueryArray(key string) []string { 350 values, _ := c.GetQueryArray(key) 351 return values 352} 353 354// GetQueryArray returns a slice of strings for a given query key, plus 355// a boolean value whether at least one value exists for the given key. 356func (c *Context) GetQueryArray(key string) ([]string, bool) { 357 if values, ok := c.Request.URL.Query()[key]; ok && len(values) > 0 { 358 return values, true 359 } 360 return []string{}, false 361} 362 363// QueryMap returns a map for a given query key. 364func (c *Context) QueryMap(key string) map[string]string { 365 dicts, _ := c.GetQueryMap(key) 366 return dicts 367} 368 369// GetQueryMap returns a map for a given query key, plus a boolean value 370// whether at least one value exists for the given key. 371func (c *Context) GetQueryMap(key string) (map[string]string, bool) { 372 return c.get(c.Request.URL.Query(), key) 373} 374 375// PostForm returns the specified key from a POST urlencoded form or multipart form 376// when it exists, otherwise it returns an empty string `("")`. 377func (c *Context) PostForm(key string) string { 378 value, _ := c.GetPostForm(key) 379 return value 380} 381 382// DefaultPostForm returns the specified key from a POST urlencoded form or multipart form 383// when it exists, otherwise it returns the specified defaultValue string. 384// See: PostForm() and GetPostForm() for further information. 385func (c *Context) DefaultPostForm(key, defaultValue string) string { 386 if value, ok := c.GetPostForm(key); ok { 387 return value 388 } 389 return defaultValue 390} 391 392// GetPostForm is like PostForm(key). It returns the specified key from a POST urlencoded 393// form or multipart form when it exists `(value, true)` (even when the value is an empty string), 394// otherwise it returns ("", false). 395// For example, during a PATCH request to update the user's email: 396// email=mail@example.com --> ("mail@example.com", true) := GetPostForm("email") // set email to "mail@example.com" 397// email= --> ("", true) := GetPostForm("email") // set email to "" 398// --> ("", false) := GetPostForm("email") // do nothing with email 399func (c *Context) GetPostForm(key string) (string, bool) { 400 if values, ok := c.GetPostFormArray(key); ok { 401 return values[0], ok 402 } 403 return "", false 404} 405 406// PostFormArray returns a slice of strings for a given form key. 407// The length of the slice depends on the number of params with the given key. 408func (c *Context) PostFormArray(key string) []string { 409 values, _ := c.GetPostFormArray(key) 410 return values 411} 412 413// GetPostFormArray returns a slice of strings for a given form key, plus 414// a boolean value whether at least one value exists for the given key. 415func (c *Context) GetPostFormArray(key string) ([]string, bool) { 416 req := c.Request 417 req.ParseForm() 418 req.ParseMultipartForm(c.engine.MaxMultipartMemory) 419 if values := req.PostForm[key]; len(values) > 0 { 420 return values, true 421 } 422 if req.MultipartForm != nil && req.MultipartForm.File != nil { 423 if values := req.MultipartForm.Value[key]; len(values) > 0 { 424 return values, true 425 } 426 } 427 return []string{}, false 428} 429 430// PostFormMap returns a map for a given form key. 431func (c *Context) PostFormMap(key string) map[string]string { 432 dicts, _ := c.GetPostFormMap(key) 433 return dicts 434} 435 436// GetPostFormMap returns a map for a given form key, plus a boolean value 437// whether at least one value exists for the given key. 438func (c *Context) GetPostFormMap(key string) (map[string]string, bool) { 439 req := c.Request 440 req.ParseForm() 441 req.ParseMultipartForm(c.engine.MaxMultipartMemory) 442 dicts, exist := c.get(req.PostForm, key) 443 444 if !exist && req.MultipartForm != nil && req.MultipartForm.File != nil { 445 dicts, exist = c.get(req.MultipartForm.Value, key) 446 } 447 448 return dicts, exist 449} 450 451// get is an internal method and returns a map which satisfy conditions. 452func (c *Context) get(m map[string][]string, key string) (map[string]string, bool) { 453 dicts := make(map[string]string) 454 exist := false 455 for k, v := range m { 456 if i := strings.IndexByte(k, '['); i >= 1 && k[0:i] == key { 457 if j := strings.IndexByte(k[i+1:], ']'); j >= 1 { 458 exist = true 459 dicts[k[i+1:][:j]] = v[0] 460 } 461 } 462 } 463 return dicts, exist 464} 465 466// FormFile returns the first file for the provided form key. 467func (c *Context) FormFile(name string) (*multipart.FileHeader, error) { 468 _, fh, err := c.Request.FormFile(name) 469 return fh, err 470} 471 472// MultipartForm is the parsed multipart form, including file uploads. 473func (c *Context) MultipartForm() (*multipart.Form, error) { 474 err := c.Request.ParseMultipartForm(c.engine.MaxMultipartMemory) 475 return c.Request.MultipartForm, err 476} 477 478// SaveUploadedFile uploads the form file to specific dst. 479func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error { 480 src, err := file.Open() 481 if err != nil { 482 return err 483 } 484 defer src.Close() 485 486 out, err := os.Create(dst) 487 if err != nil { 488 return err 489 } 490 defer out.Close() 491 492 io.Copy(out, src) 493 return nil 494} 495 496// Bind checks the Content-Type to select a binding engine automatically, 497// Depending the "Content-Type" header different bindings are used: 498// "application/json" --> JSON binding 499// "application/xml" --> XML binding 500// otherwise --> returns an error. 501// It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input. 502// It decodes the json payload into the struct specified as a pointer. 503// It writes a 400 error and sets Content-Type header "text/plain" in the response if input is not valid. 504func (c *Context) Bind(obj interface{}) error { 505 b := binding.Default(c.Request.Method, c.ContentType()) 506 return c.MustBindWith(obj, b) 507} 508 509// BindJSON is a shortcut for c.MustBindWith(obj, binding.JSON). 510func (c *Context) BindJSON(obj interface{}) error { 511 return c.MustBindWith(obj, binding.JSON) 512} 513 514// BindQuery is a shortcut for c.MustBindWith(obj, binding.Query). 515func (c *Context) BindQuery(obj interface{}) error { 516 return c.MustBindWith(obj, binding.Query) 517} 518 519// MustBindWith binds the passed struct pointer using the specified binding engine. 520// It will abort the request with HTTP 400 if any error ocurrs. 521// See the binding package. 522func (c *Context) MustBindWith(obj interface{}, b binding.Binding) (err error) { 523 if err = c.ShouldBindWith(obj, b); err != nil { 524 c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) 525 } 526 527 return 528} 529 530// ShouldBind checks the Content-Type to select a binding engine automatically, 531// Depending the "Content-Type" header different bindings are used: 532// "application/json" --> JSON binding 533// "application/xml" --> XML binding 534// otherwise --> returns an error 535// It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input. 536// It decodes the json payload into the struct specified as a pointer. 537// Like c.Bind() but this method does not set the response status code to 400 and abort if the json is not valid. 538func (c *Context) ShouldBind(obj interface{}) error { 539 b := binding.Default(c.Request.Method, c.ContentType()) 540 return c.ShouldBindWith(obj, b) 541} 542 543// ShouldBindJSON is a shortcut for c.ShouldBindWith(obj, binding.JSON). 544func (c *Context) ShouldBindJSON(obj interface{}) error { 545 return c.ShouldBindWith(obj, binding.JSON) 546} 547 548// ShouldBindQuery is a shortcut for c.ShouldBindWith(obj, binding.Query). 549func (c *Context) ShouldBindQuery(obj interface{}) error { 550 return c.ShouldBindWith(obj, binding.Query) 551} 552 553// ShouldBindWith binds the passed struct pointer using the specified binding engine. 554// See the binding package. 555func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error { 556 return b.Bind(c.Request, obj) 557} 558 559// ShouldBindBodyWith is similar with ShouldBindWith, but it stores the request 560// body into the context, and reuse when it is called again. 561// 562// NOTE: This method reads the body before binding. So you should use 563// ShouldBindWith for better performance if you need to call only once. 564func (c *Context) ShouldBindBodyWith( 565 obj interface{}, bb binding.BindingBody, 566) (err error) { 567 var body []byte 568 if cb, ok := c.Get(BodyBytesKey); ok { 569 if cbb, ok := cb.([]byte); ok { 570 body = cbb 571 } 572 } 573 if body == nil { 574 body, err = ioutil.ReadAll(c.Request.Body) 575 if err != nil { 576 return err 577 } 578 c.Set(BodyBytesKey, body) 579 } 580 return bb.BindBody(body, obj) 581} 582 583// ClientIP implements a best effort algorithm to return the real client IP, it parses 584// X-Real-IP and X-Forwarded-For in order to work properly with reverse-proxies such us: nginx or haproxy. 585// Use X-Forwarded-For before X-Real-Ip as nginx uses X-Real-Ip with the proxy's IP. 586func (c *Context) ClientIP() string { 587 if c.engine.ForwardedByClientIP { 588 clientIP := c.requestHeader("X-Forwarded-For") 589 clientIP = strings.TrimSpace(strings.Split(clientIP, ",")[0]) 590 if clientIP == "" { 591 clientIP = strings.TrimSpace(c.requestHeader("X-Real-Ip")) 592 } 593 if clientIP != "" { 594 return clientIP 595 } 596 } 597 598 if c.engine.AppEngine { 599 if addr := c.requestHeader("X-Appengine-Remote-Addr"); addr != "" { 600 return addr 601 } 602 } 603 604 if ip, _, err := net.SplitHostPort(strings.TrimSpace(c.Request.RemoteAddr)); err == nil { 605 return ip 606 } 607 608 return "" 609} 610 611// ContentType returns the Content-Type header of the request. 612func (c *Context) ContentType() string { 613 return filterFlags(c.requestHeader("Content-Type")) 614} 615 616// IsWebsocket returns true if the request headers indicate that a websocket 617// handshake is being initiated by the client. 618func (c *Context) IsWebsocket() bool { 619 if strings.Contains(strings.ToLower(c.requestHeader("Connection")), "upgrade") && 620 strings.ToLower(c.requestHeader("Upgrade")) == "websocket" { 621 return true 622 } 623 return false 624} 625 626func (c *Context) requestHeader(key string) string { 627 return c.Request.Header.Get(key) 628} 629 630/************************************/ 631/******** RESPONSE RENDERING ********/ 632/************************************/ 633 634// bodyAllowedForStatus is a copy of http.bodyAllowedForStatus non-exported function. 635func bodyAllowedForStatus(status int) bool { 636 switch { 637 case status >= 100 && status <= 199: 638 return false 639 case status == http.StatusNoContent: 640 return false 641 case status == http.StatusNotModified: 642 return false 643 } 644 return true 645} 646 647// Status sets the HTTP response code. 648func (c *Context) Status(code int) { 649 c.writermem.WriteHeader(code) 650} 651 652// Header is a intelligent shortcut for c.Writer.Header().Set(key, value). 653// It writes a header in the response. 654// If value == "", this method removes the header `c.Writer.Header().Del(key)` 655func (c *Context) Header(key, value string) { 656 if value == "" { 657 c.Writer.Header().Del(key) 658 } else { 659 c.Writer.Header().Set(key, value) 660 } 661} 662 663// GetHeader returns value from request headers. 664func (c *Context) GetHeader(key string) string { 665 return c.requestHeader(key) 666} 667 668// GetRawData return stream data. 669func (c *Context) GetRawData() ([]byte, error) { 670 return ioutil.ReadAll(c.Request.Body) 671} 672 673// SetCookie adds a Set-Cookie header to the ResponseWriter's headers. 674// The provided cookie must have a valid Name. Invalid cookies may be 675// silently dropped. 676func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) { 677 if path == "" { 678 path = "/" 679 } 680 http.SetCookie(c.Writer, &http.Cookie{ 681 Name: name, 682 Value: url.QueryEscape(value), 683 MaxAge: maxAge, 684 Path: path, 685 Domain: domain, 686 Secure: secure, 687 HttpOnly: httpOnly, 688 }) 689} 690 691// Cookie returns the named cookie provided in the request or 692// ErrNoCookie if not found. And return the named cookie is unescaped. 693// If multiple cookies match the given name, only one cookie will 694// be returned. 695func (c *Context) Cookie(name string) (string, error) { 696 cookie, err := c.Request.Cookie(name) 697 if err != nil { 698 return "", err 699 } 700 val, _ := url.QueryUnescape(cookie.Value) 701 return val, nil 702} 703 704func (c *Context) Render(code int, r render.Render) { 705 c.Status(code) 706 707 if !bodyAllowedForStatus(code) { 708 r.WriteContentType(c.Writer) 709 c.Writer.WriteHeaderNow() 710 return 711 } 712 713 if err := r.Render(c.Writer); err != nil { 714 panic(err) 715 } 716} 717 718// HTML renders the HTTP template specified by its file name. 719// It also updates the HTTP code and sets the Content-Type as "text/html". 720// See http://golang.org/doc/articles/wiki/ 721func (c *Context) HTML(code int, name string, obj interface{}) { 722 instance := c.engine.HTMLRender.Instance(name, obj) 723 c.Render(code, instance) 724} 725 726// IndentedJSON serializes the given struct as pretty JSON (indented + endlines) into the response body. 727// It also sets the Content-Type as "application/json". 728// WARNING: we recommend to use this only for development purposes since printing pretty JSON is 729// more CPU and bandwidth consuming. Use Context.JSON() instead. 730func (c *Context) IndentedJSON(code int, obj interface{}) { 731 c.Render(code, render.IndentedJSON{Data: obj}) 732} 733 734// SecureJSON serializes the given struct as Secure JSON into the response body. 735// Default prepends "while(1)," to response body if the given struct is array values. 736// It also sets the Content-Type as "application/json". 737func (c *Context) SecureJSON(code int, obj interface{}) { 738 c.Render(code, render.SecureJSON{Prefix: c.engine.secureJsonPrefix, Data: obj}) 739} 740 741// JSONP serializes the given struct as JSON into the response body. 742// It add padding to response body to request data from a server residing in a different domain than the client. 743// It also sets the Content-Type as "application/javascript". 744func (c *Context) JSONP(code int, obj interface{}) { 745 callback := c.DefaultQuery("callback", "") 746 if callback == "" { 747 c.Render(code, render.JSON{Data: obj}) 748 } else { 749 c.Render(code, render.JsonpJSON{Callback: callback, Data: obj}) 750 } 751} 752 753// JSON serializes the given struct as JSON into the response body. 754// It also sets the Content-Type as "application/json". 755func (c *Context) JSON(code int, obj interface{}) { 756 c.Render(code, render.JSON{Data: obj}) 757} 758 759// AsciiJSON serializes the given struct as JSON into the response body with unicode to ASCII string. 760// It also sets the Content-Type as "application/json". 761func (c *Context) AsciiJSON(code int, obj interface{}) { 762 c.Render(code, render.AsciiJSON{Data: obj}) 763} 764 765// XML serializes the given struct as XML into the response body. 766// It also sets the Content-Type as "application/xml". 767func (c *Context) XML(code int, obj interface{}) { 768 c.Render(code, render.XML{Data: obj}) 769} 770 771// YAML serializes the given struct as YAML into the response body. 772func (c *Context) YAML(code int, obj interface{}) { 773 c.Render(code, render.YAML{Data: obj}) 774} 775 776// String writes the given string into the response body. 777func (c *Context) String(code int, format string, values ...interface{}) { 778 c.Render(code, render.String{Format: format, Data: values}) 779} 780 781// Redirect returns a HTTP redirect to the specific location. 782func (c *Context) Redirect(code int, location string) { 783 c.Render(-1, render.Redirect{ 784 Code: code, 785 Location: location, 786 Request: c.Request, 787 }) 788} 789 790// Data writes some data into the body stream and updates the HTTP code. 791func (c *Context) Data(code int, contentType string, data []byte) { 792 c.Render(code, render.Data{ 793 ContentType: contentType, 794 Data: data, 795 }) 796} 797 798// DataFromReader writes the specified reader into the body stream and updates the HTTP code. 799func (c *Context) DataFromReader(code int, contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string) { 800 c.Render(code, render.Reader{ 801 Headers: extraHeaders, 802 ContentType: contentType, 803 ContentLength: contentLength, 804 Reader: reader, 805 }) 806} 807 808// File writes the specified file into the body stream in a efficient way. 809func (c *Context) File(filepath string) { 810 http.ServeFile(c.Writer, c.Request, filepath) 811} 812 813// SSEvent writes a Server-Sent Event into the body stream. 814func (c *Context) SSEvent(name string, message interface{}) { 815 c.Render(-1, sse.Event{ 816 Event: name, 817 Data: message, 818 }) 819} 820 821func (c *Context) Stream(step func(w io.Writer) bool) { 822 w := c.Writer 823 clientGone := w.CloseNotify() 824 for { 825 select { 826 case <-clientGone: 827 return 828 default: 829 keepOpen := step(w) 830 w.Flush() 831 if !keepOpen { 832 return 833 } 834 } 835 } 836} 837 838/************************************/ 839/******** CONTENT NEGOTIATION *******/ 840/************************************/ 841 842type Negotiate struct { 843 Offered []string 844 HTMLName string 845 HTMLData interface{} 846 JSONData interface{} 847 XMLData interface{} 848 Data interface{} 849} 850 851func (c *Context) Negotiate(code int, config Negotiate) { 852 switch c.NegotiateFormat(config.Offered...) { 853 case binding.MIMEJSON: 854 data := chooseData(config.JSONData, config.Data) 855 c.JSON(code, data) 856 857 case binding.MIMEHTML: 858 data := chooseData(config.HTMLData, config.Data) 859 c.HTML(code, config.HTMLName, data) 860 861 case binding.MIMEXML: 862 data := chooseData(config.XMLData, config.Data) 863 c.XML(code, data) 864 865 default: 866 c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server")) 867 } 868} 869 870func (c *Context) NegotiateFormat(offered ...string) string { 871 assert1(len(offered) > 0, "you must provide at least one offer") 872 873 if c.Accepted == nil { 874 c.Accepted = parseAccept(c.requestHeader("Accept")) 875 } 876 if len(c.Accepted) == 0 { 877 return offered[0] 878 } 879 for _, accepted := range c.Accepted { 880 for _, offert := range offered { 881 if accepted == offert { 882 return offert 883 } 884 } 885 } 886 return "" 887} 888 889func (c *Context) SetAccepted(formats ...string) { 890 c.Accepted = formats 891} 892 893/************************************/ 894/***** GOLANG.ORG/X/NET/CONTEXT *****/ 895/************************************/ 896 897// Deadline returns the time when work done on behalf of this context 898// should be canceled. Deadline returns ok==false when no deadline is 899// set. Successive calls to Deadline return the same results. 900func (c *Context) Deadline() (deadline time.Time, ok bool) { 901 return 902} 903 904// Done returns a channel that's closed when work done on behalf of this 905// context should be canceled. Done may return nil if this context can 906// never be canceled. Successive calls to Done return the same value. 907func (c *Context) Done() <-chan struct{} { 908 return nil 909} 910 911// Err returns a non-nil error value after Done is closed, 912// successive calls to Err return the same error. 913// If Done is not yet closed, Err returns nil. 914// If Done is closed, Err returns a non-nil error explaining why: 915// Canceled if the context was canceled 916// or DeadlineExceeded if the context's deadline passed. 917func (c *Context) Err() error { 918 return nil 919} 920 921// Value returns the value associated with this context for key, or nil 922// if no value is associated with key. Successive calls to Value with 923// the same key returns the same result. 924func (c *Context) Value(key interface{}) interface{} { 925 if key == 0 { 926 return c.Request 927 } 928 if keyAsString, ok := key.(string); ok { 929 val, _ := c.Get(keyAsString) 930 return val 931 } 932 return nil 933} 934