Skip to content

Commit

Permalink
expose wire error codes to applications
Browse files Browse the repository at this point in the history
  • Loading branch information
evanrittenhouse committed Apr 15, 2024
1 parent 3b2c177 commit 1d00ee1
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 29 deletions.
89 changes: 71 additions & 18 deletions quiche/src/h3/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,29 +423,82 @@ pub enum Error {
VersionFallback,
}

/// HTTP/3 error codes sent on the wire.
///
/// As defined in [RFC9114](https://www.rfc-editor.org/rfc/rfc9114.html#http-error-codes).
pub enum WireErrorCode {
/// No error. This is used when the connection or stream needs to be closed,
/// but there is no error to signal.
NoError = 0x100,
/// Peer violated protocol requirements in a way that does not match a more
/// specific error code or endpoint declines to use the more specific
/// error code.
GeneralProtocolError = 0x101,
/// An internal error has occurred in the HTTP stack.
InternalError = 0x102,
/// The endpoint detected that its peer created a stream that it will not
/// accept.
StreamCreationError = 0x103,
/// A stream required by the HTTP/3 connection was closed or reset.
ClosedCriticalStream = 0x104,
/// A frame was received that was not permitted in the current state or on
/// the current stream.
FrameUnexpected = 0x105,
/// A frame that fails to satisfy layout requirements or with an invalid
/// size was received.
FrameError = 0x106,
/// The endpoint detected that its peer is exhibiting a behavior that might
/// be generating excessive load.
ExcessiveLoad = 0x107,
/// A stream ID or push ID was used incorrectly, such as exceeding a limit,
/// reducing a limit, or being reused.
IdError = 0x108,
/// An endpoint detected an error in the payload of a SETTINGS frame.
SettingsError = 0x109,
/// No SETTINGS frame was received at the beginning of the control stream.
MissingSettings = 0x10a,
/// A server rejected a request without performing any application
/// processing.
RequestRejected = 0x10b,
/// The request or its response (including pushed response) is cancelled.
RequestCancelled = 0x10c,
/// The client's stream terminated without containing a fully formed
/// request.
RequestIncomplete = 0x10d,
/// An HTTP message was malformed and cannot be processed.
MessageError = 0x10e,
/// The TCP connection established in response to a CONNECT request was
/// reset or abnormally closed.
ConnectError = 0x10f,
/// The requested operation cannot be served over HTTP/3. The peer should
/// retry over HTTP/1.1.
VersionFallback = 0x110,
}

impl Error {
fn to_wire(self) -> u64 {
match self {
Error::Done => 0x100,
Error::InternalError => 0x102,
Error::StreamCreationError => 0x103,
Error::ClosedCriticalStream => 0x104,
Error::FrameUnexpected => 0x105,
Error::FrameError => 0x106,
Error::ExcessiveLoad => 0x107,
Error::IdError => 0x108,
Error::MissingSettings => 0x10A,
Error::Done => WireErrorCode::NoError as u64,
Error::InternalError => WireErrorCode::InternalError as u64,
Error::StreamCreationError =>
WireErrorCode::StreamCreationError as u64,
Error::ClosedCriticalStream =>
WireErrorCode::ClosedCriticalStream as u64,
Error::FrameUnexpected => WireErrorCode::FrameUnexpected as u64,
Error::FrameError => WireErrorCode::FrameError as u64,
Error::ExcessiveLoad => WireErrorCode::ExcessiveLoad as u64,
Error::IdError => WireErrorCode::IdError as u64,
Error::MissingSettings => WireErrorCode::MissingSettings as u64,
Error::QpackDecompressionFailed => 0x200,
Error::BufferTooShort => 0x999,
Error::TransportError { .. } => 0xFF,
Error::StreamBlocked => 0xFF,
Error::SettingsError => 0x109,
Error::RequestRejected => 0x10B,
Error::RequestCancelled => 0x10C,
Error::RequestIncomplete => 0x10D,
Error::MessageError => 0x10E,
Error::ConnectError => 0x10F,
Error::VersionFallback => 0x110,
Error::TransportError { .. } | Error::StreamBlocked => 0xFF,
Error::SettingsError => WireErrorCode::SettingsError as u64,
Error::RequestRejected => WireErrorCode::RequestRejected as u64,
Error::RequestCancelled => WireErrorCode::RequestCancelled as u64,
Error::RequestIncomplete => WireErrorCode::RequestIncomplete as u64,
Error::MessageError => WireErrorCode::MessageError as u64,
Error::ConnectError => WireErrorCode::ConnectError as u64,
Error::VersionFallback => WireErrorCode::VersionFallback as u64,
}
}

Expand Down
90 changes: 79 additions & 11 deletions quiche/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -577,20 +577,88 @@ pub enum Error {
CryptoBufferExceeded,
}

/// QUIC error codes sent on the wire.
///
/// As defined in [RFC9000](https://www.rfc-editor.org/rfc/rfc9000.html#name-error-codes).
pub enum WireErrorCode {
/// An endpoint uses this with CONNECTION_CLOSE to signal that the
/// connection is being closed abruptly in the absence of any error.
NoError = 0x0,
/// The endpoint encountered an internal error and cannot continue with the
/// connection.
InternalError = 0x1,
/// The server refused to accept a new connection.
ConnectionRefused = 0x2,
/// An endpoint received more data than it permitted in its advertised data
/// limits; see Section 4.
FlowControlError = 0x3,
/// An endpoint received a frame for a stream identifier that exceeded its
/// advertised stream limit for the corresponding stream type.
StreamLimitError = 0x4,
/// An endpoint received a frame for a stream that was not in a state that
/// permitted that frame.
StreamStateError = 0x5,
/// (1) An endpoint received a STREAM frame containing data that exceeded
/// the previously established final size, (2) an endpoint received a
/// STREAM frame or a RESET_STREAM frame containing a final size that
/// was lower than the size of stream data that was already received, or
/// (3) an endpoint received a STREAM frame or a RESET_STREAM frame
/// containing a different final size to the one already established.
FinalSizeError = 0x6,
/// An endpoint received a frame that was badly formatted -- for instance, a
/// frame of an unknown type or an ACK frame that has more
/// acknowledgment ranges than the remainder of the packet could carry.
FrameEncodingError = 0x7,
/// An endpoint received transport parameters that were badly formatted,
/// included an invalid value, omitted a mandatory transport parameter,
/// included a forbidden transport parameter, or were otherwise in
/// error.
TransportParameterError = 0x8,
/// An endpoint received transport parameters that were badly formatted,
/// included an invalid value, omitted a mandatory transport parameter,
/// included a forbidden transport parameter, or were otherwise in
/// error.
ConnectionIdLimitError = 0x9,
/// An endpoint detected an error with protocol compliance that was not
/// covered by more specific error codes.
ProtocolViolation = 0xa,
/// A server received a client Initial that contained an invalid Token
/// field.
InvalidToken = 0xb,
/// The application or application protocol caused the connection to be
/// closed.
ApplicationError = 0xc,
/// An endpoint has received more data in CRYPTO frames than it can buffer.
CryptoBufferExceeded = 0xd,
/// An endpoint detected errors in performing key updates.
KeyUpdateError = 0xe,
/// An endpoint has reached the confidentiality or integrity limit for the
/// AEAD algorithm used by the given connection.
AeadLimitReached = 0xf,
/// An endpoint has determined that the network path is incapable of
/// supporting QUIC. An endpoint is unlikely to receive a
/// CONNECTION_CLOSE frame carrying this code except when the path does
/// not support a large enough MTU.
NoViablePath = 0x10,
}

impl Error {
fn to_wire(self) -> u64 {
match self {
Error::Done => 0x0,
Error::InvalidFrame => 0x7,
Error::InvalidStreamState(..) => 0x5,
Error::InvalidTransportParam => 0x8,
Error::FlowControl => 0x3,
Error::StreamLimit => 0x4,
Error::FinalSize => 0x6,
Error::IdLimit => 0x09,
Error::KeyUpdate => 0xe,
Error::CryptoBufferExceeded => 0x0d,
_ => 0xa,
Error::Done => WireErrorCode::NoError as u64,
Error::InvalidFrame => WireErrorCode::FrameEncodingError as u64,
Error::InvalidStreamState(..) =>
WireErrorCode::StreamStateError as u64,
Error::InvalidTransportParam =>
WireErrorCode::TransportParameterError as u64,
Error::FlowControl => WireErrorCode::FlowControlError as u64,
Error::StreamLimit => WireErrorCode::StreamLimitError as u64,
Error::IdLimit => WireErrorCode::ConnectionIdLimitError as u64,
Error::FinalSize => WireErrorCode::FinalSizeError as u64,
Error::CryptoBufferExceeded =>
WireErrorCode::CryptoBufferExceeded as u64,
Error::KeyUpdate => WireErrorCode::KeyUpdateError as u64,
_ => WireErrorCode::ProtocolViolation as u64,
}
}

Expand Down

0 comments on commit 1d00ee1

Please sign in to comment.