Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce new HttpDateTime class for parsing obsolete Date formats in HTTP and Cookie #11648

Closed
richardydhan opened this issue Apr 11, 2024 · 12 comments · Fixed by #11672
Closed
Assignees
Labels
Bug For general bugs on Jetty side Specification For all industry Specifications (IETF / Servlet / etc)

Comments

@richardydhan
Copy link

Jetty version(s)

12

Jetty Environment

core

Java version/vendor (use: java -version)
Oracle jdk 17

OS type/version
RHE 9

Description

2024-04-11T20:23:36.876Z DEBUG 1 --- [ent@3c5044fa-40] o.e.jetty.client.transport.HttpReceiver : Notifying header Set-Cookie: LSKey-c$CookieConsentPolicy=0:1; path=/; expires=Fri, 11-Apr-2025 20:23:36 GMT; Max-Age=31536000; secure
2024-04-11T20:23:36.876Z DEBUG 1 --- [ent@3c5044fa-40] o.e.jetty.http.RFC6265SetCookieParser : could not set attribute expires=Fri

java.time.format.DateTimeParseException: Text 'Fri' could not be parsed at index 0
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2052)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1954)
at java.base/java.time.ZonedDateTime.parse(ZonedDateTime.java:600)
at org.eclipse.jetty.http.HttpCookie.parseExpires(HttpCookie.java:906)
at org.eclipse.jetty.http.HttpCookie$Builder.attribute(HttpCookie.java:542)
at org.eclipse.jetty.http.RFC6265SetCookieParser.setAttribute(RFC6265SetCookieParser.java:200)
at org.eclipse.jetty.http.RFC6265SetCookieParser.parse(RFC6265SetCookieParser.java:186)
at org.cometd.client.transport.HttpClientTransport.lambda$storeCookies$0(HttpClientTransport.java:60)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.cometd.client.transport.HttpClientTransport.lambda$storeCookies$1(HttpClientTransport.java:59)
at java.base/java.util.Map.forEach(Map.java:713)
at org.cometd.client.transport.HttpClientTransport.storeCookies(HttpClientTransport.java:57)
at org.cometd.client.http.jetty.JettyHttpClientTransport.access$000(JettyHttpClientTransport.java:52)
at org.cometd.client.http.jetty.JettyHttpClientTransport$ResponseListener.onHeader(JettyHttpClientTransport.java:239)
at org.eclipse.jetty.client.transport.ResponseListeners.notifyHeader(ResponseListeners.java:129)
at org.eclipse.jetty.client.transport.ResponseListeners.notifyHeader(ResponseListeners.java:121)
at org.eclipse.jetty.client.transport.HttpReceiver.lambda$responseHeader$1(HttpReceiver.java:200)
at org.eclipse.jetty.util.thread.SerializedInvoker$Link.run(SerializedInvoker.java:191)
at org.eclipse.jetty.util.thread.SerializedInvoker.run(SerializedInvoker.java:117)
at org.eclipse.jetty.client.transport.HttpReceiver.responseHeader(HttpReceiver.java:189)
at org.eclipse.jetty.client.transport.internal.HttpReceiverOverHTTP.parsedHeader(HttpReceiverOverHTTP.java:419)
at org.eclipse.jetty.http.HttpParser.parsedHeader(HttpParser.java:1109)
at org.eclipse.jetty.http.HttpParser.parseFields(HttpParser.java:1268)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:1543)
at org.eclipse.jetty.client.transport.internal.HttpReceiverOverHTTP.parse(HttpReceiverOverHTTP.java:312)
at org.eclipse.jetty.client.transport.internal.HttpReceiverOverHTTP.parseAndFill(HttpReceiverOverHTTP.java:250)
at org.eclipse.jetty.client.transport.internal.HttpReceiverOverHTTP.receive(HttpReceiverOverHTTP.java:76)
at org.eclipse.jetty.client.transport.internal.HttpChannelOverHTTP.receive(HttpChannelOverHTTP.java:90)
at org.eclipse.jetty.client.transport.internal.HttpConnectionOverHTTP.onFillable(HttpConnectionOverHTTP.java:194)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:322)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:100)
at org.eclipse.jetty.io.ssl.SslConnection$SslEndPoint.onFillable(SslConnection.java:555)
at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:374)
at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:147)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:100)
at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:478)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:441)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:293)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.run(AdaptiveExecutionStrategy.java:201)
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:311)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:979)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1209)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1164)
at java.base/java.lang.Thread.run(Thread.java:842)

How to reproduce?

@richardydhan richardydhan added the Bug For general bugs on Jetty side label Apr 11, 2024
@joakime
Copy link
Contributor

joakime commented Apr 11, 2024

Your expires format is invalid per Cookie spec.

https://datatracker.ietf.org/doc/html/rfc6265

# you have
expires=Fri, 11-Apr-2025 20:23:36 GMT;

# it should be 
Expires=Fri, 11 Apr 2025 20:23:36 GMT;

There are 2 things.

  1. The attribute name/key is Expires spelled exactly like that.
  2. The value has to follow RFC1123 syntax (see sane-cookie-date format in RFC6265), that means you have to use spaces to separate the day / month / year, not - (dash)

@joakime joakime added the Specification For all industry Specifications (IETF / Servlet / etc) label Apr 11, 2024
@joakime
Copy link
Contributor

joakime commented Apr 11, 2024

Of note, if you used that Expires format on a web browser like Chrome or Firefox you'll have one of two things happen.

  1. The browser can choose to ignore the ENTIRE Set-Cookie attempt due to one failure in a spec attribute.
  2. The browser can choose to ignore the bad Attribute.

Older browsers tended to ignore the Attribute, leaving the reset of the Set-Cookie values set. However, newer browsers will ignore the entire Set-Cookie line due to a long history around cross origin security behaviors.

@gregw
Copy link
Contributor

gregw commented Apr 12, 2024

By the principle of "strict in what you generate and forgiving in what you parse", should be perhaps not throw for a badly formed expires date?

I.e. we should either ignore the attribute or the whole cookie, but not fail entirely.

@richardydhan
Copy link
Author

Your expires format is invalid per Cookie spec.

https://datatracker.ietf.org/doc/html/rfc6265

# you have
expires=Fri, 11-Apr-2025 20:23:36 GMT;

# it should be 
Expires=Fri, 11 Apr 2025 20:23:36 GMT;

There are 2 things.

  1. The attribute name/key is Expires spelled exactly like that.
  2. The value has to follow RFC1123 syntax (see sane-cookie-date format in RFC6265), that means you have to use spaces to separate the day / month / year, not - (dash)

Hi Masters:
Thanks for the responses.
My understanding any valid format should work. It's nice to add a "converter" to convert to the specific format RFC6265 required instead of throwing exceptions.

@joakime
Copy link
Contributor

joakime commented Apr 12, 2024

Looking at various specs for Date / Time, the spec you are using is looking kind like RFC850.

The RFC850 format was deprecated and called obsolete in 1987, replaced by RFC1036.

That being said, the obsolete date format is still listed on the HTTP spec RFC9110.

To support this properly, we would need to add additional parser formats for ...

  • RFC850 - Abbreviated weekday, 2 digit year
  • RFC850 - Abbreviated weekday, 4 digit year
  • RFC850 - Long weekday, 2 digit year
  • RFC850 - Long weekday, 4 digit year
  • asctime format

This will cause quite a hit on performance.
Should probably be configurable behind an HttpCompliance mode.

@sbordet
Copy link
Contributor

sbordet commented Apr 13, 2024

Consider also that JDK has DateTimeFormatter.RFC_1123_DATE_TIME so it is easier to produce the right format.

I would not try to be compliant with specifications that are from 1983, a whopping 41 years ago.
You would expect people to have updated their date formats by now.

@martin8877
Copy link

I have the same problem. Cloudflare send cookies in this format.

expires=Tue, 16-Apr-24 09:53:43 GMT

I would have expected that such a big service like Cloudflare would be sending cookies in the correct format.

Is there any workaround?

@sbordet
Copy link
Contributor

sbordet commented Apr 16, 2024

I'd be surprised if it's CloudFlare.
More likely is the application behind CloudFlare.

@martin8877
Copy link

They are cookies from cloudflare. I have tested __cflb (load balancer session affinity) and __cf_bm (bad bots protection)

@sbordet
Copy link
Contributor

sbordet commented Apr 16, 2024

@martin8877 have you contacted CloudFlare to tell them about this issue?

If so, can you link their issue here?

@joakime
Copy link
Contributor

joakime commented Apr 16, 2024

The cloudflare rest API returns this awful format Set-Cookie expires line.

$ curl -v --http1.1 https://api.cloudflare.com/client/v4/accounts/:account_id/teamnet/routes
[joakim@hyperion ~]$ ^C
[joakim@hyperion ~]$ curl --http1.1 https://api.cloudflare.com/client/v4/accounts/:account_id/teamnet/routes
{"success":false,"errors":[{"code":7003,"message":"Could not route to \/accounts\/:account_id\/teamnet\/routes, perhaps your object identifier is invalid?"},{"code":7000,"message":"No route for that URI"}],"messages":[],"result":null}[joakim@hyperion ~]$ 
[joakim@hyperion ~]$ curl -v --http1.1 https://api.cloudflare.com/client/v4/accounts/:account_id/teamnet/routes
*   Trying 104.19.192.174:443...
* Connected to api.cloudflare.com (104.19.192.174) port 443 (#0)
> GET /client/v4/accounts/:account_id/teamnet/routes HTTP/1.1
> Host: api.cloudflare.com
> User-Agent: curl/7.81.0
> Accept: */*
> 
< HTTP/1.1 400 Bad Request
< Date: Tue, 16 Apr 2024 14:58:26 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Connection: keep-alive
< CF-Ray: 875508940a9d6b04-DFW
< CF-Cache-Status: DYNAMIC
< Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
< Expires: Sun, 25 Jan 1981 05:00:00 GMT
< Set-Cookie: __cflb=0H28vgHxwvgAQtjUGUFqYFDiSDreGJnUtMczKAdAxw7; SameSite=Lax; path=/; expires=Tue, 16-Apr-24 17:28:27 GMT; HttpOnly
< Strict-Transport-Security: max-age=31536000
< pragma: no-cache
< x-content-type-options: nosniff
< x-frame-options: SAMEORIGIN
< Set-Cookie: __cfruid=9b62972ac154f193f138b1438a2dda0852fd6f7e-1713279506; path=/; domain=.api.cloudflare.com; HttpOnly; Secure; SameSite=None
< Server: cloudflare
< 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Connection #0 to host api.cloudflare.com left intact
{"success":false,"errors":[{"code":7003,"message":"Could not route to \/accounts\/:account_id\/teamnet\/routes, perhaps your object identifier is invalid?"},{"code":7000,"message":"No route for that URI"}],"messages":[],"result":null}

@joakime
Copy link
Contributor

joakime commented Apr 16, 2024

Opened PR #11658 as a possible solution.

@joakime joakime self-assigned this Apr 16, 2024
@joakime joakime moved this to 🏗 In progress in Jetty 12.0.9 - FROZEN Apr 16, 2024
@joakime joakime changed the title jetty.http.RFC6265SetCookieParser : could not set attribute expires=Fri Parsing of Set-Cookie Expires attribute does not support obsolete Date formats Apr 17, 2024
joakime added a commit that referenced this issue Apr 19, 2024
+ Introduces HTTP (and Cookie) Date/Time parsing
  according to spec algorithms.
+ Introduces formatting according to spec
  mandated preferred RFC 1123 format.
+ Deprecate DateParser
joakime added a commit that referenced this issue Apr 19, 2024
+ Introduces HTTP (and Cookie) Date/Time parsing
  according to spec algorithms.
+ Introduces formatting according to spec
  mandated preferred RFC 1123 format.
+ Deprecate DateParser
joakime added a commit that referenced this issue Apr 23, 2024
+ Introduces HTTP (and Cookie) Date/Time parsing
  according to spec algorithms.
+ Introduces formatting according to spec
  mandated preferred RFC 1123 format.
+ Deprecate DateParser
@github-project-automation github-project-automation bot moved this from 🏗 In progress to ✅ Done in Jetty 12.0.9 - FROZEN Apr 23, 2024
@joakime joakime changed the title Parsing of Set-Cookie Expires attribute does not support obsolete Date formats Introduce new HttpDateTime class for parsing obsolete Date formats in HTTP and Cookie Apr 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug For general bugs on Jetty side Specification For all industry Specifications (IETF / Servlet / etc)
Projects
No open projects
Status: ✅ Done
5 participants