httpx icon indicating copy to clipboard operation
httpx copied to clipboard

HTTP/2 recommends sending multiple `Cookie` headers, rather than folding into a single header.

Open maloibtc opened this issue 4 years ago • 6 comments

How to pass cookies on every new line for http 2.0? This format:

cookie: ss=630755e3b1714d25b1b4533cdc2f975a cookie: s=28365F2FDED92178662D25ED8A05 cookie: lvlid=cd0c27fb94ee7d9f8d6e17324935e3c3

If you do this: cookies = httpx.Cookies. cookies.set ("ss", "630755e3b1714d25b1b4533cdc2f975a") cookies.set ("s", "28365F2FDED92178662D25ED8A05") Then the cookies will be in one cookie string separated by a separator; cookie: ss=630755e3b1714d25b1b4533cdc2f975a; s=28365F2FDED92178662D25ED8A05

maloibtc avatar Aug 23 '20 06:08 maloibtc

Confirmation...

>>> c = httpx.Client()
>>> c.cookies.set("a", "123")
>>> c.cookies.set("b", "456")
>>> r = c.build_request("GET", "https://www.example.com")
>>> r.headers.raw
[
  (b'host', b'www.example.com'),
  (b'user-agent', b'python-httpx/0.14.2'),
  (b'accept', b'*/*'),
  (b'accept-encoding', b'gzip, deflate, br'),
  (b'connection', b'keep-alive'),
  (b'cookie', b'a=123; b=456')
]

tomchristie avatar Aug 24 '20 10:08 tomchristie

Okay, just revising this for myself.

That's expected behaviour. It's only the response Set-Cookie line that needs to be set as multiple headers.

See eg... https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cookie

So my next thought was that our behaviour looks correct here, since Cookie is supposed to fold all the value pairs into a single header.

Had to dig a bit into figuring out what you were expecting to see, and okay right, you're asking specifically about HTTP/2, which recommends a line-by-line style in order to improve compression... https://http2.github.io/http2-spec/#CompressCookie

We're not actually doing anything wrong here, but we might want the HTTP/2 transport to split the Cookie header into multiple lines.

Next thought - I guess it's feasible that h2 does already does this on our behalf, let's check...

Which leads to https://github.com/python-hyper/hyper-h2/issues/497 - and from what I can gather there, nope, there's a fix to handle servers treating things correctly, but on the client side it's up to us to determine which of those two styles to write the request in. (Once again, both are okay, it's just that one is preferred for compression reasons.)

Anyways, upshot of all that. We want the behaviour we're seeing at the client layer above to stay the same. A request might end up over HTTP/1.1, or might end up over HTTP/2, and the single-line format is the right representation to use at that layer.

But our HTTP/2 transport could be smart for us, and actually split that out across multiple headers once we come to sending the request over the wire.

The h2 library could choose to just handle that automatically on our behalf, or it could be our responsibility.

tomchristie avatar Aug 24 '20 10:08 tomchristie

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Feb 20 '22 15:02 stale[bot]

Still valid thx, @stale bot.

tomchristie avatar Feb 21 '22 13:02 tomchristie

Please make this at least configurable, or, ideally, default to "normal" http2 semantics when using http2 - separate cookie headers. Current behavior is atypical http2 behavior. Sure, technically "ok" but still undesirable.

pbkdf3 avatar Aug 20 '22 17:08 pbkdf3

Any workaround?

volnei avatar Oct 18 '22 12:10 volnei

There's two ways around to fix this, either by adapting what headers we send in httpcore, or by fixing up the underlying h2 package.

Here's where we send the headers in httpcore - https://github.com/encode/httpcore/blob/master/httpcore/_async/http2.py#L181-L207

We could adapt that to fold the Cookies headers together.

Alternatively, in h2, incoming cookies are already auto-folded, see... https://python-hyper.org/projects/hyper-h2/en/stable/release-notes.html?highlight=cookie#march-2017 But it doesn't deal with the same behaviour for outgoing cookies.

It probably should.

I had a quick look, and can see that H2Connection.send_headers calls into H2Stream.send_headers, so implementing the fix would be somewhere in there...

https://github.com/python-hyper/h2/blob/63b6b97e691334464a57f933bfd7ed444f364708/src/h2/stream.py#L839

tomchristie avatar Oct 19 '22 10:10 tomchristie

I'll try to add it to h2. TY for pointing the place to start looking

cdeler avatar Dec 27 '22 06:12 cdeler

Let's close this off, since it's resolved in h2 https://github.com/python-hyper/h2/pull/1275 (Although currently unreleased.)

tomchristie avatar Jul 31 '23 16:07 tomchristie