context.go (37984B)
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 5 package gin 6 7 import ( 8 "errors" 9 "io" 10 "log" 11 "math" 12 "mime/multipart" 13 "net" 14 "net/http" 15 "net/url" 16 "os" 17 "path/filepath" 18 "strings" 19 "sync" 20 "time" 21 22 "github.com/gin-contrib/sse" 23 "github.com/gin-gonic/gin/binding" 24 "github.com/gin-gonic/gin/render" 25 ) 26 27 // Content-Type MIME of the most common data formats. 28 const ( 29 MIMEJSON = binding.MIMEJSON 30 MIMEHTML = binding.MIMEHTML 31 MIMEXML = binding.MIMEXML 32 MIMEXML2 = binding.MIMEXML2 33 MIMEPlain = binding.MIMEPlain 34 MIMEPOSTForm = binding.MIMEPOSTForm 35 MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm 36 MIMEYAML = binding.MIMEYAML 37 MIMETOML = binding.MIMETOML 38 ) 39 40 // BodyBytesKey indicates a default body bytes key. 41 const BodyBytesKey = "_gin-gonic/gin/bodybyteskey" 42 43 // ContextKey is the key that a Context returns itself for. 44 const ContextKey = "_gin-gonic/gin/contextkey" 45 46 // abortIndex represents a typical value used in abort functions. 47 const abortIndex int8 = math.MaxInt8 >> 1 48 49 // Context is the most important part of gin. It allows us to pass variables between middleware, 50 // manage the flow, validate the JSON of a request and render a JSON response for example. 51 type Context struct { 52 writermem responseWriter 53 Request *http.Request 54 Writer ResponseWriter 55 56 Params Params 57 handlers HandlersChain 58 index int8 59 fullPath string 60 61 engine *Engine 62 params *Params 63 skippedNodes *[]skippedNode 64 65 // This mutex protects Keys map. 66 mu sync.RWMutex 67 68 // Keys is a key/value pair exclusively for the context of each request. 69 Keys map[string]any 70 71 // Errors is a list of errors attached to all the handlers/middlewares who used this context. 72 Errors errorMsgs 73 74 // Accepted defines a list of manually accepted formats for content negotiation. 75 Accepted []string 76 77 // queryCache caches the query result from c.Request.URL.Query(). 78 queryCache url.Values 79 80 // formCache caches c.Request.PostForm, which contains the parsed form data from POST, PATCH, 81 // or PUT body parameters. 82 formCache url.Values 83 84 // SameSite allows a server to define a cookie attribute making it impossible for 85 // the browser to send this cookie along with cross-site requests. 86 sameSite http.SameSite 87 } 88 89 /************************************/ 90 /********** CONTEXT CREATION ********/ 91 /************************************/ 92 93 func (c *Context) reset() { 94 c.Writer = &c.writermem 95 c.Params = c.Params[:0] 96 c.handlers = nil 97 c.index = -1 98 99 c.fullPath = "" 100 c.Keys = nil 101 c.Errors = c.Errors[:0] 102 c.Accepted = nil 103 c.queryCache = nil 104 c.formCache = nil 105 c.sameSite = 0 106 *c.params = (*c.params)[:0] 107 *c.skippedNodes = (*c.skippedNodes)[:0] 108 } 109 110 // Copy returns a copy of the current context that can be safely used outside the request's scope. 111 // This has to be used when the context has to be passed to a goroutine. 112 func (c *Context) Copy() *Context { 113 cp := Context{ 114 writermem: c.writermem, 115 Request: c.Request, 116 Params: c.Params, 117 engine: c.engine, 118 } 119 cp.writermem.ResponseWriter = nil 120 cp.Writer = &cp.writermem 121 cp.index = abortIndex 122 cp.handlers = nil 123 cp.Keys = map[string]any{} 124 for k, v := range c.Keys { 125 cp.Keys[k] = v 126 } 127 paramCopy := make([]Param, len(cp.Params)) 128 copy(paramCopy, cp.Params) 129 cp.Params = paramCopy 130 return &cp 131 } 132 133 // HandlerName returns the main handler's name. For example if the handler is "handleGetUsers()", 134 // this function will return "main.handleGetUsers". 135 func (c *Context) HandlerName() string { 136 return nameOfFunction(c.handlers.Last()) 137 } 138 139 // HandlerNames returns a list of all registered handlers for this context in descending order, 140 // following the semantics of HandlerName() 141 func (c *Context) HandlerNames() []string { 142 hn := make([]string, 0, len(c.handlers)) 143 for _, val := range c.handlers { 144 hn = append(hn, nameOfFunction(val)) 145 } 146 return hn 147 } 148 149 // Handler returns the main handler. 150 func (c *Context) Handler() HandlerFunc { 151 return c.handlers.Last() 152 } 153 154 // FullPath returns a matched route full path. For not found routes 155 // returns an empty string. 156 // 157 // router.GET("/user/:id", func(c *gin.Context) { 158 // c.FullPath() == "/user/:id" // true 159 // }) 160 func (c *Context) FullPath() string { 161 return c.fullPath 162 } 163 164 /************************************/ 165 /*********** FLOW CONTROL ***********/ 166 /************************************/ 167 168 // Next should be used only inside middleware. 169 // It executes the pending handlers in the chain inside the calling handler. 170 // See example in GitHub. 171 func (c *Context) Next() { 172 c.index++ 173 for c.index < int8(len(c.handlers)) { 174 c.handlers[c.index](c) 175 c.index++ 176 } 177 } 178 179 // IsAborted returns true if the current context was aborted. 180 func (c *Context) IsAborted() bool { 181 return c.index >= abortIndex 182 } 183 184 // Abort prevents pending handlers from being called. Note that this will not stop the current handler. 185 // Let's say you have an authorization middleware that validates that the current request is authorized. 186 // If the authorization fails (ex: the password does not match), call Abort to ensure the remaining handlers 187 // for this request are not called. 188 func (c *Context) Abort() { 189 c.index = abortIndex 190 } 191 192 // AbortWithStatus calls `Abort()` and writes the headers with the specified status code. 193 // For example, a failed attempt to authenticate a request could use: context.AbortWithStatus(401). 194 func (c *Context) AbortWithStatus(code int) { 195 c.Status(code) 196 c.Writer.WriteHeaderNow() 197 c.Abort() 198 } 199 200 // AbortWithStatusJSON calls `Abort()` and then `JSON` internally. 201 // This method stops the chain, writes the status code and return a JSON body. 202 // It also sets the Content-Type as "application/json". 203 func (c *Context) AbortWithStatusJSON(code int, jsonObj any) { 204 c.Abort() 205 c.JSON(code, jsonObj) 206 } 207 208 // AbortWithError calls `AbortWithStatus()` and `Error()` internally. 209 // This method stops the chain, writes the status code and pushes the specified error to `c.Errors`. 210 // See Context.Error() for more details. 211 func (c *Context) AbortWithError(code int, err error) *Error { 212 c.AbortWithStatus(code) 213 return c.Error(err) 214 } 215 216 /************************************/ 217 /********* ERROR MANAGEMENT *********/ 218 /************************************/ 219 220 // Error attaches an error to the current context. The error is pushed to a list of errors. 221 // It's a good idea to call Error for each error that occurred during the resolution of a request. 222 // A middleware can be used to collect all the errors and push them to a database together, 223 // print a log, or append it in the HTTP response. 224 // Error will panic if err is nil. 225 func (c *Context) Error(err error) *Error { 226 if err == nil { 227 panic("err is nil") 228 } 229 230 var parsedError *Error 231 ok := errors.As(err, &parsedError) 232 if !ok { 233 parsedError = &Error{ 234 Err: err, 235 Type: ErrorTypePrivate, 236 } 237 } 238 239 c.Errors = append(c.Errors, parsedError) 240 return parsedError 241 } 242 243 /************************************/ 244 /******** METADATA MANAGEMENT********/ 245 /************************************/ 246 247 // Set is used to store a new key/value pair exclusively for this context. 248 // It also lazy initializes c.Keys if it was not used previously. 249 func (c *Context) Set(key string, value any) { 250 c.mu.Lock() 251 defer c.mu.Unlock() 252 if c.Keys == nil { 253 c.Keys = make(map[string]any) 254 } 255 256 c.Keys[key] = value 257 } 258 259 // Get returns the value for the given key, ie: (value, true). 260 // If the value does not exist it returns (nil, false) 261 func (c *Context) Get(key string) (value any, exists bool) { 262 c.mu.RLock() 263 defer c.mu.RUnlock() 264 value, exists = c.Keys[key] 265 return 266 } 267 268 // MustGet returns the value for the given key if it exists, otherwise it panics. 269 func (c *Context) MustGet(key string) any { 270 if value, exists := c.Get(key); exists { 271 return value 272 } 273 panic("Key \"" + key + "\" does not exist") 274 } 275 276 // GetString returns the value associated with the key as a string. 277 func (c *Context) GetString(key string) (s string) { 278 if val, ok := c.Get(key); ok && val != nil { 279 s, _ = val.(string) 280 } 281 return 282 } 283 284 // GetBool returns the value associated with the key as a boolean. 285 func (c *Context) GetBool(key string) (b bool) { 286 if val, ok := c.Get(key); ok && val != nil { 287 b, _ = val.(bool) 288 } 289 return 290 } 291 292 // GetInt returns the value associated with the key as an integer. 293 func (c *Context) GetInt(key string) (i int) { 294 if val, ok := c.Get(key); ok && val != nil { 295 i, _ = val.(int) 296 } 297 return 298 } 299 300 // GetInt64 returns the value associated with the key as an integer. 301 func (c *Context) GetInt64(key string) (i64 int64) { 302 if val, ok := c.Get(key); ok && val != nil { 303 i64, _ = val.(int64) 304 } 305 return 306 } 307 308 // GetUint returns the value associated with the key as an unsigned integer. 309 func (c *Context) GetUint(key string) (ui uint) { 310 if val, ok := c.Get(key); ok && val != nil { 311 ui, _ = val.(uint) 312 } 313 return 314 } 315 316 // GetUint64 returns the value associated with the key as an unsigned integer. 317 func (c *Context) GetUint64(key string) (ui64 uint64) { 318 if val, ok := c.Get(key); ok && val != nil { 319 ui64, _ = val.(uint64) 320 } 321 return 322 } 323 324 // GetFloat64 returns the value associated with the key as a float64. 325 func (c *Context) GetFloat64(key string) (f64 float64) { 326 if val, ok := c.Get(key); ok && val != nil { 327 f64, _ = val.(float64) 328 } 329 return 330 } 331 332 // GetTime returns the value associated with the key as time. 333 func (c *Context) GetTime(key string) (t time.Time) { 334 if val, ok := c.Get(key); ok && val != nil { 335 t, _ = val.(time.Time) 336 } 337 return 338 } 339 340 // GetDuration returns the value associated with the key as a duration. 341 func (c *Context) GetDuration(key string) (d time.Duration) { 342 if val, ok := c.Get(key); ok && val != nil { 343 d, _ = val.(time.Duration) 344 } 345 return 346 } 347 348 // GetStringSlice returns the value associated with the key as a slice of strings. 349 func (c *Context) GetStringSlice(key string) (ss []string) { 350 if val, ok := c.Get(key); ok && val != nil { 351 ss, _ = val.([]string) 352 } 353 return 354 } 355 356 // GetStringMap returns the value associated with the key as a map of interfaces. 357 func (c *Context) GetStringMap(key string) (sm map[string]any) { 358 if val, ok := c.Get(key); ok && val != nil { 359 sm, _ = val.(map[string]any) 360 } 361 return 362 } 363 364 // GetStringMapString returns the value associated with the key as a map of strings. 365 func (c *Context) GetStringMapString(key string) (sms map[string]string) { 366 if val, ok := c.Get(key); ok && val != nil { 367 sms, _ = val.(map[string]string) 368 } 369 return 370 } 371 372 // GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings. 373 func (c *Context) GetStringMapStringSlice(key string) (smss map[string][]string) { 374 if val, ok := c.Get(key); ok && val != nil { 375 smss, _ = val.(map[string][]string) 376 } 377 return 378 } 379 380 /************************************/ 381 /************ INPUT DATA ************/ 382 /************************************/ 383 384 // Param returns the value of the URL param. 385 // It is a shortcut for c.Params.ByName(key) 386 // 387 // router.GET("/user/:id", func(c *gin.Context) { 388 // // a GET request to /user/john 389 // id := c.Param("id") // id == "/john" 390 // // a GET request to /user/john/ 391 // id := c.Param("id") // id == "/john/" 392 // }) 393 func (c *Context) Param(key string) string { 394 return c.Params.ByName(key) 395 } 396 397 // AddParam adds param to context and 398 // replaces path param key with given value for e2e testing purposes 399 // Example Route: "/user/:id" 400 // AddParam("id", 1) 401 // Result: "/user/1" 402 func (c *Context) AddParam(key, value string) { 403 c.Params = append(c.Params, Param{Key: key, Value: value}) 404 } 405 406 // Query returns the keyed url query value if it exists, 407 // otherwise it returns an empty string `("")`. 408 // It is shortcut for `c.Request.URL.Query().Get(key)` 409 // 410 // GET /path?id=1234&name=Manu&value= 411 // c.Query("id") == "1234" 412 // c.Query("name") == "Manu" 413 // c.Query("value") == "" 414 // c.Query("wtf") == "" 415 func (c *Context) Query(key string) (value string) { 416 value, _ = c.GetQuery(key) 417 return 418 } 419 420 // DefaultQuery returns the keyed url query value if it exists, 421 // otherwise it returns the specified defaultValue string. 422 // See: Query() and GetQuery() for further information. 423 // 424 // GET /?name=Manu&lastname= 425 // c.DefaultQuery("name", "unknown") == "Manu" 426 // c.DefaultQuery("id", "none") == "none" 427 // c.DefaultQuery("lastname", "none") == "" 428 func (c *Context) DefaultQuery(key, defaultValue string) string { 429 if value, ok := c.GetQuery(key); ok { 430 return value 431 } 432 return defaultValue 433 } 434 435 // GetQuery is like Query(), it returns the keyed url query value 436 // if it exists `(value, true)` (even when the value is an empty string), 437 // otherwise it returns `("", false)`. 438 // It is shortcut for `c.Request.URL.Query().Get(key)` 439 // 440 // GET /?name=Manu&lastname= 441 // ("Manu", true) == c.GetQuery("name") 442 // ("", false) == c.GetQuery("id") 443 // ("", true) == c.GetQuery("lastname") 444 func (c *Context) GetQuery(key string) (string, bool) { 445 if values, ok := c.GetQueryArray(key); ok { 446 return values[0], ok 447 } 448 return "", false 449 } 450 451 // QueryArray returns a slice of strings for a given query key. 452 // The length of the slice depends on the number of params with the given key. 453 func (c *Context) QueryArray(key string) (values []string) { 454 values, _ = c.GetQueryArray(key) 455 return 456 } 457 458 func (c *Context) initQueryCache() { 459 if c.queryCache == nil { 460 if c.Request != nil { 461 c.queryCache = c.Request.URL.Query() 462 } else { 463 c.queryCache = url.Values{} 464 } 465 } 466 } 467 468 // GetQueryArray returns a slice of strings for a given query key, plus 469 // a boolean value whether at least one value exists for the given key. 470 func (c *Context) GetQueryArray(key string) (values []string, ok bool) { 471 c.initQueryCache() 472 values, ok = c.queryCache[key] 473 return 474 } 475 476 // QueryMap returns a map for a given query key. 477 func (c *Context) QueryMap(key string) (dicts map[string]string) { 478 dicts, _ = c.GetQueryMap(key) 479 return 480 } 481 482 // GetQueryMap returns a map for a given query key, plus a boolean value 483 // whether at least one value exists for the given key. 484 func (c *Context) GetQueryMap(key string) (map[string]string, bool) { 485 c.initQueryCache() 486 return c.get(c.queryCache, key) 487 } 488 489 // PostForm returns the specified key from a POST urlencoded form or multipart form 490 // when it exists, otherwise it returns an empty string `("")`. 491 func (c *Context) PostForm(key string) (value string) { 492 value, _ = c.GetPostForm(key) 493 return 494 } 495 496 // DefaultPostForm returns the specified key from a POST urlencoded form or multipart form 497 // when it exists, otherwise it returns the specified defaultValue string. 498 // See: PostForm() and GetPostForm() for further information. 499 func (c *Context) DefaultPostForm(key, defaultValue string) string { 500 if value, ok := c.GetPostForm(key); ok { 501 return value 502 } 503 return defaultValue 504 } 505 506 // GetPostForm is like PostForm(key). It returns the specified key from a POST urlencoded 507 // form or multipart form when it exists `(value, true)` (even when the value is an empty string), 508 // otherwise it returns ("", false). 509 // For example, during a PATCH request to update the user's email: 510 // 511 // email=mail@example.com --> ("mail@example.com", true) := GetPostForm("email") // set email to "mail@example.com" 512 // email= --> ("", true) := GetPostForm("email") // set email to "" 513 // --> ("", false) := GetPostForm("email") // do nothing with email 514 func (c *Context) GetPostForm(key string) (string, bool) { 515 if values, ok := c.GetPostFormArray(key); ok { 516 return values[0], ok 517 } 518 return "", false 519 } 520 521 // PostFormArray returns a slice of strings for a given form key. 522 // The length of the slice depends on the number of params with the given key. 523 func (c *Context) PostFormArray(key string) (values []string) { 524 values, _ = c.GetPostFormArray(key) 525 return 526 } 527 528 func (c *Context) initFormCache() { 529 if c.formCache == nil { 530 c.formCache = make(url.Values) 531 req := c.Request 532 if err := req.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil { 533 if !errors.Is(err, http.ErrNotMultipart) { 534 debugPrint("error on parse multipart form array: %v", err) 535 } 536 } 537 c.formCache = req.PostForm 538 } 539 } 540 541 // GetPostFormArray returns a slice of strings for a given form key, plus 542 // a boolean value whether at least one value exists for the given key. 543 func (c *Context) GetPostFormArray(key string) (values []string, ok bool) { 544 c.initFormCache() 545 values, ok = c.formCache[key] 546 return 547 } 548 549 // PostFormMap returns a map for a given form key. 550 func (c *Context) PostFormMap(key string) (dicts map[string]string) { 551 dicts, _ = c.GetPostFormMap(key) 552 return 553 } 554 555 // GetPostFormMap returns a map for a given form key, plus a boolean value 556 // whether at least one value exists for the given key. 557 func (c *Context) GetPostFormMap(key string) (map[string]string, bool) { 558 c.initFormCache() 559 return c.get(c.formCache, key) 560 } 561 562 // get is an internal method and returns a map which satisfies conditions. 563 func (c *Context) get(m map[string][]string, key string) (map[string]string, bool) { 564 dicts := make(map[string]string) 565 exist := false 566 for k, v := range m { 567 if i := strings.IndexByte(k, '['); i >= 1 && k[0:i] == key { 568 if j := strings.IndexByte(k[i+1:], ']'); j >= 1 { 569 exist = true 570 dicts[k[i+1:][:j]] = v[0] 571 } 572 } 573 } 574 return dicts, exist 575 } 576 577 // FormFile returns the first file for the provided form key. 578 func (c *Context) FormFile(name string) (*multipart.FileHeader, error) { 579 if c.Request.MultipartForm == nil { 580 if err := c.Request.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil { 581 return nil, err 582 } 583 } 584 f, fh, err := c.Request.FormFile(name) 585 if err != nil { 586 return nil, err 587 } 588 f.Close() 589 return fh, err 590 } 591 592 // MultipartForm is the parsed multipart form, including file uploads. 593 func (c *Context) MultipartForm() (*multipart.Form, error) { 594 err := c.Request.ParseMultipartForm(c.engine.MaxMultipartMemory) 595 return c.Request.MultipartForm, err 596 } 597 598 // SaveUploadedFile uploads the form file to specific dst. 599 func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error { 600 src, err := file.Open() 601 if err != nil { 602 return err 603 } 604 defer src.Close() 605 606 if err = os.MkdirAll(filepath.Dir(dst), 0750); err != nil { 607 return err 608 } 609 610 out, err := os.Create(dst) 611 if err != nil { 612 return err 613 } 614 defer out.Close() 615 616 _, err = io.Copy(out, src) 617 return err 618 } 619 620 // Bind checks the Method and Content-Type to select a binding engine automatically, 621 // Depending on the "Content-Type" header different bindings are used, for example: 622 // 623 // "application/json" --> JSON binding 624 // "application/xml" --> XML binding 625 // 626 // It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input. 627 // It decodes the json payload into the struct specified as a pointer. 628 // It writes a 400 error and sets Content-Type header "text/plain" in the response if input is not valid. 629 func (c *Context) Bind(obj any) error { 630 b := binding.Default(c.Request.Method, c.ContentType()) 631 return c.MustBindWith(obj, b) 632 } 633 634 // BindJSON is a shortcut for c.MustBindWith(obj, binding.JSON). 635 func (c *Context) BindJSON(obj any) error { 636 return c.MustBindWith(obj, binding.JSON) 637 } 638 639 // BindXML is a shortcut for c.MustBindWith(obj, binding.BindXML). 640 func (c *Context) BindXML(obj any) error { 641 return c.MustBindWith(obj, binding.XML) 642 } 643 644 // BindQuery is a shortcut for c.MustBindWith(obj, binding.Query). 645 func (c *Context) BindQuery(obj any) error { 646 return c.MustBindWith(obj, binding.Query) 647 } 648 649 // BindYAML is a shortcut for c.MustBindWith(obj, binding.YAML). 650 func (c *Context) BindYAML(obj any) error { 651 return c.MustBindWith(obj, binding.YAML) 652 } 653 654 // BindTOML is a shortcut for c.MustBindWith(obj, binding.TOML). 655 func (c *Context) BindTOML(obj any) error { 656 return c.MustBindWith(obj, binding.TOML) 657 } 658 659 // BindHeader is a shortcut for c.MustBindWith(obj, binding.Header). 660 func (c *Context) BindHeader(obj any) error { 661 return c.MustBindWith(obj, binding.Header) 662 } 663 664 // BindUri binds the passed struct pointer using binding.Uri. 665 // It will abort the request with HTTP 400 if any error occurs. 666 func (c *Context) BindUri(obj any) error { 667 if err := c.ShouldBindUri(obj); err != nil { 668 c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) //nolint: errcheck 669 return err 670 } 671 return nil 672 } 673 674 // MustBindWith binds the passed struct pointer using the specified binding engine. 675 // It will abort the request with HTTP 400 if any error occurs. 676 // See the binding package. 677 func (c *Context) MustBindWith(obj any, b binding.Binding) error { 678 if err := c.ShouldBindWith(obj, b); err != nil { 679 c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) //nolint: errcheck 680 return err 681 } 682 return nil 683 } 684 685 // ShouldBind checks the Method and Content-Type to select a binding engine automatically, 686 // Depending on the "Content-Type" header different bindings are used, for example: 687 // 688 // "application/json" --> JSON binding 689 // "application/xml" --> XML binding 690 // 691 // It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input. 692 // It decodes the json payload into the struct specified as a pointer. 693 // Like c.Bind() but this method does not set the response status code to 400 or abort if input is not valid. 694 func (c *Context) ShouldBind(obj any) error { 695 b := binding.Default(c.Request.Method, c.ContentType()) 696 return c.ShouldBindWith(obj, b) 697 } 698 699 // ShouldBindJSON is a shortcut for c.ShouldBindWith(obj, binding.JSON). 700 func (c *Context) ShouldBindJSON(obj any) error { 701 return c.ShouldBindWith(obj, binding.JSON) 702 } 703 704 // ShouldBindXML is a shortcut for c.ShouldBindWith(obj, binding.XML). 705 func (c *Context) ShouldBindXML(obj any) error { 706 return c.ShouldBindWith(obj, binding.XML) 707 } 708 709 // ShouldBindQuery is a shortcut for c.ShouldBindWith(obj, binding.Query). 710 func (c *Context) ShouldBindQuery(obj any) error { 711 return c.ShouldBindWith(obj, binding.Query) 712 } 713 714 // ShouldBindYAML is a shortcut for c.ShouldBindWith(obj, binding.YAML). 715 func (c *Context) ShouldBindYAML(obj any) error { 716 return c.ShouldBindWith(obj, binding.YAML) 717 } 718 719 // ShouldBindTOML is a shortcut for c.ShouldBindWith(obj, binding.TOML). 720 func (c *Context) ShouldBindTOML(obj any) error { 721 return c.ShouldBindWith(obj, binding.TOML) 722 } 723 724 // ShouldBindHeader is a shortcut for c.ShouldBindWith(obj, binding.Header). 725 func (c *Context) ShouldBindHeader(obj any) error { 726 return c.ShouldBindWith(obj, binding.Header) 727 } 728 729 // ShouldBindUri binds the passed struct pointer using the specified binding engine. 730 func (c *Context) ShouldBindUri(obj any) error { 731 m := make(map[string][]string) 732 for _, v := range c.Params { 733 m[v.Key] = []string{v.Value} 734 } 735 return binding.Uri.BindUri(m, obj) 736 } 737 738 // ShouldBindWith binds the passed struct pointer using the specified binding engine. 739 // See the binding package. 740 func (c *Context) ShouldBindWith(obj any, b binding.Binding) error { 741 return b.Bind(c.Request, obj) 742 } 743 744 // ShouldBindBodyWith is similar with ShouldBindWith, but it stores the request 745 // body into the context, and reuse when it is called again. 746 // 747 // NOTE: This method reads the body before binding. So you should use 748 // ShouldBindWith for better performance if you need to call only once. 749 func (c *Context) ShouldBindBodyWith(obj any, bb binding.BindingBody) (err error) { 750 var body []byte 751 if cb, ok := c.Get(BodyBytesKey); ok { 752 if cbb, ok := cb.([]byte); ok { 753 body = cbb 754 } 755 } 756 if body == nil { 757 body, err = io.ReadAll(c.Request.Body) 758 if err != nil { 759 return err 760 } 761 c.Set(BodyBytesKey, body) 762 } 763 return bb.BindBody(body, obj) 764 } 765 766 // ClientIP implements one best effort algorithm to return the real client IP. 767 // It calls c.RemoteIP() under the hood, to check if the remote IP is a trusted proxy or not. 768 // If it is it will then try to parse the headers defined in Engine.RemoteIPHeaders (defaulting to [X-Forwarded-For, X-Real-Ip]). 769 // If the headers are not syntactically valid OR the remote IP does not correspond to a trusted proxy, 770 // the remote IP (coming from Request.RemoteAddr) is returned. 771 func (c *Context) ClientIP() string { 772 // Check if we're running on a trusted platform, continue running backwards if error 773 if c.engine.TrustedPlatform != "" { 774 // Developers can define their own header of Trusted Platform or use predefined constants 775 if addr := c.requestHeader(c.engine.TrustedPlatform); addr != "" { 776 return addr 777 } 778 } 779 780 // Legacy "AppEngine" flag 781 if c.engine.AppEngine { 782 log.Println(`The AppEngine flag is going to be deprecated. Please check issues #2723 and #2739 and use 'TrustedPlatform: gin.PlatformGoogleAppEngine' instead.`) 783 if addr := c.requestHeader("X-Appengine-Remote-Addr"); addr != "" { 784 return addr 785 } 786 } 787 788 // It also checks if the remoteIP is a trusted proxy or not. 789 // In order to perform this validation, it will see if the IP is contained within at least one of the CIDR blocks 790 // defined by Engine.SetTrustedProxies() 791 remoteIP := net.ParseIP(c.RemoteIP()) 792 if remoteIP == nil { 793 return "" 794 } 795 trusted := c.engine.isTrustedProxy(remoteIP) 796 797 if trusted && c.engine.ForwardedByClientIP && c.engine.RemoteIPHeaders != nil { 798 for _, headerName := range c.engine.RemoteIPHeaders { 799 ip, valid := c.engine.validateHeader(c.requestHeader(headerName)) 800 if valid { 801 return ip 802 } 803 } 804 } 805 return remoteIP.String() 806 } 807 808 // RemoteIP parses the IP from Request.RemoteAddr, normalizes and returns the IP (without the port). 809 func (c *Context) RemoteIP() string { 810 ip, _, err := net.SplitHostPort(strings.TrimSpace(c.Request.RemoteAddr)) 811 if err != nil { 812 return "" 813 } 814 return ip 815 } 816 817 // ContentType returns the Content-Type header of the request. 818 func (c *Context) ContentType() string { 819 return filterFlags(c.requestHeader("Content-Type")) 820 } 821 822 // IsWebsocket returns true if the request headers indicate that a websocket 823 // handshake is being initiated by the client. 824 func (c *Context) IsWebsocket() bool { 825 if strings.Contains(strings.ToLower(c.requestHeader("Connection")), "upgrade") && 826 strings.EqualFold(c.requestHeader("Upgrade"), "websocket") { 827 return true 828 } 829 return false 830 } 831 832 func (c *Context) requestHeader(key string) string { 833 return c.Request.Header.Get(key) 834 } 835 836 /************************************/ 837 /******** RESPONSE RENDERING ********/ 838 /************************************/ 839 840 // bodyAllowedForStatus is a copy of http.bodyAllowedForStatus non-exported function. 841 func bodyAllowedForStatus(status int) bool { 842 switch { 843 case status >= 100 && status <= 199: 844 return false 845 case status == http.StatusNoContent: 846 return false 847 case status == http.StatusNotModified: 848 return false 849 } 850 return true 851 } 852 853 // Status sets the HTTP response code. 854 func (c *Context) Status(code int) { 855 c.Writer.WriteHeader(code) 856 } 857 858 // Header is an intelligent shortcut for c.Writer.Header().Set(key, value). 859 // It writes a header in the response. 860 // If value == "", this method removes the header `c.Writer.Header().Del(key)` 861 func (c *Context) Header(key, value string) { 862 if value == "" { 863 c.Writer.Header().Del(key) 864 return 865 } 866 c.Writer.Header().Set(key, value) 867 } 868 869 // GetHeader returns value from request headers. 870 func (c *Context) GetHeader(key string) string { 871 return c.requestHeader(key) 872 } 873 874 // GetRawData returns stream data. 875 func (c *Context) GetRawData() ([]byte, error) { 876 return io.ReadAll(c.Request.Body) 877 } 878 879 // SetSameSite with cookie 880 func (c *Context) SetSameSite(samesite http.SameSite) { 881 c.sameSite = samesite 882 } 883 884 // SetCookie adds a Set-Cookie header to the ResponseWriter's headers. 885 // The provided cookie must have a valid Name. Invalid cookies may be 886 // silently dropped. 887 func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) { 888 if path == "" { 889 path = "/" 890 } 891 http.SetCookie(c.Writer, &http.Cookie{ 892 Name: name, 893 Value: url.QueryEscape(value), 894 MaxAge: maxAge, 895 Path: path, 896 Domain: domain, 897 SameSite: c.sameSite, 898 Secure: secure, 899 HttpOnly: httpOnly, 900 }) 901 } 902 903 // Cookie returns the named cookie provided in the request or 904 // ErrNoCookie if not found. And return the named cookie is unescaped. 905 // If multiple cookies match the given name, only one cookie will 906 // be returned. 907 func (c *Context) Cookie(name string) (string, error) { 908 cookie, err := c.Request.Cookie(name) 909 if err != nil { 910 return "", err 911 } 912 val, _ := url.QueryUnescape(cookie.Value) 913 return val, nil 914 } 915 916 // Render writes the response headers and calls render.Render to render data. 917 func (c *Context) Render(code int, r render.Render) { 918 c.Status(code) 919 920 if !bodyAllowedForStatus(code) { 921 r.WriteContentType(c.Writer) 922 c.Writer.WriteHeaderNow() 923 return 924 } 925 926 if err := r.Render(c.Writer); err != nil { 927 // Pushing error to c.Errors 928 _ = c.Error(err) 929 c.Abort() 930 } 931 } 932 933 // HTML renders the HTTP template specified by its file name. 934 // It also updates the HTTP code and sets the Content-Type as "text/html". 935 // See http://golang.org/doc/articles/wiki/ 936 func (c *Context) HTML(code int, name string, obj any) { 937 instance := c.engine.HTMLRender.Instance(name, obj) 938 c.Render(code, instance) 939 } 940 941 // IndentedJSON serializes the given struct as pretty JSON (indented + endlines) into the response body. 942 // It also sets the Content-Type as "application/json". 943 // WARNING: we recommend using this only for development purposes since printing pretty JSON is 944 // more CPU and bandwidth consuming. Use Context.JSON() instead. 945 func (c *Context) IndentedJSON(code int, obj any) { 946 c.Render(code, render.IndentedJSON{Data: obj}) 947 } 948 949 // SecureJSON serializes the given struct as Secure JSON into the response body. 950 // Default prepends "while(1)," to response body if the given struct is array values. 951 // It also sets the Content-Type as "application/json". 952 func (c *Context) SecureJSON(code int, obj any) { 953 c.Render(code, render.SecureJSON{Prefix: c.engine.secureJSONPrefix, Data: obj}) 954 } 955 956 // JSONP serializes the given struct as JSON into the response body. 957 // It adds padding to response body to request data from a server residing in a different domain than the client. 958 // It also sets the Content-Type as "application/javascript". 959 func (c *Context) JSONP(code int, obj any) { 960 callback := c.DefaultQuery("callback", "") 961 if callback == "" { 962 c.Render(code, render.JSON{Data: obj}) 963 return 964 } 965 c.Render(code, render.JsonpJSON{Callback: callback, Data: obj}) 966 } 967 968 // JSON serializes the given struct as JSON into the response body. 969 // It also sets the Content-Type as "application/json". 970 func (c *Context) JSON(code int, obj any) { 971 c.Render(code, render.JSON{Data: obj}) 972 } 973 974 // AsciiJSON serializes the given struct as JSON into the response body with unicode to ASCII string. 975 // It also sets the Content-Type as "application/json". 976 func (c *Context) AsciiJSON(code int, obj any) { 977 c.Render(code, render.AsciiJSON{Data: obj}) 978 } 979 980 // PureJSON serializes the given struct as JSON into the response body. 981 // PureJSON, unlike JSON, does not replace special html characters with their unicode entities. 982 func (c *Context) PureJSON(code int, obj any) { 983 c.Render(code, render.PureJSON{Data: obj}) 984 } 985 986 // XML serializes the given struct as XML into the response body. 987 // It also sets the Content-Type as "application/xml". 988 func (c *Context) XML(code int, obj any) { 989 c.Render(code, render.XML{Data: obj}) 990 } 991 992 // YAML serializes the given struct as YAML into the response body. 993 func (c *Context) YAML(code int, obj any) { 994 c.Render(code, render.YAML{Data: obj}) 995 } 996 997 // TOML serializes the given struct as TOML into the response body. 998 func (c *Context) TOML(code int, obj any) { 999 c.Render(code, render.TOML{Data: obj}) 1000 } 1001 1002 // ProtoBuf serializes the given struct as ProtoBuf into the response body. 1003 func (c *Context) ProtoBuf(code int, obj any) { 1004 c.Render(code, render.ProtoBuf{Data: obj}) 1005 } 1006 1007 // String writes the given string into the response body. 1008 func (c *Context) String(code int, format string, values ...any) { 1009 c.Render(code, render.String{Format: format, Data: values}) 1010 } 1011 1012 // Redirect returns an HTTP redirect to the specific location. 1013 func (c *Context) Redirect(code int, location string) { 1014 c.Render(-1, render.Redirect{ 1015 Code: code, 1016 Location: location, 1017 Request: c.Request, 1018 }) 1019 } 1020 1021 // Data writes some data into the body stream and updates the HTTP code. 1022 func (c *Context) Data(code int, contentType string, data []byte) { 1023 c.Render(code, render.Data{ 1024 ContentType: contentType, 1025 Data: data, 1026 }) 1027 } 1028 1029 // DataFromReader writes the specified reader into the body stream and updates the HTTP code. 1030 func (c *Context) DataFromReader(code int, contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string) { 1031 c.Render(code, render.Reader{ 1032 Headers: extraHeaders, 1033 ContentType: contentType, 1034 ContentLength: contentLength, 1035 Reader: reader, 1036 }) 1037 } 1038 1039 // File writes the specified file into the body stream in an efficient way. 1040 func (c *Context) File(filepath string) { 1041 http.ServeFile(c.Writer, c.Request, filepath) 1042 } 1043 1044 // FileFromFS writes the specified file from http.FileSystem into the body stream in an efficient way. 1045 func (c *Context) FileFromFS(filepath string, fs http.FileSystem) { 1046 defer func(old string) { 1047 c.Request.URL.Path = old 1048 }(c.Request.URL.Path) 1049 1050 c.Request.URL.Path = filepath 1051 1052 http.FileServer(fs).ServeHTTP(c.Writer, c.Request) 1053 } 1054 1055 var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"") 1056 1057 func escapeQuotes(s string) string { 1058 return quoteEscaper.Replace(s) 1059 } 1060 1061 // FileAttachment writes the specified file into the body stream in an efficient way 1062 // On the client side, the file will typically be downloaded with the given filename 1063 func (c *Context) FileAttachment(filepath, filename string) { 1064 if isASCII(filename) { 1065 c.Writer.Header().Set("Content-Disposition", `attachment; filename="`+escapeQuotes(filename)+`"`) 1066 } else { 1067 c.Writer.Header().Set("Content-Disposition", `attachment; filename*=UTF-8''`+url.QueryEscape(filename)) 1068 } 1069 http.ServeFile(c.Writer, c.Request, filepath) 1070 } 1071 1072 // SSEvent writes a Server-Sent Event into the body stream. 1073 func (c *Context) SSEvent(name string, message any) { 1074 c.Render(-1, sse.Event{ 1075 Event: name, 1076 Data: message, 1077 }) 1078 } 1079 1080 // Stream sends a streaming response and returns a boolean 1081 // indicates "Is client disconnected in middle of stream" 1082 func (c *Context) Stream(step func(w io.Writer) bool) bool { 1083 w := c.Writer 1084 clientGone := w.CloseNotify() 1085 for { 1086 select { 1087 case <-clientGone: 1088 return true 1089 default: 1090 keepOpen := step(w) 1091 w.Flush() 1092 if !keepOpen { 1093 return false 1094 } 1095 } 1096 } 1097 } 1098 1099 /************************************/ 1100 /******** CONTENT NEGOTIATION *******/ 1101 /************************************/ 1102 1103 // Negotiate contains all negotiations data. 1104 type Negotiate struct { 1105 Offered []string 1106 HTMLName string 1107 HTMLData any 1108 JSONData any 1109 XMLData any 1110 YAMLData any 1111 Data any 1112 TOMLData any 1113 } 1114 1115 // Negotiate calls different Render according to acceptable Accept format. 1116 func (c *Context) Negotiate(code int, config Negotiate) { 1117 switch c.NegotiateFormat(config.Offered...) { 1118 case binding.MIMEJSON: 1119 data := chooseData(config.JSONData, config.Data) 1120 c.JSON(code, data) 1121 1122 case binding.MIMEHTML: 1123 data := chooseData(config.HTMLData, config.Data) 1124 c.HTML(code, config.HTMLName, data) 1125 1126 case binding.MIMEXML: 1127 data := chooseData(config.XMLData, config.Data) 1128 c.XML(code, data) 1129 1130 case binding.MIMEYAML: 1131 data := chooseData(config.YAMLData, config.Data) 1132 c.YAML(code, data) 1133 1134 case binding.MIMETOML: 1135 data := chooseData(config.TOMLData, config.Data) 1136 c.TOML(code, data) 1137 1138 default: 1139 c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server")) //nolint: errcheck 1140 } 1141 } 1142 1143 // NegotiateFormat returns an acceptable Accept format. 1144 func (c *Context) NegotiateFormat(offered ...string) string { 1145 assert1(len(offered) > 0, "you must provide at least one offer") 1146 1147 if c.Accepted == nil { 1148 c.Accepted = parseAccept(c.requestHeader("Accept")) 1149 } 1150 if len(c.Accepted) == 0 { 1151 return offered[0] 1152 } 1153 for _, accepted := range c.Accepted { 1154 for _, offer := range offered { 1155 // According to RFC 2616 and RFC 2396, non-ASCII characters are not allowed in headers, 1156 // therefore we can just iterate over the string without casting it into []rune 1157 i := 0 1158 for ; i < len(accepted) && i < len(offer); i++ { 1159 if accepted[i] == '*' || offer[i] == '*' { 1160 return offer 1161 } 1162 if accepted[i] != offer[i] { 1163 break 1164 } 1165 } 1166 if i == len(accepted) { 1167 return offer 1168 } 1169 } 1170 } 1171 return "" 1172 } 1173 1174 // SetAccepted sets Accept header data. 1175 func (c *Context) SetAccepted(formats ...string) { 1176 c.Accepted = formats 1177 } 1178 1179 /************************************/ 1180 /***** GOLANG.ORG/X/NET/CONTEXT *****/ 1181 /************************************/ 1182 1183 // hasRequestContext returns whether c.Request has Context and fallback. 1184 func (c *Context) hasRequestContext() bool { 1185 hasFallback := c.engine != nil && c.engine.ContextWithFallback 1186 hasRequestContext := c.Request != nil && c.Request.Context() != nil 1187 return hasFallback && hasRequestContext 1188 } 1189 1190 // Deadline returns that there is no deadline (ok==false) when c.Request has no Context. 1191 func (c *Context) Deadline() (deadline time.Time, ok bool) { 1192 if !c.hasRequestContext() { 1193 return 1194 } 1195 return c.Request.Context().Deadline() 1196 } 1197 1198 // Done returns nil (chan which will wait forever) when c.Request has no Context. 1199 func (c *Context) Done() <-chan struct{} { 1200 if !c.hasRequestContext() { 1201 return nil 1202 } 1203 return c.Request.Context().Done() 1204 } 1205 1206 // Err returns nil when c.Request has no Context. 1207 func (c *Context) Err() error { 1208 if !c.hasRequestContext() { 1209 return nil 1210 } 1211 return c.Request.Context().Err() 1212 } 1213 1214 // Value returns the value associated with this context for key, or nil 1215 // if no value is associated with key. Successive calls to Value with 1216 // the same key returns the same result. 1217 func (c *Context) Value(key any) any { 1218 if key == 0 { 1219 return c.Request 1220 } 1221 if key == ContextKey { 1222 return c 1223 } 1224 if keyAsString, ok := key.(string); ok { 1225 if val, exists := c.Get(keyAsString); exists { 1226 return val 1227 } 1228 } 1229 if !c.hasRequestContext() { 1230 return nil 1231 } 1232 return c.Request.Context().Value(key) 1233 }