/* Check if H3 frame of type <ftype> is valid when received on stream <qcs>.
*
- * Returns a boolean. If false, a connection error H3_FRAME_UNEXPECTED should
- * be reported.
+ * Returns 0 if frame valid, otherwise HTTP/3 error code.
*/
-static int h3_is_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype)
+static int h3_check_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype)
{
struct h3s *h3s = qcs->ctx;
+ int ret = 0;
/* Stream type must be known to ensure frame is valid for this stream. */
BUG_ON(h3s->type == H3S_T_UNKNOWN);
switch (ftype) {
case H3_FT_DATA:
- return h3s->type != H3S_T_CTRL && (h3s->st_req == H3S_ST_REQ_HEADERS ||
- h3s->st_req == H3S_ST_REQ_DATA);
+ /* cf H3_FT_HEADERS case. */
+ if (h3s->type == H3S_T_CTRL ||
+ (h3s->st_req != H3S_ST_REQ_HEADERS && h3s->st_req != H3S_ST_REQ_DATA)) {
+ ret = H3_FRAME_UNEXPECTED;
+ }
+
+ break;
case H3_FT_HEADERS:
- return h3s->type != H3S_T_CTRL && h3s->st_req != H3S_ST_REQ_TRAILERS;
+ /* RFC 9114 4.1. HTTP Message Framing
+ *
+ *
+ * An HTTP message (request or response) consists of:
+ * 1. the header section, including message control data, sent as a
+ * single HEADERS frame,
+ * 2. optionally, the content, if present, sent as a series of DATA
+ * frames, and
+ * 3. optionally, the trailer section, if present, sent as a single
+ * HEADERS frame.
+ *
+ * [...]
+ *
+ * Receipt of an invalid sequence of frames MUST be treated as a
+ * connection error of type H3_FRAME_UNEXPECTED. In particular, a DATA
+ * frame before any HEADERS frame, or a HEADERS or DATA frame after the
+ * trailing HEADERS frame, is considered invalid. Other frame types,
+ * especially unknown frame types, might be permitted subject to their
+ * own rules; see Section 9.
+ */
+ if (h3s->type == H3S_T_CTRL || h3s->st_req == H3S_ST_REQ_TRAILERS)
+ ret = H3_FRAME_UNEXPECTED;
+ break;
case H3_FT_CANCEL_PUSH:
case H3_FT_GOAWAY:
case H3_FT_MAX_PUSH_ID:
- /* Only allowed for control stream. First frame of control
- * stream MUST be SETTINGS.
+ /* RFC 9114 7.2.3. CANCEL_PUSH
+ *
+ * A CANCEL_PUSH frame is sent on the control stream. Receiving a
+ * CANCEL_PUSH frame on a stream other than the control stream MUST be
+ * treated as a connection error of type H3_FRAME_UNEXPECTED.
*/
- return h3s->type == H3S_T_CTRL &&
- (h3c->flags & H3_CF_SETTINGS_RECV);
+
+ /* RFC 9114 7.2.6. GOAWAY
+ *
+ * A client MUST treat a GOAWAY frame on a stream other than the
+ * control stream as a connection error of type H3_FRAME_UNEXPECTED.
+ */
+
+ /* RFC 9114 7.2.7. MAX_PUSH_ID
+ *
+ * The MAX_PUSH_ID frame is always sent on the control stream. Receipt
+ * of a MAX_PUSH_ID frame on any other stream MUST be treated as a
+ * connection error of type H3_FRAME_UNEXPECTED.
+ */
+
+ if (h3s->type != H3S_T_CTRL)
+ ret = H3_FRAME_UNEXPECTED;
+ else if (!(h3c->flags & H3_CF_SETTINGS_RECV))
+ ret = H3_MISSING_SETTINGS;
+ break;
case H3_FT_SETTINGS:
- /* draft-ietf-quic-http34 7.2.4. SETTINGS
+ /* RFC 9114 7.2.4. SETTINGS
+ *
+ * A SETTINGS frame MUST be sent as the first frame of
+ * each control stream (see Section 6.2.1) by each peer, and it MUST NOT
+ * be sent subsequently. If an endpoint receives a second SETTINGS frame
+ * on the control stream, the endpoint MUST respond with a connection
+ * error of type H3_FRAME_UNEXPECTED.
*
- * If an endpoint receives a second SETTINGS frame on the control
+ * SETTINGS frames MUST NOT be sent on any stream other than the control
+ * stream. If an endpoint receives a SETTINGS frame on a different
* stream, the endpoint MUST respond with a connection error of type
* H3_FRAME_UNEXPECTED.
*/
- return h3s->type == H3S_T_CTRL &&
- !(h3c->flags & H3_CF_SETTINGS_RECV);
+ if (h3s->type != H3S_T_CTRL || h3c->flags & H3_CF_SETTINGS_RECV)
+ ret = H3_FRAME_UNEXPECTED;
+ break;
case H3_FT_PUSH_PROMISE:
/* RFC 9114 7.2.5. PUSH_PROMISE
+ *
* A client MUST NOT send a PUSH_PROMISE frame. A server MUST treat the
* receipt of a PUSH_PROMISE frame as a connection error of type
* H3_FRAME_UNEXPECTED.
*/
/* TODO server-side only. */
- return 0;
+ ret = H3_FRAME_UNEXPECTED;
+ break;
default:
- /* draft-ietf-quic-http34 9. Extensions to HTTP/3
+ /* RFC 9114 9. Extensions to HTTP/3
*
- * Implementations MUST discard frames [...] that have unknown
- * or unsupported types.
+ * Implementations MUST ignore unknown or unsupported values in all
+ * extensible protocol elements. [...]
+ * However, where a known frame type is required to be in a
+ * specific location, such as the SETTINGS frame as the first frame of
+ * the control stream (see Section 6.2.1), an unknown frame type does
+ * not satisfy that requirement and SHOULD be treated as an error.
*/
- return h3s->type != H3S_T_CTRL || (h3c->flags & H3_CF_SETTINGS_RECV);
+ if (h3s->type == H3S_T_CTRL && !(h3c->flags & H3_CF_SETTINGS_RECV))
+ ret = H3_MISSING_SETTINGS;
+ break;
}
+
+ return ret;
}
/* Check from stream <qcs> that length of all DATA frames does not exceed with
break;
}
- if (!h3_is_frame_valid(h3c, qcs, ftype)) {
+ if ((ret = h3_check_frame_valid(h3c, qcs, ftype))) {
TRACE_ERROR("received an invalid frame", H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
- qcc_set_error(qcs->qcc, H3_FRAME_UNEXPECTED, 1);
+ qcc_set_error(qcs->qcc, ret, 1);
goto err;
}