twitter / finagle

A fault tolerant, protocol-agnostic RPC system
https://twitter.github.io/finagle
Apache License 2.0
8.78k stars 1.45k forks source link

`CookieMap#getAll` does not return all values for a given cookie name #909

Closed guilgaly closed 2 years ago

guilgaly commented 3 years ago

Describe the bug The Scaladoc for com.twitter.finagle.http.CookieMap#getAll says that it "Fetches all cookies with the given name from this map.". However it appears to always return only the first value for a cookie name when handling a request and accessing the request cookies.

To Reproduce

  1. Send an HTTP request with a cookie header containing different values for the same name (from a web browser, this will happen if the same cookie name was set with different paths, some more specific than others); e.g. Cookie: FOO=value1; FOO=value2; FOO=value3.
  2. In the server code, retrieve the cookie values with request.cookies.getAll("FOO"); it will return Seq("value1") instead of Seq("value1", "value2", "value3").

Expected behavior I think CookieMap#getAll would be expected to return all values for a given name when several values are given in the request cookies.

Environment For the cookie header format: tested with Chrome 91 on macOS 10.15.7. For Finagle: tested with Finagle 20.3.0 (comes with Finch 0.32.1). Looking at the code for com.twitter.finagle.http.CookieMap and com.twitter.finagle.http.netty4.Netty4CookieCodec in the develop branch, it should still be the same.

Additional context I see two causes for this:

  1. com.twitter.finagle.http.netty4.Netty4CookieCodec#decodeServer calls io.netty.handler.codec.http.cookie.ServerCookieDecoder#decode rather than io.netty.handler.codec.http.cookie.ServerCookieDecoder#decodeAll. According to the Netty Javadoc, decodeAll "includes all cookie values present, even if they have the same name", unlike decode.
  2. If we change 1., then com.twitter.finagle.http.CookieMap#addNoRewrite only keeps the last value added for a given name (that's because of how equality works for com.twitter.finagle.http.Cookie; the cookies would only differ by their paths, and we of course cannot know the paths for the request cookies on the server side).

I'd be happy to try and submit a pull request, if this is in fact not the expected behavior.

yufangong commented 3 years ago

Hi @guilgaly, I agree with you this smells like a bug. Pull requests are welcomed! thanks!

In terms of 2, can you explain a bit more of what would be the behavior change and how it would affect the use of com.twitter.finagle.http.CookieMap#add? Thanks!

guilgaly commented 3 years ago

In terms of 2, can you explain a bit more of what would be the behavior change and how it would affect the use of com.twitter.finagle.http.CookieMap#add? Thanks!

I'd say that the current behavior is correct for a response (it doesn't make sense to set different values for the same combination of name/path/domain; but we can always specify different paths with the same name). So we can't just change the cookie equality to always consider the value (plus it might have other impacts elsewhere).

Maybe the best solution is to just check if message.isRequest in addNoRewrite and have two different behaviors:

yufangong commented 3 years ago

@guilgaly thanks! That sounds like a legit solution. Looks like you are interested in patching this issue, I'll mark this in progress for now. ty!

guilgaly commented 3 years ago

@yufangong I forgot to mention: I opened a PR, and in addition to the above: