Skip to content

HttpClient does not set a cookie spec: every response logs "Invalid cookie header" at WARN #25

Description

@CharlyRien

Summary

AfterShipClient.Builder.build() creates its RequestConfig without a cookie spec, so Apache HttpClient 4 falls back to CookieSpecs.DEFAULT. That spec cannot parse the Cloudflare __cf_bm cookie that api.aftership.com returns on every response, and org.apache.http.client.protocol.ResponseProcessCookies logs a WARN for each call.

We see ~5000 of these per day on a single worker. There is no functional impact, but it drowns the application logs.

Invalid cookie header: "set-cookie: __cf_bm=<redacted>; HttpOnly; SameSite=None; Secure; Path=/; Domain=aftership.com; Expires=Fri, 11 Sep 2026 07:52:08 GMT". Invalid 'expires' attribute: Fri, 11 Sep 2026 07:52:08 GMT

Versions

  • com.aftership:tracking-sdk 11.0.0 and 12.0.1 (latest) are both affected
  • org.apache.httpcomponents:httpclient 4.5.14, as declared by the SDK pom

Root cause

AfterShipClient.Builder.build() only sets the proxy and the socket timeout:

RequestConfig.custom()
    .setProxy(...)          // when a proxy is configured
    .setSocketTimeout(timeoutMill)
    .build();

With no cookieSpec, HttpClient 4 uses DefaultCookieSpecProvider. Because the Set-Cookie header carries an expires attribute and no version, that provider routes to the Netscape draft branch, which only accepts EEE, dd-MMM-yy HH:mm:ss z. Cloudflare emits RFC 1123 (Fri, 11 Sep 2026 07:52:08 GMT), so parsing fails.

Reproduction

Standalone, against httpclient 4.5.14 — no SDK call needed:

CookieSpec spec = new DefaultCookieSpecProvider().create(null);
CookieOrigin origin = new CookieOrigin("api.aftership.com", 443, "/", true);
Header header = new BasicHeader("Set-Cookie",
    "__cf_bm=abc123; HttpOnly; SameSite=None; Secure; Path=/; Domain=aftership.com; Expires=Fri, 11 Sep 2026 07:52:08 GMT");
spec.parse(header, origin);

Output:

Invalid 'expires' attribute: Fri, 11 Sep 2026 07:52:08 GMT

The same header parses cleanly with new RFC6265CookieSpecProvider().create(null), and the default spec accepts the header once Expires is rewritten as Fri, 11-Sep-26 07:52:08 GMT.

Suggested fix

The SDK authenticates through headers and never reads cookies, so the cleanest fix is to opt out in AfterShipClient.Builder.build():

RequestConfig.custom()
    .setCookieSpec(CookieSpecs.IGNORE_COOKIES)
    // ... existing proxy and timeout

If you would rather keep cookie handling, CookieSpecs.STANDARD (RFC 6265) parses the Cloudflare cookie correctly.

Workarounds for other users

  • Set org.apache.http.client.protocol.ResponseProcessCookies to ERROR in the logging configuration.
  • Or pass a pre-built client: new AfterShipClient.Builder(...).setHttpClient(new HttpClient(requestConfig, userAgent)) with a RequestConfig that sets CookieSpecs.IGNORE_COOKIES.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions