httpx
httpx copied to clipboard
HTTP/2 recommends sending multiple `Cookie` headers, rather than folding into a single header.
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
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')
]
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.
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.
Still valid thx, @stale bot.
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.
Any workaround?
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
I'll try to add it to h2
. TY for pointing the place to start looking
Let's close this off, since it's resolved in h2
https://github.com/python-hyper/h2/pull/1275
(Although currently unreleased.)