Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,14 +280,15 @@ func (c *Context) Error(err error) *Error {

// Set is used to store a new key/value pair exclusively for this context.
// It also lazy initializes c.Keys if it was not used previously.
func (c *Context) Set(key any, value any) {
func (c *Context) Set(key any, value any) *Context {
c.mu.Lock()
defer c.mu.Unlock()
if c.Keys == nil {
c.Keys = make(map[any]any)
}

c.Keys[key] = value
return c
}

// Get returns the value for the given key, ie: (value, true).
Expand Down Expand Up @@ -506,8 +507,9 @@ func (c *Context) Param(key string) string {
// Example Route: "/user/:id"
// AddParam("id", 1)
// Result: "/user/1"
func (c *Context) AddParam(key, value string) {
func (c *Context) AddParam(key, value string) *Context {
c.Params = append(c.Params, Param{Key: key, Value: value})
return c
}

// Query returns the keyed url query value if it exists,
Expand Down Expand Up @@ -1052,19 +1054,21 @@ func bodyAllowedForStatus(status int) bool {
}

// Status sets the HTTP response code.
func (c *Context) Status(code int) {
func (c *Context) Status(code int) *Context {
c.Writer.WriteHeader(code)
return c
}

// Header is an intelligent shortcut for c.Writer.Header().Set(key, value).
// It writes a header in the response.
// If value == "", this method removes the header `c.Writer.Header().Del(key)`
func (c *Context) Header(key, value string) {
func (c *Context) Header(key, value string) *Context {
if value == "" {
c.Writer.Header().Del(key)
return
return c
}
c.Writer.Header().Set(key, value)
return c
}

// GetHeader returns value from request headers.
Expand All @@ -1081,14 +1085,15 @@ func (c *Context) GetRawData() ([]byte, error) {
}

// SetSameSite with cookie
func (c *Context) SetSameSite(samesite http.SameSite) {
func (c *Context) SetSameSite(samesite http.SameSite) *Context {
c.sameSite = samesite
return c
}

// SetCookie adds a Set-Cookie header to the ResponseWriter's headers.
// The provided cookie must have a valid Name. Invalid cookies may be
// silently dropped.
func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) {
func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) *Context {
if path == "" {
path = "/"
}
Expand All @@ -1102,19 +1107,21 @@ func (c *Context) SetCookie(name, value string, maxAge int, path, domain string,
Secure: secure,
HttpOnly: httpOnly,
})
return c
}

// SetCookieData adds a Set-Cookie header to the ResponseWriter's headers.
// It accepts a pointer to http.Cookie structure for more flexibility in setting cookie attributes.
// The provided cookie must have a valid Name. Invalid cookies may be silently dropped.
func (c *Context) SetCookieData(cookie *http.Cookie) {
func (c *Context) SetCookieData(cookie *http.Cookie) *Context {
if cookie.Path == "" {
cookie.Path = "/"
}
if cookie.SameSite == http.SameSiteDefaultMode {
cookie.SameSite = c.sameSite
}
http.SetCookie(c.Writer, cookie)
return c
}

// Cookie returns the named cookie provided in the request or
Expand Down Expand Up @@ -1394,8 +1401,9 @@ func (c *Context) NegotiateFormat(offered ...string) string {
}

// SetAccepted sets Accept header data.
func (c *Context) SetAccepted(formats ...string) {
func (c *Context) SetAccepted(formats ...string) *Context {
c.Accepted = formats
return c
}

/************************************/
Expand Down
43 changes: 43 additions & 0 deletions context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3677,3 +3677,46 @@ func BenchmarkGetMapFromFormData(b *testing.B) {
})
}
}

func TestContextChaining(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
// Basic cookie settings
cookie := &http.Cookie{
Name: "name",
Value: "gin",
MaxAge: 1,
Path: "/",
Domain: "localhost",
Secure: true,
HttpOnly: true,
}

c.Set("foo", "bar").
AddParam("id", "1").
SetSameSite(http.SameSiteLaxMode).
SetCookie("user", "gin", 1, "/", "localhost", true, true).
SetCookieData(cookie).
Header("Content-Type", "text/plain").
Header("X-Custom", "value").
SetAccepted(MIMEJSON, MIMEXML).
Status(200)

value, err := c.Get("foo")
assert.Equal(t, "bar", value)
assert.True(t, err)

v, ok := c.Params.Get("id")
assert.True(t, ok)
assert.Equal(t, "1", v)

assert.Equal(t, []string{"user=gin; Path=/; Domain=localhost; Max-Age=1; HttpOnly; Secure; SameSite=Lax", "name=gin; Path=/; Domain=localhost; Max-Age=1; HttpOnly; Secure"}, c.Writer.Header().Values("Set-Cookie"))

assert.Equal(t, "text/plain", c.Writer.Header().Get("Content-Type"))
assert.Equal(t, "value", c.Writer.Header().Get("X-Custom"))

assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON, MIMEXML)) //nolint:testifylint
assert.Equal(t, MIMEXML, c.NegotiateFormat(MIMEXML, MIMEHTML))
assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON)) //nolint:testifylint

assert.Equal(t, 200, c.Writer.Status())
}