diff --git a/binding/binding.go b/binding/binding.go index 036b329b1c..bcf8b06a79 100644 --- a/binding/binding.go +++ b/binding/binding.go @@ -85,6 +85,7 @@ var ( Uri = uriBinding{} Header = headerBinding{} TOML = tomlBinding{} + Cookie = cookieBinding{} ) // Default returns the appropriate Binding instance based on the HTTP method diff --git a/binding/cookie.go b/binding/cookie.go new file mode 100644 index 0000000000..d82c36c945 --- /dev/null +++ b/binding/cookie.go @@ -0,0 +1,22 @@ +// Copyright 2017 Manu Martinez-Almeida. All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package binding + +import "net/http" + +type cookieBinding struct{} + +func (cookieBinding) Name() string { + return "cookie" +} + +func (c cookieBinding) Bind(req *http.Request, obj any) error { + cookies := make(map[string][]string, len(req.Cookies())) + for _, cookie := range req.Cookies() { + cookies[cookie.Name] = append(cookies[cookie.Name], cookie.Value) + } + + return mapFormByTag(obj, cookies, c.Name()) +} diff --git a/context.go b/context.go index 3a9608d5fb..8156f2acc1 100644 --- a/context.go +++ b/context.go @@ -737,6 +737,11 @@ func (c *Context) ShouldBindHeader(obj any) error { return c.ShouldBindWith(obj, binding.Header) } +// ShouldBindCookie is a shortcut for c.ShouldBindWith(obj, binding.Cookie). +func (c *Context) ShouldBindCookie(obj any) error { + return c.ShouldBindWith(obj, binding.Cookie) +} + // ShouldBindUri binds the passed struct pointer using the specified binding engine. func (c *Context) ShouldBindUri(obj any) error { m := make(map[string][]string) diff --git a/context_test.go b/context_test.go index 9c1717ed20..794fee329d 100644 --- a/context_test.go +++ b/context_test.go @@ -1825,6 +1825,27 @@ func TestContextShouldBindHeader(t *testing.T) { assert.Equal(t, 0, w.Body.Len()) } +func TestContextShouldBindCookie(t *testing.T) { + w := httptest.NewRecorder() + c, _ := CreateTestContext(w) + + c.Request, _ = http.NewRequest("POST", "/", nil) + c.Request.AddCookie(&http.Cookie{Name: "rate", Value: "8000"}) + c.Request.AddCookie(&http.Cookie{Name: "domain", Value: "music"}) + c.Request.AddCookie(&http.Cookie{Name: "limit", Value: "1000"}) + + var testCookie struct { + Rate int `cookie:"rate"` + Domain string `cookie:"domain"` + Limit int `cookie:"limit"` + } + + assert.NoError(t, c.ShouldBindCookie(&testCookie)) + assert.Equal(t, 8000, testCookie.Rate) + assert.Equal(t, "music", testCookie.Domain) + assert.Equal(t, 1000, testCookie.Limit) +} + func TestContextShouldBindWithQuery(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) diff --git a/docs/doc.md b/docs/doc.md index df006e87a7..8b9d12f88b 100644 --- a/docs/doc.md +++ b/docs/doc.md @@ -28,6 +28,7 @@ - [Bind Query String or Post Data](#bind-query-string-or-post-data) - [Bind Uri](#bind-uri) - [Bind Header](#bind-header) + - [Bind Cookie](#bind-cookie) - [Bind HTML checkboxes](#bind-html-checkboxes) - [Multipart/Urlencoded binding](#multiparturlencoded-binding) - [XML, JSON, YAML, TOML and ProtoBuf rendering](#xml-json-yaml-toml-and-protobuf-rendering) @@ -938,6 +939,45 @@ func main() { } ``` +### Bind Cookie + +```go +package main + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" +) + +type testCookie struct { + Rate int `cookie:"Rate"` + Domain string `cookie:"Domain"` +} + +func main() { + r := gin.Default() + r.GET("/", func(c *gin.Context) { + h := testCookie{} + + if err := c.ShouldBindCookie(&h); err != nil { + c.JSON(http.StatusOK, err) + } + + fmt.Printf("%#v\n", h) + c.JSON(http.StatusOK, gin.H{"Rate": h.Rate, "Domain": h.Domain}) + }) + + r.Run() + +// client +// curl -H "rate:300" -H "domain:music" 127.0.0.1:8080/ +// output +// {"Domain":"music","Rate":300} +} +``` + ### Bind HTML checkboxes See the [detail information](https://github.com/gin-gonic/gin/issues/129#issuecomment-124260092)