Subject: [quicwg/base-drafts] HTTP/3: Conflicting error codes for DATA frame on control stream (#4842)

From: Dmitri Tikhonov <[email-masked]>
Date: Wed, 17 Mar 2021 06:18:51 -0700

When a _DATA_ frame is received as the first frame on the control stream, [HTTP/3 ID-34](https://tools.ietf.org/html/draft-ietf-quic-http-34) mandates two different error codes:

Section 6.2.1:

```
   Each side MUST initiate a single control stream at the beginning of
   the connection and send its SETTINGS frame as the first frame on this
   stream.  If the first frame of the control stream is any other frame
   type, this MUST be treated as a connection error of type
   H3_MISSING_SETTINGS.
```

Section 7.2.1:

```
   DATA frames MUST be associated with an HTTP request or response.  If
   a DATA frame is received on a control stream, the recipient MUST
   respond with a connection error of type H3_FRAME_UNEXPECTED;
```

(Found by @kazu-yamamoto's `h3spec` tool while testing [lsquic](https://github.com/litespeedtech/lsquic).)

-- 
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/4842

---

From: Lucas Pardue <[email-masked]>
Date: Wed, 17 Mar 2021 06:32:57 -0700

Seems fine to me. Its always an error to send DATA on a control stream. There's a precedence between the two conditions, if we try to articulate that in every case the text could become quite unwieldy.

There is a precedence between betwe

-- 
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/4842#issuecomment-801083189

---

From: Mike Bishop <[email-masked]>
Date: Thu, 18 Mar 2021 07:42:40 -0700

I don't feel the need to address this.  There are multiple situations in which a particular behavior can be wrong in more than one way, and it's implementation-dependent which failure it notices and errors on first.  @quicwg/chairs, does this need any process, as this is a design question?

-- 
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/4842#issuecomment-801985042

---

From: Lucas Pardue <[email-masked]>
Date: Thu, 18 Mar 2021 07:52:22 -0700

I'm not seeing any compelling reason to challenge a design principle. In this case specifically there's never a reason to send DATA on control streams, 

 We try to make it clear that endpoints shouldn't read too much into the specific error codes that they get and in this case the error is terminal for the connection, so there's not much the offender can do when it receives an error.

-- 
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/4842#issuecomment-801992409

---

From: Dmitri Tikhonov <[email-masked]>
Date: Thu, 18 Mar 2021 09:21:48 -0700

Responses along the lines of "a behavior may be wrong in more than one way" and "endpoints should not read too much into error codes" go against the spirit of the specification, with its registry of error codes and big bold **MUST** pronouncements about which error code is to be used under which circumstances.  It's inconsistent: what's the point of all the error codes, then, if we allow an implementation just to pick one of the error codes (as in this example)?  This is not a rhetorical question.

>From the application perspective, how is a spec-verification tool, such as `h3spec`, to deal with this ambiguity?

-- 
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/4842#issuecomment-802063532

---

From: Lucas Pardue <[email-masked]>
Date: Thu, 18 Mar 2021 10:16:48 -0700

> Responses along the lines of "a behavior may be wrong in more than one way" and "endpoints should not read too much into error codes" go against the spirit of the specification,

Not really. Section 8 is pretty clear: Stream errors can be upgraded to connection errors and any error condition can be reported as H3_GENERAL_PROTOCOL_ERROR if the implementation chooses to do so.

> with its registry of error codes and big bold MUST pronouncements about which error code is to be used under which circumstances. It's inconsistent: what's the point of all the error codes, then, if we allow an implementation just to pick one of the error codes (as in this example)? This is not a rhetorical question.

the MUST applies to how to treat the event of a protocol violation - must close the connection. Error codes are a nice feature on the top - users of HTTP/3 should be entirely prepared for them to be used wrongly.

In this specific case, it sounds like you're asking for something like a blanket requirement for every frame that cannot be sent on the control stream to say something like

> If a <non-control-stream> frame is received on a control stream, the recipient MUST respond with a connection error. The type of error depends on the state of the control stream. If the receiver has not processed a SETTINGS frame, the error code MUST be H3_MISSING_SETTINGS. If the receiver has process a SETTINGS frame, the error code MUST be H3_FRAME_UNEXPECTED.

As @MikeBishop points out, this can be viewed as a design change for implementations that don't follow the guidance exactly like that. I think its too late to revisit this because there is no interoperability or security issues associated with the current design.

> From the application perspective, how is a spec-verification tool, such as h3spec, to deal with this ambiguity?

Since such tools have to accommodate any error condition being a connection error, and any error type being a  H3_GENERAL_PROTOCOL_ERROR, my advise is that they validate error test cases as so:

1. Did stream or connection error occur?
2. Did error type contain one of the set of error codes (H3_GENERAL_PROTOCOL_ERROR, more-specfic error code, ...)

-- 
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/4842#issuecomment-802137827

---

From: Martin Thomson <[email-masked]>
Date: Thu, 18 Mar 2021 16:34:50 -0700

The first clause in this general guidance (in transport, but it should apply to h3 well enough) would seem to make this question moot:

>  In particular, an endpoint MAY use any applicable error code when it detects an error condition; a generic error code (such as PROTOCOL_VIOLATION or INTERNAL_ERROR) can always be used in place of specific error codes.

Indeed, this exact kind of situation is what motivated the inclusion of this text.  These debates are commonplace and waste a lot of time and they also place unnatural constraints on implementations.  What an implementation does here might determine which code is reported and that is OK.  Both codes are applicable.  Reporting either achieves the ultimate goal, which is identifying a bug.  Forcing a choice only leads to wasteful discussions like this one.

The answer is that `h3spec` should accept either error code as valid in this case.  In addition to any generally applicable codes.

-- 
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/4842#issuecomment-802386417

---

From: Kazu Yamamoto <[email-masked]>
Date: Thu, 18 Mar 2021 18:04:52 -0700

Talking about `h3spec`. It is possible to change the test case for Sec 6.2.1 to also accept 3_FRAME_UNEXPECTED. But I changed it to use MAX_PUSH_ID instead of DATA:

https://github.com/kazu-yamamoto/h3spec/commit/2d74a59b5a1a8fe50a96d7b5e3fc01952ea22a2c

-- 
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/4842#issuecomment-802430976