Skip to content

Conversation

@jduo
Copy link
Member

@jduo jduo commented Oct 30, 2020

Add a ClientMiddleware that can read HTTP Set-Cookie and Set-Cookie2 headers
from server responses and transmit corresponding Cookie headers

@github-actions
Copy link

Copy link
Member

@lidavidm lidavidm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks straightforward. Just a comment about the implementation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the middleware is instantiated per call, so to have persistent cookie values across multiple calls, you actually want this map to be part of the Factory.

Also, FlightClient can handle concurrent calls, so this should be a ConcurrentHashMap.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I'll add an end-to-end test for persistence too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we actually expect to see this header, as it's deprecated?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really. This isn't supported by any major browsers now: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie2 .

It's there for completeness, but given it's buggy in the JDK, let's remove Set-cookie2 handling.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed Set-Cookie2 support.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calculate seems to imply that we are generating new cookies here but we are just joining existing cookie strings?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Add a ClientMiddleware that can read HTTP Set-Cookie and Set-Cookie2 headers
from server responses and transmit corresponding Cookie headers
Keerat Singh and others added 4 commits November 3, 2020 16:02
- Remove COOKIE2_HEADER
- Store cookies in the concurrent hashmap in the factory for persistance.
- Added end to end test for cookie persistence
- Fixed test cookieStaysAfterMultipleRequestsEndToEnd.
- Cleanup TestCookieHandling resources.
- Update TestCookieHandling to use the test Factory with the ability to intercept the returned ClientCookieMiddleware.
@lidavidm
Copy link
Member

lidavidm commented Nov 5, 2020

Just to link things: #8572 is implementing support for arbitrary headers, perhaps we should think about if cookies should build on top of that support.

@jduo
Copy link
Member Author

jduo commented Nov 5, 2020

Just to link things: #8572 is implementing support for arbitrary headers, perhaps we should think about if cookies should build on top of that support.

I'm leaning towards keeping this as just middleware and not involving CallOptions. #8572 is for letting the client arbitrarily add headers at the time of a request, whereas cookie-headers aren't arbitrary and should be automatically sent. The checking of expiration should also be automatic.

We could rework this patch to have a subclass of HeaderCallOption that lazily retrieves the cookie header from the cookie middleware during wrapStub, but I feel this is more difficult/error-prone for app-developers.

@lidavidm
Copy link
Member

lidavidm commented Nov 6, 2020

I'm leaning towards keeping this as just middleware and not involving CallOptions.

Sounds good to me.

// The server can also update a cookie to have an Expiry in the past or negative age
// to signal that the client should stop using the cookie immediately.
final Consumer<String> handleSetCookieHeader = (headerValue) -> {
final List<HttpCookie> parsedCookies = HttpCookie.parse(headerValue);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we handle IllegalArgumentException here from HttpCookie.parse?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also instead of a lambda it may be clearer to define Factory#updateFromSetCookieHeader or something like that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

cookieMiddleware.onHeadersReceived(headersToSend);

// Verify that the k cookie was discarded because the server told the client it is expired.
Assert.assertTrue(cookieMiddleware.getValidCookiesAsString().isEmpty());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems this test doesn't always succeed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I looked into this and found that on my Mac, the JDK explicitly checks if Max-Age == -1 (MAX_AGE_UNSPECIFIED), treat the max age as unset.
In the OpenJDK 11 source code though, they treat any negative number as max age unset:
https://github.com/openjdk/jdk11u-dev/blob/75a42602826c32a1053b10188ec3826eb9c0c898/src/java.base/share/classes/java/net/HttpCookie.java#L236

The RFC states that 0, and any value less than zero is supposed to be treated as immediately expired.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a note about this in ClientCookieMiddleware's class description.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! That's fun. Do you think it's worth filing a JDK bug? Though I'm surprised it's been around so long.

Assert.assertEquals("k=\"v\"", cookieMiddleware.getValidCookiesAsString());

try {
Thread.sleep(5000);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a little icky, though it appears there's no way to mock time for HttpCookie.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll mark this test as @ignore, since this is essentially just testing that we call isExpired correctly, which we do in the max-age -2 test.

cookieMiddleware.onHeadersReceived(headersToSend);

// Verify that the k cookie was discarded because the server told the client it is expired.
Assert.assertTrue(cookieMiddleware.getValidCookiesAsString().isEmpty());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! That's fun. Do you think it's worth filing a JDK bug? Though I'm surprised it's been around so long.

@lidavidm
Copy link
Member

lidavidm commented Nov 6, 2020

Will merge on green.

@lidavidm lidavidm closed this in 47f2e0c Nov 6, 2020
pribor pushed a commit to GlobalWebIndex/arrow that referenced this pull request Oct 24, 2025
Add a ClientMiddleware that can read HTTP Set-Cookie and Set-Cookie2 headers
from server responses and transmit corresponding Cookie headers

Closes apache#8554 from jduo/cookie-handling

Lead-authored-by: James Duong <[email protected]>
Co-authored-by: Keerat Singh <[email protected]>
Co-authored-by: Keerat Singh <[email protected]>
Signed-off-by: David Li <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants