1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use super::{frame::reason::Reason, hpack::DecoderError};
/// Errors that can occur during parsing an HTTP/2 frame.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
/// A length value other than 8 was set on a PING message.
BadFrameSize,
/// The padding length was larger than the frame-header-specified
/// length of the payload.
TooMuchPadding,
/// An invalid setting value was provided
InvalidSettingValue,
/// An invalid window update value
// InvalidWindowUpdateValue,
/// SETTINGS_INITIAL_WINDOW_SIZE caused the flow-control window to overflow.
InitialWindowOverflow,
/// The payload length specified by the frame header was not the
/// value necessary for the specific frame type.
InvalidPayloadLength,
/// Received a payload with an ACK settings frame
InvalidPayloadAckSettings,
/// An invalid stream identifier was provided.
///
/// This is returned if a SETTINGS or PING frame is received with a stream
/// identifier other than zero.
InvalidStreamId,
/// A request or response is malformed.
MalformedMessage,
/// An invalid stream dependency ID was provided
///
/// This is returned if a HEADERS or PRIORITY frame is received with an
/// invalid stream identifier.
InvalidDependencyId,
FrameAfterReset,
FrameAfterEndStream,
/// Failed to perform HPACK decoding
Hpack(DecoderError),
}
impl From<DecoderError> for Error {
fn from(e: DecoderError) -> Self {
Self::Hpack(e)
}
}
impl Error {
pub(crate) fn reason(&self) -> Reason {
match self {
Self::BadFrameSize | Self::InvalidPayloadLength | Self::InvalidPayloadAckSettings => {
Reason::FRAME_SIZE_ERROR
}
Self::TooMuchPadding
| Self::InvalidSettingValue
// | Self::InvalidWindowUpdateValue
| Self::InvalidStreamId
| Self::MalformedMessage
| Self::InvalidDependencyId
| Self::FrameAfterEndStream => Reason::PROTOCOL_ERROR,
Self::InitialWindowOverflow => Reason::FLOW_CONTROL_ERROR,
Self::FrameAfterReset => Reason::STREAM_CLOSED,
Self::Hpack(_) => Reason::COMPRESSION_ERROR,
}
}
pub(crate) fn is_go_away(&self) -> bool {
// MalformedMessage is the only variant that is strictly stream-level:
// it comes from pseudo-header / connection-specific-header validation in
// HPACK decoding (RFC 7540 ยง8.1.2), where the HPACK context itself stays
// intact so peers can continue on other streams. Everything else is a
// wire-protocol violation that corrupts shared state (framing, HPACK
// dynamic table, flow-control window) and must tear down the connection.
!matches!(self, Self::MalformedMessage)
}
}