Search code examples
gogo-gin

golang gin get cookie json


I use gin@v1.9.0

Trying to get cookie from request

Cookie example:

key={"ckey": "cvalue"}

code:

token, err := c.Request.Cookie("key")

Returns error

http: named cookie not present

But without curly braces, works fine

Cookie example:

key=cvalue

receive token = "key=cvalue"


Solution

  • The issue is happening because of the cookie value format.

    Let's look at these codes from net/http

     // Strip the quotes, if present.
    if allowDoubleQuote && len(raw) > 1 && raw[0] == '"' && raw[len(raw)-1] == '"' {
        raw = raw[1 : len(raw)-1]
    }
    

    this statement is used to strip the " from the beginning and the end of the string. {"ckey": "cvalue"} the quotes from this string cannot be removed.

    And then it call another function which is a loop that iterates through each characters and checks the character is a valid byte.

       for i := 0; i < len(raw); i++ {
            if !validCookieValueByte(raw[i]) {
                return "", false
            }
        }
    

    validCookieValueByte implementation

    func validCookieValueByte(b byte) bool {
        return 0x20 <= b && b < 0x7f && b != '"' && b != ';' && b != '\\'
    }
    

    and the check is failing at here. Because we have a " in {"ckey": "cvalue"}

    Let's check with a sample code

    func main() {
        router := gin.Default()
    
        router.GET("/get-cookie", func(c *gin.Context) {
            cookie, err := c.Request.Cookie("key")
            if err != nil {
                c.String(http.StatusBadRequest, err.Error())
                return
            }
            c.String(http.StatusOK, fmt.Sprintf("token = key=%v", cookie.Value))
        })
    
        router.Run(":8080")
    }
    

    This will fail

    curl --request GET \
      --url http://localhost:8080/get-cookie \
      --cookie key='{"ckey": "cvalue"}'
    

    but this will succeed

    curl --request GET \
      --url http://localhost:8080/get-cookie \
      --cookie key='{ckey: cvalue}'
    

    We can use http.Cookie to set the cookie as json

    val := `{"ckey": "cvalue"}`
    cookie := &http.Cookie{
        Name:  "key",
        Value: val,
    }
    http.SetCookie(c.Writer, cookie)
    

    SetCookie will remove the " before saving the value.