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  }