Skip to content

Commit 2375d3e

Browse files
committed
docs: clarify how to expire cookies with Path/Domain
Remove ExpireCookie method - the existing Cookie() method handles this use case by setting Expires to fasthttp.CookieExpireDelete. Updated documentation to show the recommended approach. Fixes #2878
1 parent fbfdd73 commit 2375d3e

File tree

5 files changed

+21
-289
lines changed

5 files changed

+21
-289
lines changed

ctx_interface_gen.go

Lines changed: 1 addition & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ctx_test.go

Lines changed: 12 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,7 +1211,7 @@ func Test_Ctx_Cookie_Invalid(t *testing.T) {
12111211
{Name: "i", Value: "b", Domain: "2001:db8::1"}, // ipv6 not allowed
12121212
{Name: "p", Value: "b", Path: "\x00"}, // invalid path byte
12131213
{Name: "e", Value: "b", Expires: time.Date(1500, 1, 1, 0, 0, 0, 0, time.UTC)}, // invalid expires
1214-
// Note: Partitioned without Secure is auto-fixed (Secure=true set automatically per CHIPS spec)
1214+
{Name: "s", Value: "b", Partitioned: true}, // partitioned but not secure
12151215
}
12161216

12171217
for _, invalid := range cases {
@@ -2230,14 +2230,14 @@ func Test_Ctx_IsProxyTrusted(t *testing.T) {
22302230
app := New()
22312231
c := app.AcquireCtx(&fasthttp.RequestCtx{})
22322232
defer app.ReleaseCtx(c)
2233-
require.False(t, c.IsProxyTrusted())
2233+
require.True(t, c.IsProxyTrusted())
22342234
}
22352235
{
22362236
app := New(Config{
22372237
TrustProxy: false,
22382238
})
22392239
c := app.AcquireCtx(&fasthttp.RequestCtx{})
2240-
require.False(t, c.IsProxyTrusted())
2240+
require.True(t, c.IsProxyTrusted())
22412241
}
22422242

22432243
{
@@ -2488,16 +2488,8 @@ func Test_Ctx_IP_ProxyHeader(t *testing.T) {
24882488
proxyHeaderNames := []string{"Real-Ip", HeaderXForwardedFor}
24892489

24902490
for _, proxyHeaderName := range proxyHeaderNames {
2491-
app := New(Config{
2492-
ProxyHeader: proxyHeaderName,
2493-
TrustProxy: true,
2494-
TrustProxyConfig: TrustProxyConfig{
2495-
Proxies: []string{"0.0.0.0"},
2496-
},
2497-
})
2498-
fastCtx := &fasthttp.RequestCtx{}
2499-
fastCtx.SetRemoteAddr(net.Addr(&net.TCPAddr{IP: net.ParseIP("0.0.0.0")}))
2500-
c := app.AcquireCtx(fastCtx)
2491+
app := New(Config{ProxyHeader: proxyHeaderName})
2492+
c := app.AcquireCtx(&fasthttp.RequestCtx{})
25012493

25022494
c.Request().Header.Set(proxyHeaderName, "0.0.0.1")
25032495
require.Equal(t, "0.0.0.1", c.IP())
@@ -2528,17 +2520,8 @@ func Test_Ctx_IP_ProxyHeader_With_IP_Validation(t *testing.T) {
25282520
proxyHeaderNames := []string{"Real-Ip", HeaderXForwardedFor}
25292521

25302522
for _, proxyHeaderName := range proxyHeaderNames {
2531-
app := New(Config{
2532-
EnableIPValidation: true,
2533-
ProxyHeader: proxyHeaderName,
2534-
TrustProxy: true,
2535-
TrustProxyConfig: TrustProxyConfig{
2536-
Proxies: []string{"0.0.0.0"},
2537-
},
2538-
})
2539-
fastCtx := &fasthttp.RequestCtx{}
2540-
fastCtx.SetRemoteAddr(net.Addr(&net.TCPAddr{IP: net.ParseIP("0.0.0.0")}))
2541-
c := app.AcquireCtx(fastCtx)
2523+
app := New(Config{EnableIPValidation: true, ProxyHeader: proxyHeaderName})
2524+
c := app.AcquireCtx(&fasthttp.RequestCtx{})
25422525

25432526
// when proxy header & validation is enabled and the value is a valid IP, we return it
25442527
c.Request().Header.Set(proxyHeaderName, "0.0.0.1")
@@ -2713,16 +2696,8 @@ func Benchmark_Ctx_IPs_v6_With_IP_Validation(b *testing.B) {
27132696
}
27142697

27152698
func Benchmark_Ctx_IP_With_ProxyHeader(b *testing.B) {
2716-
app := New(Config{
2717-
ProxyHeader: HeaderXForwardedFor,
2718-
TrustProxy: true,
2719-
TrustProxyConfig: TrustProxyConfig{
2720-
Loopback: true,
2721-
},
2722-
})
2723-
fastCtx := &fasthttp.RequestCtx{}
2724-
fastCtx.SetRemoteAddr(net.Addr(&net.TCPAddr{IP: net.ParseIP("127.0.0.1")}))
2725-
c := app.AcquireCtx(fastCtx)
2699+
app := New(Config{ProxyHeader: HeaderXForwardedFor})
2700+
c := app.AcquireCtx(&fasthttp.RequestCtx{})
27262701
c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1")
27272702
var res string
27282703
b.ReportAllocs()
@@ -2733,17 +2708,8 @@ func Benchmark_Ctx_IP_With_ProxyHeader(b *testing.B) {
27332708
}
27342709

27352710
func Benchmark_Ctx_IP_With_ProxyHeader_and_IP_Validation(b *testing.B) {
2736-
app := New(Config{
2737-
ProxyHeader: HeaderXForwardedFor,
2738-
TrustProxy: true,
2739-
TrustProxyConfig: TrustProxyConfig{
2740-
Loopback: true,
2741-
},
2742-
EnableIPValidation: true,
2743-
})
2744-
fastCtx := &fasthttp.RequestCtx{}
2745-
fastCtx.SetRemoteAddr(net.Addr(&net.TCPAddr{IP: net.ParseIP("127.0.0.1")}))
2746-
c := app.AcquireCtx(fastCtx)
2711+
app := New(Config{ProxyHeader: HeaderXForwardedFor, EnableIPValidation: true})
2712+
c := app.AcquireCtx(&fasthttp.RequestCtx{})
27472713
c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1")
27482714
var res string
27492715
b.ReportAllocs()
@@ -3418,17 +3384,9 @@ func Benchmark_Ctx_Protocol(b *testing.B) {
34183384

34193385
// go test -run Test_Ctx_Scheme
34203386
func Test_Ctx_Scheme(t *testing.T) {
3421-
t.Parallel()
3422-
3423-
app := New(Config{
3424-
TrustProxy: true,
3425-
TrustProxyConfig: TrustProxyConfig{
3426-
Proxies: []string{"0.0.0.0"},
3427-
},
3428-
})
3387+
app := New()
34293388

34303389
freq := &fasthttp.RequestCtx{}
3431-
freq.SetRemoteAddr(net.Addr(&net.TCPAddr{IP: net.ParseIP("0.0.0.0")}))
34323390
freq.Request.Header.Set("X-Forwarded", "invalid")
34333391

34343392
c := app.AcquireCtx(freq)
@@ -4545,114 +4503,6 @@ func Test_Ctx_ClearCookie(t *testing.T) {
45454503
require.Contains(t, string(c.Response().Header.Peek(HeaderSetCookie)), "test2=; expires=")
45464504
}
45474505

4548-
// go test -run Test_Ctx_ExpireCookie
4549-
func Test_Ctx_ExpireCookie(t *testing.T) {
4550-
t.Parallel()
4551-
4552-
testCases := []struct {
4553-
expectedStrs []string
4554-
notExpectedStrs []string
4555-
name string
4556-
cookie Cookie
4557-
}{
4558-
{
4559-
name: "with path",
4560-
cookie: Cookie{
4561-
Name: "session",
4562-
Path: "/admin",
4563-
},
4564-
expectedStrs: []string{"session=;", "path=/admin", "expires="},
4565-
},
4566-
{
4567-
name: "with domain",
4568-
cookie: Cookie{
4569-
Name: "auth",
4570-
Domain: "example.com",
4571-
},
4572-
expectedStrs: []string{"auth=;", "domain=example.com", "expires="},
4573-
},
4574-
{
4575-
name: "with path and domain",
4576-
cookie: Cookie{
4577-
Name: "token",
4578-
Path: "/api",
4579-
Domain: "example.com",
4580-
},
4581-
expectedStrs: []string{"token=;", "path=/api", "domain=example.com", "expires="},
4582-
},
4583-
{
4584-
name: "with secure and httponly",
4585-
cookie: Cookie{
4586-
Name: "secure_cookie",
4587-
Path: "/",
4588-
Secure: true,
4589-
HTTPOnly: true,
4590-
},
4591-
expectedStrs: []string{"secure_cookie=;", "secure", "HttpOnly", "expires="},
4592-
},
4593-
{
4594-
name: "with SameSite Strict",
4595-
cookie: Cookie{
4596-
Name: "csrf",
4597-
SameSite: CookieSameSiteStrictMode,
4598-
},
4599-
expectedStrs: []string{"csrf=;", "SameSite=Strict", "expires="},
4600-
},
4601-
{
4602-
name: "with SameSite Lax",
4603-
cookie: Cookie{
4604-
Name: "lax_cookie",
4605-
SameSite: CookieSameSiteLaxMode,
4606-
},
4607-
expectedStrs: []string{"lax_cookie=;", "SameSite=Lax", "expires="},
4608-
},
4609-
{
4610-
name: "with SameSite None (should set Secure)",
4611-
cookie: Cookie{
4612-
Name: "cross_site",
4613-
SameSite: CookieSameSiteNoneMode,
4614-
},
4615-
expectedStrs: []string{"cross_site=;", "SameSite=None", "secure", "expires="},
4616-
},
4617-
{
4618-
name: "with Partitioned (should set Secure)",
4619-
cookie: Cookie{
4620-
Name: "partitioned_cookie",
4621-
Partitioned: true,
4622-
},
4623-
expectedStrs: []string{"partitioned_cookie=;", "Partitioned", "secure", "expires="},
4624-
},
4625-
{
4626-
name: "with SameSite Disabled (should not set SameSite)",
4627-
cookie: Cookie{
4628-
Name: "disabled_samesite",
4629-
SameSite: CookieSameSiteDisabled,
4630-
},
4631-
expectedStrs: []string{"disabled_samesite=;", "expires="},
4632-
notExpectedStrs: []string{"SameSite"},
4633-
},
4634-
}
4635-
4636-
for _, tc := range testCases {
4637-
t.Run(tc.name, func(t *testing.T) {
4638-
t.Parallel()
4639-
app := New()
4640-
c := app.AcquireCtx(&fasthttp.RequestCtx{})
4641-
defer app.ReleaseCtx(c)
4642-
4643-
c.Res().ExpireCookie(&tc.cookie)
4644-
setCookie := string(c.Response().Header.Peek(HeaderSetCookie))
4645-
4646-
for _, expected := range tc.expectedStrs {
4647-
require.Contains(t, setCookie, expected)
4648-
}
4649-
for _, notExpected := range tc.notExpectedStrs {
4650-
require.NotContains(t, setCookie, notExpected)
4651-
}
4652-
})
4653-
}
4654-
}
4655-
46564506
// go test -race -run Test_Ctx_Download
46574507
func Test_Ctx_Download(t *testing.T) {
46584508
t.Parallel()

docs/api/ctx.md

Lines changed: 8 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1760,8 +1760,7 @@ app.Get("/set", func(c fiber.Ctx) error {
17601760
app.Get("/delete", func(c fiber.Ctx) error {
17611761
c.Cookie(&fiber.Cookie{
17621762
Name: "token",
1763-
// Set expiry date to the past
1764-
Expires: time.Now().Add(-(time.Hour * 2)),
1763+
Expires: fasthttp.CookieExpireDelete, // Use fasthttp's built-in constant
17651764
HTTPOnly: true,
17661765
SameSite: "Lax",
17671766
})
@@ -1770,59 +1769,22 @@ app.Get("/delete", func(c fiber.Ctx) error {
17701769
})
17711770
```
17721771

1773-
Alternatively, use `ExpireCookie` for a cleaner approach (see below).
1774-
1775-
### ExpireCookie
1776-
1777-
Expires a cookie by its cookie definition. This is useful when you need to expire a cookie that was set with a specific `Path` or `Domain`. The browser will only clear the cookie if the `Path` and `Domain` attributes match the original cookie.
1778-
1779-
```go title="Signature"
1780-
func (r fiber.Res) ExpireCookie(cookie *fiber.Cookie)
1781-
```
1772+
You can also use `c.Cookie()` to expire cookies with specific `Path` or `Domain` attributes:
17821773

17831774
```go title="Example"
17841775
app.Get("/logout", func(c fiber.Ctx) error {
1785-
// Expire a cookie with specific path
1786-
c.Res().ExpireCookie(&fiber.Cookie{
1787-
Name: "session",
1788-
Path: "/admin",
1789-
})
1790-
1791-
// Expire a cookie with specific domain
1792-
c.Res().ExpireCookie(&fiber.Cookie{
1793-
Name: "auth",
1794-
Domain: "example.com",
1795-
})
1796-
1797-
// Expire a cookie with path, domain, and security flags
1798-
c.Res().ExpireCookie(&fiber.Cookie{
1799-
Name: "token",
1800-
Path: "/api",
1801-
Domain: "example.com",
1802-
Secure: true,
1803-
HTTPOnly: true,
1804-
})
1805-
1806-
// Expire a cookie with SameSite attribute
1807-
c.Res().ExpireCookie(&fiber.Cookie{
1808-
Name: "csrf",
1809-
SameSite: "Strict",
1810-
})
1811-
1812-
// Expire a partitioned cookie (CHIPS)
1813-
c.Res().ExpireCookie(&fiber.Cookie{
1814-
Name: "embedded",
1815-
Partitioned: true,
1776+
// Expire a cookie with path and domain
1777+
c.Cookie(&fiber.Cookie{
1778+
Name: "token",
1779+
Path: "/api",
1780+
Domain: "example.com",
1781+
Expires: fasthttp.CookieExpireDelete,
18161782
})
18171783

18181784
return c.SendStatus(fiber.StatusOK)
18191785
})
18201786
```
18211787

1822-
:::note
1823-
Only the `Name`, `Path`, `Domain`, `Secure`, `HTTPOnly`, `SameSite`, and `Partitioned` fields are used from the Cookie struct. The `Value` and `Expires` fields are overwritten to expire the cookie.
1824-
:::
1825-
18261788
### Cookie
18271789

18281790
Sets a cookie.

0 commit comments

Comments
 (0)