go.sdls.io/sin@v0.0.9/pkg/sin/context.go (about) 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 sin 6 7 import ( 8 "io" 9 "math" 10 "mime/multipart" 11 "net/http" 12 "net/url" 13 "strings" 14 "sync" 15 "time" 16 17 "go.sdls.io/sin/pkg/render" 18 ) 19 20 const abortIndex int8 = math.MaxInt8 / 2 21 22 // Context is the most important part of gin. It allows us to pass variables between middleware, 23 // manage the flow, validate the JSON of a request and render a JSON response for example. 24 type Context struct { 25 Writer ResponseWriter 26 engine *Engine 27 Request *http.Request 28 queryCache url.Values 29 Keys map[ // queryCache use url.ParseQuery cached the param query result from c.Request.URL.Query() 30 // Keys is a key/value pair exclusively for the context of each request. 31 string]interface{} 32 params *Params 33 fullPath string 34 writermem responseWriter 35 handlers HandlersChain 36 Errors errorMsgs 37 38 Params Params 39 sameSite http.SameSite 40 mu sync.RWMutex 41 index int8 // SameSite allows a server to define a cookie attribute making it impossible for 42 // the browser to send this cookie along with cross-site requests. 43 // This mutex protect Keys map 44 } 45 46 /************************************/ 47 /********** CONTEXT CREATION ********/ 48 /************************************/ 49 50 func (c *Context) reset() { 51 c.Writer = &c.writermem 52 c.Params = c.Params[0:0] 53 c.handlers = nil 54 c.index = -1 55 56 c.fullPath = "" 57 c.Keys = nil 58 c.Errors = c.Errors[0:0] 59 c.queryCache = nil 60 *c.params = (*c.params)[0:0] 61 } 62 63 // Copy returns a copy of the current context that can be safely used outside the request's scope. 64 // This has to be used when the context has to be passed to a goroutine. 65 func (c *Context) Copy() *Context { 66 cp := Context{ 67 writermem: c.writermem, 68 Request: c.Request, 69 Params: c.Params, 70 engine: c.engine, 71 } 72 cp.writermem.ResponseWriter = nil 73 cp.Writer = &cp.writermem 74 cp.index = abortIndex 75 cp.handlers = nil 76 cp.Keys = map[string]interface{}{} 77 for k, v := range c.Keys { 78 cp.Keys[k] = v 79 } 80 paramCopy := make([]Param, len(cp.Params)) 81 copy(paramCopy, cp.Params) 82 cp.Params = paramCopy 83 return &cp 84 } 85 86 // HandlerName returns the main handler's name. For example if the handler is "handleGetUsers()", 87 // this function will return "main.handleGetUsers". 88 func (c *Context) HandlerName() string { 89 return nameOfFunction(c.handlers.Last()) 90 } 91 92 // HandlerNames returns a list of all registered handlers for this context in descending order, 93 // following the semantics of HandlerName() 94 func (c *Context) HandlerNames() []string { 95 hn := make([]string, 0, len(c.handlers)) 96 for _, val := range c.handlers { 97 hn = append(hn, nameOfFunction(val)) 98 } 99 return hn 100 } 101 102 // Handler returns the main handler. 103 func (c *Context) Handler() HandlerFunc { 104 return c.handlers.Last() 105 } 106 107 // FullPath returns a matched route full path. For not found routes 108 // returns an empty string. 109 // router.GET("/user/:id", func(c *gin.Context) { 110 // c.FullPath() == "/user/:id" // true 111 // }) 112 func (c *Context) FullPath() string { 113 return c.fullPath 114 } 115 116 /************************************/ 117 /*********** FLOW CONTROL ***********/ 118 /************************************/ 119 120 // Next should be used only inside middleware. 121 // It executes the pending handlers in the chain inside the calling handler. 122 // See example in GitHub. 123 func (c *Context) Next() { 124 c.index++ 125 for c.index < int8(len(c.handlers)) { 126 c.handlers[c.index](c) 127 c.index++ 128 } 129 } 130 131 // IsAborted returns true if the current context was aborted. 132 func (c *Context) IsAborted() bool { 133 return c.index >= abortIndex 134 } 135 136 // Abort prevents pending handlers from being called. Note that this will not stop the current handler. 137 // Let's say you have an authorization middleware that validates that the current request is authorized. 138 // If the authorization fails (ex: the password does not match), call Abort to ensure the remaining handlers 139 // for this request are not called. 140 func (c *Context) Abort() { 141 c.index = abortIndex 142 } 143 144 // AbortWithStatus calls `Abort()` and writes the headers with the specified status code. 145 // For example, a failed attempt to authenticate a request could use: context.AbortWithStatus(401). 146 func (c *Context) AbortWithStatus(code int) { 147 c.Status(code) 148 c.Writer.WriteHeaderNow() 149 c.Abort() 150 } 151 152 // AbortWithStatusJSON calls `Abort()` and then `JSON` internally. 153 // This method stops the chain, writes the status code and return a JSON body. 154 // It also sets the Content-Type as "application/json". 155 func (c *Context) AbortWithStatusJSON(code int, jsonObj interface{}) { 156 c.Abort() 157 c.JSON(code, jsonObj) 158 } 159 160 // AbortWithError calls `AbortWithStatus()` and `Error()` internally. 161 // This method stops the chain, writes the status code and pushes the specified error to `c.Errors`. 162 // See Context.Error() for more details. 163 func (c *Context) AbortWithError(code int, err error) *Error { 164 c.AbortWithStatus(code) 165 return c.Error(err) 166 } 167 168 /************************************/ 169 /********* ERROR MANAGEMENT *********/ 170 /************************************/ 171 172 // Error attaches an error to the current context. The error is pushed to a list of errors. 173 // It's a good idea to call Error for each error that occurred during the resolution of a request. 174 // A middleware can be used to collect all the errors and push them to a database together, 175 // print a log, or append it in the HTTP response. 176 // Error will panic if err is nil. 177 func (c *Context) Error(err error) *Error { 178 if err == nil { 179 panic("err is nil") 180 } 181 182 parsedError, ok := err.(*Error) 183 if !ok { 184 parsedError = &Error{ 185 Err: err, 186 Type: ErrorTypePrivate, 187 } 188 } 189 190 c.Errors = append(c.Errors, parsedError) 191 return parsedError 192 } 193 194 /************************************/ 195 /******** METADATA MANAGEMENT********/ 196 /************************************/ 197 198 // Set is used to store a new key/value pair exclusively for this context. 199 // It also lazy initializes c.Keys if it was not used previously. 200 func (c *Context) Set(key string, value interface{}) { 201 c.mu.Lock() 202 if c.Keys == nil { 203 c.Keys = make(map[string]interface{}) 204 } 205 206 c.Keys[key] = value 207 c.mu.Unlock() 208 } 209 210 // Get returns the value for the given key, ie: (value, true). 211 // If the value does not exists it returns (nil, false) 212 func (c *Context) Get(key string) (value interface{}, exists bool) { 213 c.mu.RLock() 214 value, exists = c.Keys[key] 215 c.mu.RUnlock() 216 return 217 } 218 219 // MustGet returns the value for the given key if it exists, otherwise it panics. 220 func (c *Context) MustGet(key string) interface{} { 221 if value, exists := c.Get(key); exists { 222 return value 223 } 224 panic("Key \"" + key + "\" does not exist") 225 } 226 227 // GetString returns the value associated with the key as a string. 228 func (c *Context) GetString(key string) (s string) { 229 if val, ok := c.Get(key); ok && val != nil { 230 s, _ = val.(string) 231 } 232 return 233 } 234 235 // GetBool returns the value associated with the key as a boolean. 236 func (c *Context) GetBool(key string) (b bool) { 237 if val, ok := c.Get(key); ok && val != nil { 238 b, _ = val.(bool) 239 } 240 return 241 } 242 243 // GetInt returns the value associated with the key as an integer. 244 func (c *Context) GetInt(key string) (i int) { 245 if val, ok := c.Get(key); ok && val != nil { 246 i, _ = val.(int) 247 } 248 return 249 } 250 251 // GetInt64 returns the value associated with the key as an integer. 252 func (c *Context) GetInt64(key string) (i64 int64) { 253 if val, ok := c.Get(key); ok && val != nil { 254 i64, _ = val.(int64) 255 } 256 return 257 } 258 259 // GetUint returns the value associated with the key as an unsigned integer. 260 func (c *Context) GetUint(key string) (ui uint) { 261 if val, ok := c.Get(key); ok && val != nil { 262 ui, _ = val.(uint) 263 } 264 return 265 } 266 267 // GetUint64 returns the value associated with the key as an unsigned integer. 268 func (c *Context) GetUint64(key string) (ui64 uint64) { 269 if val, ok := c.Get(key); ok && val != nil { 270 ui64, _ = val.(uint64) 271 } 272 return 273 } 274 275 // GetFloat64 returns the value associated with the key as a float64. 276 func (c *Context) GetFloat64(key string) (f64 float64) { 277 if val, ok := c.Get(key); ok && val != nil { 278 f64, _ = val.(float64) 279 } 280 return 281 } 282 283 // GetTime returns the value associated with the key as time. 284 func (c *Context) GetTime(key string) (t time.Time) { 285 if val, ok := c.Get(key); ok && val != nil { 286 t, _ = val.(time.Time) 287 } 288 return 289 } 290 291 // GetDuration returns the value associated with the key as a duration. 292 func (c *Context) GetDuration(key string) (d time.Duration) { 293 if val, ok := c.Get(key); ok && val != nil { 294 d, _ = val.(time.Duration) 295 } 296 return 297 } 298 299 // GetStringSlice returns the value associated with the key as a slice of strings. 300 func (c *Context) GetStringSlice(key string) (ss []string) { 301 if val, ok := c.Get(key); ok && val != nil { 302 ss, _ = val.([]string) 303 } 304 return 305 } 306 307 // GetStringMap returns the value associated with the key as a map of interfaces. 308 func (c *Context) GetStringMap(key string) (sm map[string]interface{}) { 309 if val, ok := c.Get(key); ok && val != nil { 310 sm, _ = val.(map[string]interface{}) 311 } 312 return 313 } 314 315 // GetStringMapString returns the value associated with the key as a map of strings. 316 func (c *Context) GetStringMapString(key string) (sms map[string]string) { 317 if val, ok := c.Get(key); ok && val != nil { 318 sms, _ = val.(map[string]string) 319 } 320 return 321 } 322 323 // GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings. 324 func (c *Context) GetStringMapStringSlice(key string) (smss map[string][]string) { 325 if val, ok := c.Get(key); ok && val != nil { 326 smss, _ = val.(map[string][]string) 327 } 328 return 329 } 330 331 /************************************/ 332 /************ INPUT DATA ************/ 333 /************************************/ 334 335 // Param returns the value of the URL param. 336 // It is a shortcut for c.Params.ByName(key) 337 // router.GET("/user/:id", func(c *gin.Context) { 338 // // a GET request to /user/john 339 // id := c.Param("id") // id == "john" 340 // }) 341 func (c *Context) Param(key string) string { 342 return c.Params.ByName(key) 343 } 344 345 // Query returns the keyed url query value if it exists, 346 // otherwise it returns an empty string `("")`. 347 // It is shortcut for `c.Request.URL.Query().Get(key)` 348 // GET /path?id=1234&name=Manu&value= 349 // c.Query("id") == "1234" 350 // c.Query("name") == "Manu" 351 // c.Query("value") == "" 352 // c.Query("wtf") == "" 353 func (c *Context) Query(key string) string { 354 value, _ := c.GetQuery(key) 355 return value 356 } 357 358 // DefaultQuery returns the keyed url query value if it exists, 359 // otherwise it returns the specified defaultValue string. 360 // See: Query() and GetQuery() for further information. 361 // GET /?name=Manu&lastname= 362 // c.DefaultQuery("name", "unknown") == "Manu" 363 // c.DefaultQuery("id", "none") == "none" 364 // c.DefaultQuery("lastname", "none") == "" 365 func (c *Context) DefaultQuery(key, defaultValue string) string { 366 if value, ok := c.GetQuery(key); ok { 367 return value 368 } 369 return defaultValue 370 } 371 372 // GetQuery is like Query(), it returns the keyed url query value 373 // if it exists `(value, true)` (even when the value is an empty string), 374 // otherwise it returns `("", false)`. 375 // It is shortcut for `c.Request.URL.Query().Get(key)` 376 // GET /?name=Manu&lastname= 377 // ("Manu", true) == c.GetQuery("name") 378 // ("", false) == c.GetQuery("id") 379 // ("", true) == c.GetQuery("lastname") 380 func (c *Context) GetQuery(key string) (string, bool) { 381 if values, ok := c.GetQueryArray(key); ok { 382 return values[0], ok 383 } 384 return "", false 385 } 386 387 // QueryArray returns a slice of strings for a given query key. 388 // The length of the slice depends on the number of params with the given key. 389 func (c *Context) QueryArray(key string) []string { 390 values, _ := c.GetQueryArray(key) 391 return values 392 } 393 394 func (c *Context) initQueryCache() { 395 if c.queryCache == nil { 396 if c.Request != nil { 397 c.queryCache = c.Request.URL.Query() 398 } else { 399 c.queryCache = url.Values{} 400 } 401 } 402 } 403 404 // GetQueryArray returns a slice of strings for a given query key, plus 405 // a boolean value whether at least one value exists for the given key. 406 func (c *Context) GetQueryArray(key string) ([]string, bool) { 407 c.initQueryCache() 408 if values, ok := c.queryCache[key]; ok && len(values) > 0 { 409 return values, true 410 } 411 return nil, false 412 } 413 414 // QueryMap returns a map for a given query key. 415 func (c *Context) QueryMap(key string) map[string]string { 416 dicts, _ := c.GetQueryMap(key) 417 return dicts 418 } 419 420 // GetQueryMap returns a map for a given query key, plus a boolean value 421 // whether at least one value exists for the given key. 422 func (c *Context) GetQueryMap(key string) (map[string]string, bool) { 423 c.initQueryCache() 424 return c.get(c.queryCache, key) 425 } 426 427 // get is an internal method and returns a map which satisfy conditions. 428 func (c *Context) get(m map[string][]string, key string) (map[string]string, bool) { 429 dicts := make(map[string]string) 430 exist := false 431 for k, v := range m { 432 if i := strings.IndexByte(k, '['); i >= 1 && k[0:i] == key { 433 if j := strings.IndexByte(k[i+1:], ']'); j >= 1 { 434 exist = true 435 dicts[k[i+1:][:j]] = v[0] 436 } 437 } 438 } 439 return dicts, exist 440 } 441 442 // FormFile returns the first file for the provided form key. 443 func (c *Context) FormFile(name string) (*multipart.FileHeader, error) { 444 if c.Request.MultipartForm == nil { 445 if err := c.Request.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil { 446 return nil, err 447 } 448 } 449 f, fh, err := c.Request.FormFile(name) 450 if err != nil { 451 return nil, err 452 } 453 _ = f.Close() 454 return fh, err 455 } 456 457 // MultipartForm is the parsed multipart form, including file uploads. 458 func (c *Context) MultipartForm() (*multipart.Form, error) { 459 err := c.Request.ParseMultipartForm(c.engine.MaxMultipartMemory) 460 return c.Request.MultipartForm, err 461 } 462 463 // ContentType returns the Content-Type header of the request. 464 func (c *Context) ContentType() string { 465 return filterFlags(c.requestHeader("Content-Type")) 466 } 467 468 // IsWebsocket returns true if the request headers indicate that a websocket 469 // handshake is being initiated by the client. 470 func (c *Context) IsWebsocket() bool { 471 if strings.Contains(strings.ToLower(c.requestHeader("Connection")), "upgrade") && 472 strings.EqualFold(c.requestHeader("Upgrade"), "websocket") { 473 return true 474 } 475 return false 476 } 477 478 func (c *Context) requestHeader(key string) string { 479 return c.Request.Header.Get(key) 480 } 481 482 /************************************/ 483 /******** RESPONSE RENDERING ********/ 484 /************************************/ 485 486 // bodyAllowedForStatus is a copy of http.bodyAllowedForStatus non-exported function. 487 func bodyAllowedForStatus(status int) bool { 488 switch { 489 case status >= 100 && status <= 199: 490 return false 491 case status == http.StatusNoContent: 492 return false 493 case status == http.StatusNotModified: 494 return false 495 } 496 return true 497 } 498 499 // Status sets the HTTP response code. 500 func (c *Context) Status(code int) { 501 c.Writer.WriteHeader(code) 502 } 503 504 // Header is a intelligent shortcut for c.Writer.Header().Set(key, value). 505 // It writes a header in the response. 506 // If value == "", this method removes the header `c.Writer.Header().Del(key)` 507 func (c *Context) Header(key, value string) { 508 if value == "" { 509 c.Writer.Header().Del(key) 510 return 511 } 512 c.Writer.Header().Set(key, value) 513 } 514 515 // GetHeader returns value from request headers. 516 func (c *Context) GetHeader(key string) string { 517 return c.requestHeader(key) 518 } 519 520 // SetSameSite with cookie 521 func (c *Context) SetSameSite(samesite http.SameSite) { 522 c.sameSite = samesite 523 } 524 525 // SetCookie adds a Set-Cookie header to the ResponseWriter's headers. 526 // The provided cookie must have a valid Name. Invalid cookies may be 527 // silently dropped. 528 func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) { 529 if path == "" { 530 path = "/" 531 } 532 http.SetCookie(c.Writer, &http.Cookie{ 533 Name: name, 534 Value: url.QueryEscape(value), 535 MaxAge: maxAge, 536 Path: path, 537 Domain: domain, 538 SameSite: c.sameSite, 539 Secure: secure, 540 HttpOnly: httpOnly, 541 }) 542 } 543 544 // Cookie returns the named cookie provided in the request or 545 // ErrNoCookie if not found. And return the named cookie is unescaped. 546 // If multiple cookies match the given name, only one cookie will 547 // be returned. 548 func (c *Context) Cookie(name string) (string, error) { 549 cookie, err := c.Request.Cookie(name) 550 if err != nil { 551 return "", err 552 } 553 val, _ := url.QueryUnescape(cookie.Value) 554 return val, nil 555 } 556 557 // Render writes the response headers and calls render.Render to render data. 558 func (c *Context) Render(code int, r render.Render) { 559 c.Status(code) 560 561 if !bodyAllowedForStatus(code) { 562 r.WriteContentType(c.Writer) 563 c.Writer.WriteHeaderNow() 564 return 565 } 566 567 if err := r.Render(c.Writer); err != nil { 568 _ = c.Error(err) 569 c.Abort() 570 } 571 } 572 573 // IndentedJSON serializes the given struct as pretty JSON (indented + endlines) into the response body. 574 // It also sets the Content-Type as "application/json". 575 // WARNING: we recommend to use this only for development purposes since printing pretty JSON is 576 // more CPU and bandwidth consuming. Use Context.JSON() instead. 577 func (c *Context) IndentedJSON(code int, obj interface{}) { 578 c.Render(code, render.IndentedJSON{Data: obj}) 579 } 580 581 // JSON serializes the given struct as JSON into the response body. 582 // It also sets the Content-Type as "application/json". 583 func (c *Context) JSON(code int, obj interface{}) { 584 c.Render(code, render.JSON{Data: obj}) 585 } 586 587 // XML serializes the given struct as XML into the response body. 588 // It also sets the Content-Type as "application/xml". 589 func (c *Context) XML(code int, obj interface{}) { 590 c.Render(code, render.XML{Data: obj}) 591 } 592 593 // String writes the given string into the response body. 594 func (c *Context) String(code int, format string, values ...interface{}) { 595 c.Render(code, render.String{Format: format, Data: values}) 596 } 597 598 // Redirect returns a HTTP redirect to the specific location. 599 func (c *Context) Redirect(code int, location string) { 600 c.Render(-1, render.Redirect{ 601 Code: code, 602 Location: location, 603 Request: c.Request, 604 }) 605 } 606 607 // Data writes some data into the body stream and updates the HTTP code. 608 func (c *Context) Data(code int, contentType string, data []byte) { 609 c.Render(code, render.Data{ 610 ContentType: contentType, 611 Data: data, 612 }) 613 } 614 615 // DataFromReader writes the specified reader into the body stream and updates the HTTP code. 616 func (c *Context) DataFromReader(code int, contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string) { 617 c.Render(code, render.Reader{ 618 Headers: extraHeaders, 619 ContentType: contentType, 620 ContentLength: contentLength, 621 Reader: reader, 622 }) 623 } 624 625 /************************************/ 626 /***** GOLANG.ORG/X/NET/CONTEXT *****/ 627 /************************************/ 628 629 // Deadline always returns that there is no deadline (ok==false), 630 // maybe you want to use Request.Context().Deadline() instead. 631 func (c *Context) Deadline() (deadline time.Time, ok bool) { 632 if c.Request == nil || c.Request.Context() == nil { 633 return 634 } 635 return c.Request.Context().Deadline() 636 } 637 638 // Done always returns nil (chan which will wait forever), 639 // if you want to abort your work when the connection was closed 640 // you should use Request.Context().Done() instead. 641 func (c *Context) Done() <-chan struct{} { 642 if c.Request == nil || c.Request.Context() == nil { 643 return nil 644 } 645 return c.Request.Context().Done() 646 } 647 648 // Err always returns nil, maybe you want to use Request.Context().Err() instead. 649 func (c *Context) Err() error { 650 if c.Request == nil || c.Request.Context() == nil { 651 return nil 652 } 653 return c.Request.Context().Err() 654 } 655 656 // Value returns the value associated with this context for key, or nil 657 // if no value is associated with key. Successive calls to Value with 658 // the same key returns the same result. 659 func (c *Context) Value(key interface{}) interface{} { 660 if key == 0 { 661 return c.Request 662 } 663 if keyAsString, ok := key.(string); ok { 664 if val, exists := c.Get(keyAsString); exists { 665 return val 666 } 667 } 668 if c.Request == nil || c.Request.Context() == nil { 669 return nil 670 } 671 return c.Request.Context().Value(key) 672 }