Subject: [quicwg/base-drafts] http deadlock with stream FIN choices (#1972)

From: martinduke <[email-masked]>
Date: Tue, 06 Nov 2018 00:17:31 -0800

During interop, I couldn't interop with winquic because I never FIN my request stream, and winquic doesn't serve the response until the request FINs.

My conversation with @MikeBishop suggests that both of us are behaving legally, which is a problem. We should either force clients to FIN (allowing servers to wait for it) or not (not). I don't particularly care which.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972

---

From: Nick Banks <[email-masked]>
Date: Tue, 06 Nov 2018 00:25:36 -0800

This isn't really a spec issue, as this 0.9 HTTP design we have had for interop is not explicitly written anywhere. It has been a defacto requirement since the interop 2 or 3 to FIN your HTTP requests.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-436169090

---

From: martinduke <[email-masked]>
Date: Tue, 06 Nov 2018 00:27:28 -0800

I'm referring to HTTP/3, although it came up in a 0.9 interop. I don't believe there is any requirement in the draft for clients to FIN their requests in a timely fashion.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-436169551

---

From: afrind <[email-masked]>
Date: Tue, 06 Nov 2018 00:43:33 -0800

HTTP/2 doesn't require a client FIN before the server will process the request, but you do need one to complete the stream state machine.  I think HQ/H3 should be the same.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-436173765

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 06 Nov 2018 01:20:16 -0800

I agree with @nibanks.

HTTP/0.9 has two ways of terminating a request: CRLF and a FIN. HTTP/1 introduced the concept of request body along with a `content-length` request header field that allows a server to detect the end of the request _without_ using FIN.

It is not the case with H2, where END_STREAM is the only way to terminate a request. I'd assume that that is the same with H3.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-436184007

---

From: Ryan Hamilton <[email-masked]>
Date: Tue, 06 Nov 2018 07:14:51 -0800

It seems quite reasonable for servers to wait for the FIN before sending
the response. As such it seems like requiring the client FIN the request to
avoid deadlock makes sense to me.

On Tue, Nov 6, 2018 at 1:20 AM, Kazuho Oku <[email-masked]> wrote:

> I agree with @nibanks <https://github.com/nibanks>.
>
> HTTP/0.9 has two ways of terminating a request: CRLF and a FIN. HTTP/1
> introduced the concept of request body along with a content-length
> request header field that allows a server to detect the end of the request
> *without* using FIN.
>
> It is not the case with H2, where END_STREAM is the only way to terminate
> a request. I'd assume that that is the same with H3.
>
> —
> Reply to this email directly, view it on GitHub
> <https://github.com/quicwg/base-drafts/issues/1972#issuecomment-436184007>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/ASp6ymtvyKrIGgQV76RCqI8uVeoFAbuAks5usVRPgaJpZM4YP8rZ>
> .
>

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-436287934

---

From: Lucas Pardue <[email-masked]>
Date: Tue, 06 Nov 2018 16:08:44 +0000 (UTC)

Forcing client to FIN doesn't work because of things like CONNECT.

Section 3.1.2 of HTTP/QUIC says:

> A CONNECT request in HTTP/QUIC functions in the same manner as in HTTP/2. The request MUST be formatted as described in [RFC7540], Section 8.3. A CONNECT request that does not conform to these restrictions is malformed. The request stream MUST NOT be half-closed at the end of the request.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-436308788

---

From: Nick Banks <[email-masked]>
Date: Tue, 06 Nov 2018 09:10:11 -0800

Let's not take this discussion too far. All we are talking about is the simple HTTP 0.9 interop protocol we are currently using. We aren't talking HQ/H3. There is nothing but GET and a response body for the current interop. The (unofficial) requirements throughout interop have always been to FIN the request.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-436331663

---

From: Lucas Pardue <[email-masked]>
Date: Tue, 06 Nov 2018 09:30:03 -0800

OK that makes sense. As you point out in the 2nd comment @nibanks this isn't really a spec issue, this was a subtlety I missed when skimming.

As someone that doesn't do interop, raising issues specific to it (and not the core documents) is awfully confusing. Especially so in future when search engine crawlers bring up old discussions as new implementers jump on board to build HTTP/QUIC software.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-436338486

---

From: MikkelFJ <[email-masked]>
Date: Tue, 06 Nov 2018 10:05:30 -0800

@nibanks Martin D. says it is concerning H3 in a comment in the above and he is OP.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-436350183

---

From: Nick Banks <[email-masked]>
Date: Tue, 06 Nov 2018 10:10:58 -0800

Ok. Then I think we shouldn't be conflating the two issues of HTTP 0.9 interoperability issues and HQ/H3 design. I'm perfectly fine dedicating the rest of this issue to HQ/H3. For interop, the client FINs the 0.9 request.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-436352057

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 06 Nov 2018 15:31:47 -0800

Re HQ, I think we have a clear definition. [Section 5.1](
https://quicwg.org/base-drafts/draft-ietf-quic-http.html#rfc.section.5.1) states that:
> An HTTP request/response exchange fully consumes a bidirectional QUIC stream. After sending a request, a client closes the stream for sending; after sending a final response, the server closes the stream for sending and the QUIC stream is fully closed. Requests and responses are considered complete when the corresponding QUIC stream is closed in the appropriate direction.

I would interpret this statement that it is OK to use FIN as the way to determine the end of a HTTP request.

FWIW, this follows what we have had for H2 in [RFC 7540 section 8.1](
https://httpwg.org/specs/rfc7540.html#rfc.section.8.1).

Re CONNECT case that @LPardue points out, my understanding is that is considered either as an exception or that CONNECT elicits an early response.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-436448098

---

From: Mike Bishop <[email-masked]>
Date: Tue, 06 Nov 2018 18:43:22 -0800

> An HTTP request/response exchange fully consumes a bidirectional QUIC stream. After sending a request, a client closes the stream for sending; after sending a final response, the server closes the…

There's no normative language, but there's an expectation that the closure will happen at the end of the request.  CONNECT is different, as noted, and (if you support CONNECT, at the very least), you have to look at the request to determine whether to expect it to be closed.

In the opposite direction, we say:
> Changes to the state of a request stream, including receiving a QUIC RESET_STREAM with any error code, do not affect the state of the server’s response.

While this text is targeted at streams being reset or FIN'd *before* the request finishes, this could reasonably be interpreted/expanded to say that servers also cannot rely upon the FIN for finding the end of the request.  I suspect that you need to process a complete request regardless of whether the stream has closed or not.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-436484647

---

From: martinduke <[email-masked]>
Date: Tue, 06 Nov 2018 21:22:34 -0800

I apologize for giving the impression that I care about 0.9 at all with respect to the draft. As @MikeBishop says, the issue is filed about HTTP/3.

@MikeBishop Can you file a PR for whatever changes you think are needed?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-436508460

---

From: Mike Bishop <[email-masked]>
Date: Wed, 14 Nov 2018 12:09:30 -0800

@RyanAtGoogle points out that Content-Length isn't mandatory, and when absent, end-of-stream is the only way to identify the end of the body.  So perhaps we need to be having a more granular conversation here:  You have to process headers (and discover whether you're expecting a body) without waiting for the body to arrive.

If you expect a body and the length is given, read that many bytes.  If you expect a body of unknown size, then and only then do you use end-of-stream as a signal.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-438801077

---

From: Dmitri Tikhonov <[email-masked]>
Date: Wed, 14 Nov 2018 13:32:56 -0800

Why shouldn't HTTP/3 behave the same way with regard to EOS as HTTP/2 and HTTP/1.x do?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-438826373

---

From: David Schinazi <[email-masked]>
Date: Wed, 14 Nov 2018 13:56:08 -0800

@dtikhonov Because this is an opportunity to improve the status quo, like we did for TLS 1.3. Since implementors need to at least look at their EOS handling when transitioning from h2 to h3, now would be a good time to clarify the expected behavior.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-438833275

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 14 Nov 2018 22:11:39 +0000 (UTC)

While I agree that clarifying what endpoints *would* do is a good thing, I am not sure if we need to diverge from the model we have in HTTP/2.

In HTTP/2, end of a message was EOS, with the only exception being the `CONNECT` method. IIRC that was an intentional choice; that's one of the reasons [RFC 8441](https://httpwg.org/specs/rfc8441.html) uses `CONNECT` instead of `GET` when opening a WebSocket channel.

At the same time, we have allowed the endpoints to start processing parts of the message as they arrive (e.g., early response, progressive rendering of responses).

I do not see a reason to change the model in HTTP/3, and therefore my preference goes to retaining the same model in order to reduce the differences between different HTTP versions as well as maximizing the chance to reuse extensions.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-438837913

---

From: David Schinazi <[email-masked]>
Date: Wed, 14 Nov 2018 15:00:52 -0800

Ah, I got confused between [http-core issue 22](https://github.com/httpwg/http-core/issues/22) and this one, apologies. I just had an opinion on clarifying that closing one half of a stream does not imply closing both sides. I agree that EOS should be the end of a message.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-438851457

---

From: Ryan Hamilton <[email-masked]>
Date: Wed, 14 Nov 2018 16:13:48 -0800

I agree with @kazuho and @dtikhonov I don't see a good reason to diverge from HTTP/2's model here where end of stream ends the message (and "A request or response is also malformed if the value of a content-length header field does not equal the sum of the DATA frame payload lengths that form the body".)

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-438866959

---

From: Mike Bishop <[email-masked]>
Date: Wed, 14 Nov 2018 16:52:05 -0800

In part because in HTTP/2 end-of-stream wasn't a separate thing -- it was a flag on the final header block or DATA frame.  You couldn't end a stream elsewhere (though the workaround was a zero-length DATA frame with END_STREAM set).

In a more abstract sense, there are HTTP messages which aren't sent atomically -- they develop over time, and have to be handled in a streaming fashion.  These might be streamed responses -- or requests, for a POST or a strained protocol adaptation.  CONNECT fits into this category, since the "message body" and the "response body" are essentially infinite, and in HTTP/1.1 it was unique in being totally unframed.  In HTTP/2, though, pseudo-chunked messages work exactly the same way.

To frame it differently, I don't have a problem with saying that EOS is the end of the message; I have a problem with the implication that you can wait for the entire message to arrive before you begin processing it.  *That's* the original incompatible bug that started this issue.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-438874606

---

From: Dmitri Tikhonov <[email-masked]>
Date: Wed, 14 Nov 2018 18:50:44 -0800

> [...] I have a problem with the implication that you can wait for the entire message to arrive before you begin processing it. _That's_ the original incompatible bug that started this issue.

> During interop, I couldn't interop with winquic because I never FIN my request stream, and winquic doesn't serve the response until the request FINs.

Plus, it really depends on the type of the request? For example, if one is to calculate MD5 sum of the request body and return it as response body (something we did during last interop), one must wait for FIN. An echo-type service (another interop example) must process request body immediately (echo it back) and does not have to wait for FIN.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-438897761

---

From: Ryan Hamilton <[email-masked]>
Date: Wed, 14 Nov 2018 19:45:01 -0800

On Wed, Nov 14, 2018 at 6:50 PM, Dmitri Tikhonov <[email-masked]>
wrote:

> [...] I have a problem with the implication that you can wait for the
> entire message to arrive before you begin processing it. *That's* the
> original incompatible bug that started this issue.
>
> During interop, I couldn't interop with winquic because I never FIN my
> request stream, and winquic doesn't serve the response until the request
> FINs.
>
> From the subsequent discussion the request did not have a content-length,
there would be no way for the request to be complete without a FIN and as
such, I would argue, a server would be perfectly well behaved to wait until
the FIN arrives before it processed the request. Mike, would you agree with
this?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#issuecomment-438906962

---

From: Mike Bishop <[email-masked]>
Date: Wed, 28 Nov 2018 18:29:50 +0000 (UTC)

Closed #1972 via #2003.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/1972#event-1993246871