- From: Lucas Pardue <lucaspardue.24.7@gmail.com>
- Date: Wed, 18 Dec 2024 11:10:32 +0000
- To: Willy Tarreau <w@1wt.eu>
- Cc: HTTP Working Group <ietf-http-wg@w3.org>, Patrick McManus <mcmanus@ducksong.com>
- Message-ID: <CALGR9oba14Gf++u=hrs7KaQv=h9DK47av8tqe3AAqO1ZRuVGmg@mail.gmail.com>
I also found it funny to observe in the docker documentation the section onn interactive sessions [1], with our old fried h2c upgrade > This endpoint hijacks the HTTP connection to HTTP2 transport that allows the client to expose gPRC services on that connection. RFC 7540 has the following to say about h2c upgrade [2]: > Requests that contain a payload body MUST be sent in their entirety before the client can send HTTP/2 frames. This means that a large request can block the use of the connection until it is completely sent. Anyone got the history about why that text was added? Cheers Lucas [1] https://docs.docker.com/reference/api/engine/version/v1.43/ [2] https://datatracker.ietf.org/doc/html/rfc7540#section-3.2 On Wed, 18 Dec 2024, 10:50 Lucas Pardue, <lucaspardue.24.7@gmail.com> wrote: > Hi Willy, > > Just a brief reply that this sounds like its also related to > draft-ietf-httpbis-optimistic-upgrade [1]. > > Cheers > Lucas > > [1] > https://httpwg.org/http-extensions/draft-ietf-httpbis-optimistic-upgrade.html > > > > On Wed, 18 Dec 2024, 10:33 Willy Tarreau, <w@1wt.eu> wrote: > >> Hi! >> >> RFC8441 ("Bootstrapping WebSockets with HTTP/2") indicates how >> to deal with an Upgrade over HTTP/2. To make it short, HTTP/1's >> Connection+Upgrade->101 becomes a CONNECT+:protocol->200 in H2. >> The RFC specifies a :protocol pseudo-header that allows to use >> the mechanism beyond Websocket. >> >> A while ago, we've implemented the mechanism in haproxy and we >> support the upgrade from H1+Upgrade to H2+CONNECT. So far it >> works fine for our users. >> >> A few months ago we got a report of breakage[1] that unveiled >> something unexpected: given that CONNECT doesn't support a >> request body, we had simplified our support for Upgrade and >> completely rejected any request body at the H1 layer (so that >> we could fail early when not knowing if the output would be in >> H1 or H2). But doing so we accidentally broke support for the >> "Docker Engine API" protocol over H1. That's how we discovered >> that some protocols were relying on POST + Upgrade! (maybe it's >> the only one, I don't know, it was the first report in a few >> years of existence). >> >> Thus, for now we've worked around the problem so that our code >> now rejects the upgrade only on the outgoing H2 side when facing >> a body, but the problem remains that the mechanism proposed by >> RFC8441 doesn't offer provisions for completely transporting H1 >> over H2, nor replacing H1 with H2. Indeed, users of this docker >> engine protocol will need to limit themselves to H1 when talking >> to servers or other proxies. It's a bit sad, and I liked the idea >> of using the semantically-close CONNECT for this. >> >> To me, it looks like the limitations are shared among multiple >> causes: >> - the docker engine API relies on upgrades after a POST, which are >> not much common, and even never mentioned in any of the upgrade >> specs (2817, 7230, 9110), though common sense dictates that it's >> expected to work fine since the client cannot know whether the >> server will accept the upgrade or not. I.e. it's natural to >> think that the server is expected to consume the whole request >> body before upgrading, or at least drain it after rejecting the >> upgrade. >> >> - RFC8441 that proposes to use the CONNECT method for the tunnel, >> while CONNECT itself is defined as "not having content" (9110) >> or "not having semantics" (7231), which looked fine for websocket >> but not necessarily for others (that were not identified by then). >> >> - the use of RFC8441 for non-websocket protocols (but if not usable, >> what could be the point of ":protocol" ?) >> >> I really don't know what could reasonably be done at this point to >> address that incompatibility. Here are a few ideas: >> - we could decide that in the context of RFC8441, CONNECT works a bit >> like GET in that by default the request has no message body unless >> it is explicitly advertised, and in this case the request cannot >> succeed until it's entirely consumed. That sounds quite reasonable >> since this would remove exceptions, and not change anything for >> existing implementations that don't look for that message body. >> That does not solve the situation for request bodies sent using >> chunked encoding however. >> >> - we could imagine a new method that does like CONNECT but also >> covers the message body. Same as above, there are still no >> provisions in H2+ to transmit a chunked body and delimit the >> part that belongs to the request message and the part that >> is to be tunnelled. And I'm personally not convinced about the >> improved interoperability of a new method. >> >> - we could explicitly state that POST+Upgrade is strictly forbidden, >> but we now know it's already in use and working fine for at least >> one implementation. >> >> - or we could do nothing and consider that some parts of HTTP/1 will >> remain HTTP/1 forever and will not be transportable over newer >> versions. I'm not fundamentally against it but it would warrant >> some extra documentation (especially in the H1 related specs) to >> discourage such use so that we make sure no new protocol adopts >> them and stay stuck in a corner. >> >> I'd say that the first approach (tolerating content-length with >> CONNECT when :protocol is used) has my preference. It will not >> permit chunked requests but should cover the vast majority of use >> cases where the server expects a body before deciding to upgrade >> (after all not all HTTP/1 servers support chunked requests either). >> >> But I'm interesting in ideas and opinions others might have. >> >> Thanks! >> Willy >> >> [1] https://github.com/haproxy/haproxy/issues/2684 >> >>
Received on Wednesday, 18 December 2024 11:10:49 UTC