I am using a standard RestTemplate of Spring boot 2.6.7, which corresponds to org.apache.httpcomponents -> httpclient -> 4.5.13.
Calling one public API causes some warnings to be present in the logs. The logger appears to be from httpclient from apache:
org.apache.http.client.protocol.ResponseProcessCookies
The warning is:
Invalid cookie header: "Set-Cookie: ts=foo; Path=/; Domain=paypal.com;
Expires=Sat, 21 Feb 2026 14:43:55 GMT; HttpOnly; Secure".
Invalid 'expires' attribute: Sat, 21 Feb 2026 14:43:55 GMT
I checked the source code of apache http client:
- The interceptor
org.apache.http.client.protocol.RequestAddCookies
influences theorg.apache.http.client.protocol.ResponseProcessCookies
one - In the end it all falls down to using the
org.apache.http.impl.cookie.DefaultCookieSpec
- which instantiates a
netscapeDraft
withNetscapeDraftSpec.EXPIRES_PATTERN
, which isEEE, dd-MMM-yy HH:mm:ss z
- so when the
DefaultCookieSpec
sees the attributeexpires
it goes and tries to parse it via the above mentioned pattern, which is legacy and failing (see below a screenshot from apache httpclient lib):
I don't understand how come the default settings are not enough to have a perfectly conform date to be able to parsed properly.
The PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz"
would be working with Sat, 21 Feb 2026 14:43:55 GMT
, but it is not used as default. In order to make it working I have to customize the cookie parsing explicitly, which appears ugly to me:
new RestTemplateBuilder()
.requestFactory(() -> new HttpComponentsClientHttpRequestFactory(
HttpClientBuilder.create().setDefaultRequestConfig(RequestConfig.custom().setCookieSpec("fixPaypalExpires").build())
.setDefaultCookieSpecRegistry(CookieSpecRegistries.createDefaultBuilder()
.register("fixPaypalExpires",
new DefaultCookieSpecProvider(
CompatibilityLevel.DEFAULT,
PublicSuffixMatcherLoader.getDefault(),
new String[]{"EEE, dd MMM yyyy HH:mm:ss z"},
false))
.build())
.build()))
.build();
Or maybe I can use one of the pre-defined cookie spec providers, but still the default should work out of the box or? What do you think?
Thanks in advance