Coverage Report

Created: 2025-08-26 07:09

/src/h2/src/frame/reason.rs
Line
Count
Source (jump to first uncovered line)
1
use std::fmt;
2
3
/// HTTP/2 error codes.
4
///
5
/// Error codes are used in `RST_STREAM` and `GOAWAY` frames to convey the
6
/// reasons for the stream or connection error. For example,
7
/// [`SendStream::send_reset`] takes a `Reason` argument. Also, the `Error` type
8
/// may contain a `Reason`.
9
///
10
/// Error codes share a common code space. Some error codes apply only to
11
/// streams, others apply only to connections, and others may apply to either.
12
/// See [RFC 7540] for more information.
13
///
14
/// See [Error Codes in the spec][spec].
15
///
16
/// [spec]: http://httpwg.org/specs/rfc7540.html#ErrorCodes
17
/// [`SendStream::send_reset`]: struct.SendStream.html#method.send_reset
18
#[derive(PartialEq, Eq, Clone, Copy)]
19
pub struct Reason(u32);
20
21
impl Reason {
22
    /// The associated condition is not a result of an error.
23
    ///
24
    /// For example, a GOAWAY might include this code to indicate graceful
25
    /// shutdown of a connection.
26
    pub const NO_ERROR: Reason = Reason(0);
27
    /// The endpoint detected an unspecific protocol error.
28
    ///
29
    /// This error is for use when a more specific error code is not available.
30
    pub const PROTOCOL_ERROR: Reason = Reason(1);
31
    /// The endpoint encountered an unexpected internal error.
32
    pub const INTERNAL_ERROR: Reason = Reason(2);
33
    /// The endpoint detected that its peer violated the flow-control protocol.
34
    pub const FLOW_CONTROL_ERROR: Reason = Reason(3);
35
    /// The endpoint sent a SETTINGS frame but did not receive a response in
36
    /// a timely manner.
37
    pub const SETTINGS_TIMEOUT: Reason = Reason(4);
38
    /// The endpoint received a frame after a stream was half-closed.
39
    pub const STREAM_CLOSED: Reason = Reason(5);
40
    /// The endpoint received a frame with an invalid size.
41
    pub const FRAME_SIZE_ERROR: Reason = Reason(6);
42
    /// The endpoint refused the stream prior to performing any application
43
    /// processing.
44
    pub const REFUSED_STREAM: Reason = Reason(7);
45
    /// Used by the endpoint to indicate that the stream is no longer needed.
46
    pub const CANCEL: Reason = Reason(8);
47
    /// The endpoint is unable to maintain the header compression context for
48
    /// the connection.
49
    pub const COMPRESSION_ERROR: Reason = Reason(9);
50
    /// The connection established in response to a CONNECT request was reset
51
    /// or abnormally closed.
52
    pub const CONNECT_ERROR: Reason = Reason(10);
53
    /// The endpoint detected that its peer is exhibiting a behavior that might
54
    /// be generating excessive load.
55
    pub const ENHANCE_YOUR_CALM: Reason = Reason(11);
56
    /// The underlying transport has properties that do not meet minimum
57
    /// security requirements.
58
    pub const INADEQUATE_SECURITY: Reason = Reason(12);
59
    /// The endpoint requires that HTTP/1.1 be used instead of HTTP/2.
60
    pub const HTTP_1_1_REQUIRED: Reason = Reason(13);
61
62
    /// Get a string description of the error code.
63
0
    pub fn description(&self) -> &str {
64
0
        match self.0 {
65
0
            0 => "not a result of an error",
66
0
            1 => "unspecific protocol error detected",
67
0
            2 => "unexpected internal error encountered",
68
0
            3 => "flow-control protocol violated",
69
0
            4 => "settings ACK not received in timely manner",
70
0
            5 => "received frame when stream half-closed",
71
0
            6 => "frame with invalid size",
72
0
            7 => "refused stream before processing any application logic",
73
0
            8 => "stream no longer needed",
74
0
            9 => "unable to maintain the header compression context",
75
            10 => {
76
0
                "connection established in response to a CONNECT request was reset or abnormally \
77
0
                 closed"
78
            }
79
0
            11 => "detected excessive load generating behavior",
80
0
            12 => "security properties do not meet minimum requirements",
81
0
            13 => "endpoint requires HTTP/1.1",
82
0
            _ => "unknown reason",
83
        }
84
0
    }
85
}
86
87
impl From<u32> for Reason {
88
4.38k
    fn from(src: u32) -> Reason {
89
4.38k
        Reason(src)
90
4.38k
    }
91
}
92
93
impl From<Reason> for u32 {
94
7.37k
    fn from(src: Reason) -> u32 {
95
7.37k
        src.0
96
7.37k
    }
97
}
98
99
impl fmt::Debug for Reason {
100
28.6k
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
101
28.6k
        let name = match self.0 {
102
804
            0 => "NO_ERROR",
103
5.35k
            1 => "PROTOCOL_ERROR",
104
3
            2 => "INTERNAL_ERROR",
105
139
            3 => "FLOW_CONTROL_ERROR",
106
0
            4 => "SETTINGS_TIMEOUT",
107
0
            5 => "STREAM_CLOSED",
108
14.9k
            6 => "FRAME_SIZE_ERROR",
109
0
            7 => "REFUSED_STREAM",
110
4
            8 => "CANCEL",
111
0
            9 => "COMPRESSION_ERROR",
112
0
            10 => "CONNECT_ERROR",
113
0
            11 => "ENHANCE_YOUR_CALM",
114
0
            12 => "INADEQUATE_SECURITY",
115
0
            13 => "HTTP_1_1_REQUIRED",
116
7.42k
            other => return f.debug_tuple("Reason").field(&Hex(other)).finish(),
117
        };
118
21.2k
        f.write_str(name)
119
28.6k
    }
120
}
121
122
struct Hex(u32);
123
124
impl fmt::Debug for Hex {
125
7.42k
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
126
7.42k
        fmt::LowerHex::fmt(&self.0, f)
127
7.42k
    }
128
}
129
130
impl fmt::Display for Reason {
131
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
132
0
        write!(fmt, "{}", self.description())
133
0
    }
134
}