Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 23 additions & 25 deletions .duvet/snapshot.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ SPECIFICATION: https://www.rfc-editor.org/rfc/rfc9114
TEXT[!MUST,todo]: PUSH_PROMISE frames are not permitted on push streams;
TEXT[!MUST,todo]: a pushed response that includes PUSH_PROMISE frames MUST be treated
TEXT[!MUST,todo]: as a connection error of type H3_FRAME_UNEXPECTED.
TEXT[!MAY,todo]: Frames of unknown types (Section 9), including reserved frames
TEXT[!MAY,todo]: (Section 7.2.8) MAY be sent on a request or push stream before,
TEXT[!MAY,todo]: after, or interleaved with other frames described in this section.
TEXT[!MAY,implementation,test]: Frames of unknown types (Section 9), including reserved frames
TEXT[!MAY,implementation,test]: (Section 7.2.8) MAY be sent on a request or push stream before,
TEXT[!MAY,implementation,test]: after, or interleaved with other frames described in this section.
TEXT[!MUST,todo]: Transfer codings (see Section 7 of [HTTP/1.1]) are not defined for
TEXT[!MUST,todo]: HTTP/3; the Transfer-Encoding header field MUST NOT be used.
TEXT[!MAY,todo]: A response MAY consist of multiple messages when and only when one or
Expand Down Expand Up @@ -170,12 +170,12 @@ SPECIFICATION: https://www.rfc-editor.org/rfc/rfc9114
TEXT[!MUST,exception]: Intermediaries that process HTTP requests or responses (i.e., any
TEXT[!MUST,exception]: intermediary not acting as a tunnel) MUST NOT forward a malformed
TEXT[!MUST,exception]: request or response.
TEXT[!MUST,implementation,todo]: Malformed requests or responses that are
TEXT[!MUST,implementation,todo]: detected MUST be treated as a stream error of type H3_MESSAGE_ERROR.
TEXT[!MUST,implementation]: Malformed requests or responses that are
TEXT[!MUST,implementation]: detected MUST be treated as a stream error of type H3_MESSAGE_ERROR.
TEXT[!MAY,todo]: For malformed requests, a server MAY send an HTTP response indicating
TEXT[!MAY,todo]: the error prior to closing or resetting the stream.
TEXT[!MUST,todo]: Clients MUST NOT
TEXT[!MUST,todo]: accept a malformed response.
TEXT[!MUST,implementation,todo]: Clients MUST NOT
TEXT[!MUST,implementation,todo]: accept a malformed response.

SECTION: [HTTP Fields](#section-4.2)
TEXT[!MUST,todo]: Characters in field names MUST be
Expand Down Expand Up @@ -223,13 +223,13 @@ SPECIFICATION: https://www.rfc-editor.org/rfc/rfc9114
TEXT[!MUST,implication]: appear in requests.
TEXT[!MUST,implementation]: Pseudo-header fields MUST NOT appear in trailer
TEXT[!MUST,implementation]: sections.
TEXT[!MUST,todo]: Endpoints MUST treat a request or response that contains
TEXT[!MUST,todo]: undefined or invalid pseudo-header fields as malformed.
TEXT[!MUST,implementation,test]: Endpoints MUST treat a request or response that contains
TEXT[!MUST,implementation,test]: undefined or invalid pseudo-header fields as malformed.
TEXT[!MUST,implementation]: All pseudo-header fields MUST appear in the header section before
TEXT[!MUST,implementation]: regular header fields.
TEXT[!MUST,todo]: Any request or response that contains a
TEXT[!MUST,todo]: pseudo-header field that appears in a header section after a regular
TEXT[!MUST,todo]: header field MUST be treated as malformed.
TEXT[!MUST,implementation,test]: Any request or response that contains a
TEXT[!MUST,implementation,test]: pseudo-header field that appears in a header section after a regular
TEXT[!MUST,implementation,test]: header field MUST be treated as malformed.

SECTION: [Request Pseudo-Header Fields](#section-4.3.1)
TEXT[!MUST,todo]: The authority MUST NOT include the
Expand Down Expand Up @@ -463,9 +463,9 @@ SPECIFICATION: https://www.rfc-editor.org/rfc/rfc9114
TEXT[!MUST,todo]: However, stream types that could modify the state or
TEXT[!MUST,todo]: semantics of existing protocol components, including QPACK or other
TEXT[!MUST,todo]: extensions, MUST NOT be sent until the peer is known to support them.
TEXT[!MUST,implementation,todo]: A receiver MUST tolerate unidirectional streams being
TEXT[!MUST,implementation,todo]: closed or reset prior to the reception of the unidirectional stream
TEXT[!MUST,implementation,todo]: header.
TEXT[!MUST,implementation]: A receiver MUST tolerate unidirectional streams being
TEXT[!MUST,implementation]: closed or reset prior to the reception of the unidirectional stream
TEXT[!MUST,implementation]: header.

SECTION: [Control Streams](#section-6.2.1)
TEXT[!MUST,implementation]: Each side MUST initiate a single control stream at the beginning of
Expand Down Expand Up @@ -715,13 +715,11 @@ SPECIFICATION: https://www.rfc-editor.org/rfc/rfc9114
TEXT[implication]: types be ignored (Section 9).
TEXT[!MAY,implication]: These frames have no semantics, and
TEXT[!MAY,implication]: they MAY be sent on any stream where frames are allowed to be sent.
TEXT[!MUST,implementation,todo]: Endpoints MUST
TEXT[!MUST,implementation,todo]: NOT consider these frames to have any meaning upon receipt.
TEXT[todo]: Frame types that were used in HTTP/2 where there is no corresponding
TEXT[todo]: HTTP/3 frame have also been reserved (Section 11.2.1).
TEXT[!MUST,implementation,todo]: These frame
TEXT[!MUST,implementation,todo]: types MUST NOT be sent, and their receipt MUST be treated as a
TEXT[!MUST,implementation,todo]: connection error of type H3_FRAME_UNEXPECTED.
TEXT[!MUST,implementation]: Endpoints MUST
TEXT[!MUST,implementation]: NOT consider these frames to have any meaning upon receipt.
TEXT[!MUST,implementation]: These frame
TEXT[!MUST,implementation]: types MUST NOT be sent, and their receipt MUST be treated as a
TEXT[!MUST,implementation]: connection error of type H3_FRAME_UNEXPECTED.

SECTION: [Error Handling](#section-8)
TEXT[!MAY,todo]: An endpoint MAY choose to treat a stream error as a connection error
Expand All @@ -742,9 +740,9 @@ SPECIFICATION: https://www.rfc-editor.org/rfc/rfc9114
SECTION: [Extensions to HTTP/3](#section-9)
TEXT[!MUST,todo]: Implementations MUST ignore unknown or unsupported values in all
TEXT[!MUST,todo]: extensible protocol elements.
TEXT[!MUST,todo]: Implementations MUST discard data or
TEXT[!MUST,todo]: abort reading on unidirectional streams that have unknown or
TEXT[!MUST,todo]: unsupported types.
TEXT[!MUST,implementation]: Implementations MUST discard data or
TEXT[!MUST,implementation]: abort reading on unidirectional streams that have unknown or
TEXT[!MUST,implementation]: unsupported types.
TEXT[!SHOULD,todo]: However, where a known frame type is required to be in
TEXT[!SHOULD,todo]: a specific location, such as the SETTINGS frame as the first frame of
TEXT[!SHOULD,todo]: the control stream (see Section 6.2.1), an unknown frame type does
Expand Down
6 changes: 0 additions & 6 deletions .duvet/todos/rfc9114/4.1.2.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
target = "https://www.rfc-editor.org/rfc/rfc9114#section-4.1.2"

[[TODO]]
quote = '''
Malformed requests or responses that are
detected MUST be treated as a stream error of type H3_MESSAGE_ERROR.
'''

[[TODO]]
quote = '''
For malformed requests, a server MAY send an HTTP response indicating
Expand Down
7 changes: 0 additions & 7 deletions .duvet/todos/rfc9114/4.1.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,6 @@ a pushed response that includes PUSH_PROMISE frames MUST be treated
as a connection error of type H3_FRAME_UNEXPECTED.
'''

[[TODO]]
quote = '''
Frames of unknown types (Section 9), including reserved frames
(Section 7.2.8) MAY be sent on a request or push stream before,
after, or interleaved with other frames described in this section.
'''

Comment thread
seanmonstar marked this conversation as resolved.
[[TODO]]
quote = '''
Transfer codings (see Section 7 of [HTTP/1.1]) are not defined for
Expand Down
14 changes: 0 additions & 14 deletions .duvet/todos/rfc9114/4.3.toml

This file was deleted.

7 changes: 0 additions & 7 deletions .duvet/todos/rfc9114/6.2.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,3 @@ However, stream types that could modify the state or
semantics of existing protocol components, including QPACK or other
extensions, MUST NOT be sent until the peer is known to support them.
'''

[[TODO]]
quote = '''
A receiver MUST tolerate unidirectional streams being
closed or reset prior to the reception of the unidirectional stream
header.
'''
15 changes: 0 additions & 15 deletions .duvet/todos/rfc9114/7.2.8.toml

This file was deleted.

7 changes: 0 additions & 7 deletions .duvet/todos/rfc9114/9.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,6 @@ Implementations MUST ignore unknown or unsupported values in all
extensible protocol elements.
'''

[[TODO]]
quote = '''
Implementations MUST discard data or
abort reading on unidirectional streams that have unknown or
unsupported types.
'''

[[TODO]]
quote = '''
However, where a known frame type is required to be in
Expand Down
6 changes: 6 additions & 0 deletions h3/src/client/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,12 @@ where

let qpack::Decoded { fields, .. } = decoded;

//= https://www.rfc-editor.org/rfc/rfc9114#section-4.1.2
//# Malformed requests or responses that are
//# detected MUST be treated as a stream error of type H3_MESSAGE_ERROR.
//= https://www.rfc-editor.org/rfc/rfc9114#section-4.1.2
//# Clients MUST NOT
//# accept a malformed response.
let (status, headers) = Header::try_from(fields)
.map_err(|_e| {
self.inner.stream.stop_sending(Code::H3_REQUEST_CANCELLED);
Expand Down
10 changes: 10 additions & 0 deletions h3/src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,10 @@ where
//# Endpoints MUST NOT consider these streams to have any meaning upon
//# receipt.
AcceptedRecvStream::Unknown(mut stream) => {
//= https://www.rfc-editor.org/rfc/rfc9114#section-9
//# Implementations MUST discard data or
//# abort reading on unidirectional streams that have unknown or
//# unsupported types.
//= https://www.rfc-editor.org/rfc/rfc9114#section-6.2
//# Recipients of unknown stream types MUST
//# either abort reading of the stream or discard incoming data without
Expand Down Expand Up @@ -1011,6 +1015,12 @@ where
Poll::Ready(Ok(Some(
Header::try_from(fields)
.map_err(|_e| {
//= https://www.rfc-editor.org/rfc/rfc9114#section-4.1.2
//# Malformed requests or responses that are
//# detected MUST be treated as a stream error of type H3_MESSAGE_ERROR.
//= https://www.rfc-editor.org/rfc/rfc9114#section-4.1.2
//# Clients MUST NOT
//# accept a malformed response.
self.stop_sending(Code::H3_MESSAGE_ERROR);
StreamError::StreamError {
code: Code::H3_MESSAGE_ERROR,
Expand Down
4 changes: 4 additions & 0 deletions h3/src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@ impl FrameDecoder {

match decoded {
Err(frame::FrameError::UnknownFrame(_ty)) => {
//= https://www.rfc-editor.org/rfc/rfc9114#section-4.1
//# Frames of unknown types (Section 9), including reserved frames
//# (Section 7.2.8) MAY be sent on a request or push stream before,
//# after, or interleaved with other frames described in this section.
//= https://www.rfc-editor.org/rfc/rfc9114#section-7.2.8
//# Endpoints MUST
//# NOT consider these frames to have any meaning upon receipt.
Expand Down
54 changes: 54 additions & 0 deletions h3/src/proto/headers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,25 @@ impl TryFrom<Vec<HeaderField>> for Header {
fn try_from(headers: Vec<HeaderField>) -> Result<Self, Self::Error> {
let mut fields = HeaderMap::with_capacity(headers.len());
let mut pseudo = Pseudo::default();
let mut regular_field_seen = false;

for field in headers.into_iter() {
let (name, value) = field.into_inner();
match Field::parse(name, value)? {
//= https://www.rfc-editor.org/rfc/rfc9114#section-4.3
//# Any request or response that contains a
//# pseudo-header field that appears in a header section after a regular
//# header field MUST be treated as malformed.
Field::Method(_)
| Field::Scheme(_)
| Field::Authority(_)
| Field::Path(_)
| Field::Status(_)
| Field::Protocol(_)
if regular_field_seen =>
{
return Err(HeaderError::PseudoAfterRegularField)
}
Field::Method(m) => {
pseudo.method = Some(m);
pseudo.len += 1;
Expand All @@ -231,6 +246,7 @@ impl TryFrom<Vec<HeaderField>> for Header {
pseudo.len += 1;
}
Field::Header((n, v)) => {
regular_field_seen = true;
fields.append(n, v);
}
Field::Protocol(p) => {
Expand Down Expand Up @@ -304,6 +320,9 @@ impl Field {
.map_err(|_| HeaderError::invalid_value(name, value))?,
),
b":protocol" => Field::Protocol(try_value(name, value)?),
//= https://www.rfc-editor.org/rfc/rfc9114#section-4.3
//# Endpoints MUST treat a request or response that contains
//# undefined or invalid pseudo-header fields as malformed.
_ => return Err(HeaderError::invalid_name(name)),
})
}
Expand Down Expand Up @@ -446,6 +465,7 @@ pub enum HeaderError {
MissingStatus,
MissingAuthority,
ContradictedAuthority,
PseudoAfterRegularField,
}

impl HeaderError {
Expand Down Expand Up @@ -483,6 +503,12 @@ impl fmt::Display for HeaderError {
HeaderError::ContradictedAuthority => {
write!(f, "uri and authority field are in contradiction")
}
HeaderError::PseudoAfterRegularField => {
write!(
f,
"pseudo-header field appears after a regular header field"
)
}
}
}
}
Expand Down Expand Up @@ -642,4 +668,32 @@ mod tests {
},]
);
}

#[test]
fn rejects_undefined_pseudo_header() {
//= https://www.rfc-editor.org/rfc/rfc9114#section-4.3
//= type=test
//# Endpoints MUST treat a request or response that contains
//# undefined or invalid pseudo-header fields as malformed.
assert_matches!(
Header::try_from(vec![(b":unknown", b"value").into()]),
Err(HeaderError::InvalidHeaderName(_))
);
}

#[test]
fn rejects_pseudo_header_after_regular_header() {
//= https://www.rfc-editor.org/rfc/rfc9114#section-4.3
//= type=test
//# Any request or response that contains a
//# pseudo-header field that appears in a header section after a regular
//# header field MUST be treated as malformed.
assert_matches!(
Header::try_from(vec![
(b"regular", b"value").into(),
(b":method", b"GET").into(),
]),
Err(HeaderError::PseudoAfterRegularField)
);
}
}
8 changes: 5 additions & 3 deletions h3/src/tests/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1105,9 +1105,11 @@ async fn request_valid_header_trailer() {
.await;
}

// Frames of unknown types (Section 9), including reserved frames (Section
// 7.2.8) MAY be sent on a request or push stream before, after, or interleaved
// with other frames described in this section.
//= https://www.rfc-editor.org/rfc/rfc9114#section-4.1
//= type=test
//# Frames of unknown types (Section 9), including reserved frames
//# (Section 7.2.8) MAY be sent on a request or push stream before,
//# after, or interleaved with other frames described in this section.

#[tokio::test]
async fn request_valid_unknown_frame_before() {
Expand Down
Loading