From b7100620c3e7dccc50d008747eddb53a73d9d9d8 Mon Sep 17 00:00:00 2001 From: Aaron Date: Sat, 25 Jul 2026 17:12:10 -0400 Subject: [PATCH] feat(client): Allow configuration of client cookie storage (#1716) * Allow configuration of cookie storage * Update client/config.go --------- Co-authored-by: TwiN --- README.md | 2 ++ client/config.go | 12 ++++++++++++ client/config_test.go | 15 +++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/README.md b/README.md index 086597f3..e7350d6f 100644 --- a/README.md +++ b/README.md @@ -654,6 +654,7 @@ the client used to send the request. | `client.tls.renegotiation` | Type of renegotiation support to provide. (`never`, `freely`, `once`). | `"never"` | | `client.network` | The network to use for ICMP endpoint client (`ip`, `ip4` or `ip6`). | `"ip"` | | `client.tunnel` | Name of the SSH tunnel to use for this endpoint. See [Tunneling](#tunneling). | `""` | +| `client.store-cookies` | Whether to store cookies between requests. | `false` | > 📝 Some of these parameters are ignored based on the type of endpoint. For instance, there's no certificate involved @@ -666,6 +667,7 @@ client: insecure: false ignore-redirect: false timeout: 10s + store-cookies: false ``` Note that this configuration is only available under `endpoints[]`, `alerting.mattermost` and `alerting.custom`. diff --git a/client/config.go b/client/config.go index 7cc174cf..740e46e6 100644 --- a/client/config.go +++ b/client/config.go @@ -6,6 +6,7 @@ import ( "errors" "net" "net/http" + "net/http/cookiejar" "net/url" "regexp" "strconv" @@ -34,6 +35,7 @@ var ( IgnoreRedirect: false, Timeout: defaultTimeout, Network: "ip", + StoreCookies: false, } ) @@ -82,6 +84,9 @@ type Config struct { // ResolvedTunnel is the resolved SSH tunnel for this specific Config ResolvedTunnel *sshtunnel.SSHTunnel `yaml:"-"` + // StoreCookies determines whether cookies are stored and included across requests. + StoreCookies bool `yaml:"store-cookies,omitempty"` + httpClient *http.Client } @@ -280,6 +285,13 @@ func (c *Config) getHTTPClient() *http.Client { } } } + if c.StoreCookies { + jar, err := cookiejar.New(nil) + if err != nil { + logr.Fatalf("[client.getHTTPClient] Failed to initialize cookie jar: %v", err) + } + c.httpClient.Jar = jar + } } return c.httpClient } diff --git a/client/config_test.go b/client/config_test.go index 3f6043fb..82b8d1f0 100644 --- a/client/config_test.go +++ b/client/config_test.go @@ -17,6 +17,9 @@ func TestConfig_getHTTPClient(t *testing.T) { if insecureClient.Timeout != defaultTimeout { t.Error("expected Config.Timeout to default the HTTP client to a timeout of 10s") } + if insecureClient.Jar != nil { + t.Error("expected Config.StoreCookies to default the HTTP client to not store cookies") + } request, _ := http.NewRequest("GET", "", nil) if err := insecureClient.CheckRedirect(request, nil); err != nil { t.Error("expected Config.IgnoreRedirect set to false to cause the HTTP client's CheckRedirect to return nil") @@ -31,12 +34,24 @@ func TestConfig_getHTTPClient(t *testing.T) { if secureClient.Timeout != 5*time.Second { t.Error("expected Config.Timeout to cause the HTTP client to have a timeout of 5s") } + if insecureClient.Jar != nil { + t.Error("expected Config.StoreCookies to default the HTTP client to not store cookies") + } request, _ = http.NewRequest("GET", "", nil) if err := secureClient.CheckRedirect(request, nil); err != http.ErrUseLastResponse { t.Error("expected Config.IgnoreRedirect set to true to cause the HTTP client's CheckRedirect to return http.ErrUseLastResponse") } } +func TestConfig_getHTTPClient_withCookieJar(t *testing.T) { + config := &Config{StoreCookies: true} + config.ValidateAndSetDefaults() + client := config.getHTTPClient() + if client.Jar == nil { + t.Error("expected Config.StoreCookies to cause the HTTP client to have a CookieJar") + } +} + func TestConfig_ValidateAndSetDefaults_withCustomDNSResolver(t *testing.T) { type args struct { dnsResolver string