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