1use std::fmt;
5
6pub const PREFACE: &[u8; 24] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
8
9pub const HEADER_LEN: usize = 9;
11
12pub mod kind {
14 pub const DATA: u8 = 0x0;
15 pub const HEADERS: u8 = 0x1;
16 pub const PRIORITY: u8 = 0x2;
17 pub const RST_STREAM: u8 = 0x3;
18 pub const SETTINGS: u8 = 0x4;
19 pub const PUSH_PROMISE: u8 = 0x5;
20 pub const PING: u8 = 0x6;
21 pub const GOAWAY: u8 = 0x7;
22 pub const WINDOW_UPDATE: u8 = 0x8;
23 pub const CONTINUATION: u8 = 0x9;
24}
25
26pub mod flag {
28 pub const END_STREAM: u8 = 0x1;
29 pub const ACK: u8 = 0x1;
30 pub const END_HEADERS: u8 = 0x4;
31 pub const PADDED: u8 = 0x8;
32 pub const PRIORITY: u8 = 0x20;
33}
34
35pub mod setting {
37 pub const HEADER_TABLE_SIZE: u16 = 0x1;
38 pub const ENABLE_PUSH: u16 = 0x2;
39 pub const MAX_CONCURRENT_STREAMS: u16 = 0x3;
40 pub const INITIAL_WINDOW_SIZE: u16 = 0x4;
41 pub const MAX_FRAME_SIZE: u16 = 0x5;
42 pub const MAX_HEADER_LIST_SIZE: u16 = 0x6;
43 pub const ENABLE_CONNECT_PROTOCOL: u16 = 0x8;
44}
45
46pub const MAX_WINDOW: u32 = (1 << 31) - 1;
48pub const DEFAULT_WINDOW: u32 = 65_535;
50pub const MIN_FRAME_SIZE: u32 = 16_384;
52pub const MAX_FRAME_SIZE: u32 = (1 << 24) - 1;
53
54#[derive(Clone, Copy, PartialEq, Eq, Hash)]
56pub struct ErrorCode(pub u32);
57
58impl ErrorCode {
59 pub const NO_ERROR: ErrorCode = ErrorCode(0x0);
60 pub const PROTOCOL_ERROR: ErrorCode = ErrorCode(0x1);
61 pub const INTERNAL_ERROR: ErrorCode = ErrorCode(0x2);
62 pub const FLOW_CONTROL_ERROR: ErrorCode = ErrorCode(0x3);
63 pub const SETTINGS_TIMEOUT: ErrorCode = ErrorCode(0x4);
64 pub const STREAM_CLOSED: ErrorCode = ErrorCode(0x5);
65 pub const FRAME_SIZE_ERROR: ErrorCode = ErrorCode(0x6);
66 pub const REFUSED_STREAM: ErrorCode = ErrorCode(0x7);
67 pub const CANCEL: ErrorCode = ErrorCode(0x8);
68 pub const COMPRESSION_ERROR: ErrorCode = ErrorCode(0x9);
69 pub const CONNECT_ERROR: ErrorCode = ErrorCode(0xa);
70 pub const ENHANCE_YOUR_CALM: ErrorCode = ErrorCode(0xb);
71 pub const INADEQUATE_SECURITY: ErrorCode = ErrorCode(0xc);
72 pub const HTTP_1_1_REQUIRED: ErrorCode = ErrorCode(0xd);
73
74 pub fn name(self) -> &'static str {
76 const NAMES: [&str; 14] = [
77 "NO_ERROR",
78 "PROTOCOL_ERROR",
79 "INTERNAL_ERROR",
80 "FLOW_CONTROL_ERROR",
81 "SETTINGS_TIMEOUT",
82 "STREAM_CLOSED",
83 "FRAME_SIZE_ERROR",
84 "REFUSED_STREAM",
85 "CANCEL",
86 "COMPRESSION_ERROR",
87 "CONNECT_ERROR",
88 "ENHANCE_YOUR_CALM",
89 "INADEQUATE_SECURITY",
90 "HTTP_1_1_REQUIRED",
91 ];
92 NAMES.get(self.0 as usize).copied().unwrap_or("UNKNOWN")
93 }
94}
95
96impl fmt::Debug for ErrorCode {
97 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98 write!(f, "{}", self.name())
99 }
100}
101
102impl fmt::Display for ErrorCode {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 write!(f, "{} (0x{:x})", self.name(), self.0)
105 }
106}
107
108#[derive(Clone, Copy, Debug, PartialEq, Eq)]
110pub struct FrameHeader {
111 pub len: usize,
112 pub kind: u8,
113 pub flags: u8,
114 pub stream: u32,
115}
116
117impl FrameHeader {
118 #[inline]
120 pub fn parse(b: &[u8]) -> FrameHeader {
121 FrameHeader {
122 len: ((b[0] as usize) << 16) | ((b[1] as usize) << 8) | b[2] as usize,
123 kind: b[3],
124 flags: b[4],
125 stream: u32::from_be_bytes([b[5], b[6], b[7], b[8]]) & 0x7fff_ffff,
126 }
127 }
128
129 #[inline]
130 pub fn has(&self, f: u8) -> bool {
131 self.flags & f != 0
132 }
133}
134
135#[inline]
137pub fn write_header(out: &mut Vec<u8>, len: usize, kind: u8, flags: u8, stream: u32) {
138 let s = (stream & 0x7fff_ffff).to_be_bytes();
139 out.extend_from_slice(&[(len >> 16) as u8, (len >> 8) as u8, len as u8, kind, flags, s[0], s[1], s[2], s[3]]);
140}
141
142#[inline]
144pub(crate) fn patch_header(out: &mut [u8], at: usize, len: usize, flags: u8) {
145 out[at] = (len >> 16) as u8;
146 out[at + 1] = (len >> 8) as u8;
147 out[at + 2] = len as u8;
148 out[at + 4] = flags;
149}
150
151pub fn write_data(out: &mut Vec<u8>, stream: u32, data: &[u8], end_stream: bool) {
153 write_header(out, data.len(), kind::DATA, if end_stream { flag::END_STREAM } else { 0 }, stream);
154 out.extend_from_slice(data);
155}
156
157pub fn write_settings(out: &mut Vec<u8>, values: &[(u16, u32)]) {
159 write_header(out, values.len() * 6, kind::SETTINGS, 0, 0);
160 for (id, v) in values {
161 out.extend_from_slice(&id.to_be_bytes());
162 out.extend_from_slice(&v.to_be_bytes());
163 }
164}
165
166pub fn write_settings_ack(out: &mut Vec<u8>) {
168 write_header(out, 0, kind::SETTINGS, flag::ACK, 0);
169}
170
171pub fn write_ping(out: &mut Vec<u8>, data: [u8; 8], ack: bool) {
173 write_header(out, 8, kind::PING, if ack { flag::ACK } else { 0 }, 0);
174 out.extend_from_slice(&data);
175}
176
177pub fn write_goaway(out: &mut Vec<u8>, last_stream: u32, code: ErrorCode, debug: &[u8]) {
179 write_header(out, 8 + debug.len(), kind::GOAWAY, 0, 0);
180 out.extend_from_slice(&(last_stream & 0x7fff_ffff).to_be_bytes());
181 out.extend_from_slice(&code.0.to_be_bytes());
182 out.extend_from_slice(debug);
183}
184
185pub fn write_rst(out: &mut Vec<u8>, stream: u32, code: ErrorCode) {
187 write_header(out, 4, kind::RST_STREAM, 0, stream);
188 out.extend_from_slice(&code.0.to_be_bytes());
189}
190
191pub fn write_window_update(out: &mut Vec<u8>, stream: u32, increment: u32) {
193 write_header(out, 4, kind::WINDOW_UPDATE, 0, stream);
194 out.extend_from_slice(&(increment & 0x7fff_ffff).to_be_bytes());
195}
196
197pub fn write_headers(out: &mut Vec<u8>, stream: u32, block: &[u8], end_stream: bool, max_frame: usize) {
199 let mut chunks = block.chunks(max_frame.max(1));
200 let first = chunks.next().unwrap_or(&[]);
201 let mut rest = chunks.peekable();
202 let mut fl = if end_stream { flag::END_STREAM } else { 0 };
203 if rest.peek().is_none() {
204 fl |= flag::END_HEADERS;
205 }
206 write_header(out, first.len(), kind::HEADERS, fl, stream);
207 out.extend_from_slice(first);
208 while let Some(c) = rest.next() {
209 let fl = if rest.peek().is_none() { flag::END_HEADERS } else { 0 };
210 write_header(out, c.len(), kind::CONTINUATION, fl, stream);
211 out.extend_from_slice(c);
212 }
213}
214
215#[inline]
217pub(crate) fn be32(b: &[u8]) -> u32 {
218 u32::from_be_bytes([b[0], b[1], b[2], b[3]])
219}
220
221pub fn split_frames(buf: &[u8]) -> Vec<(FrameHeader, &[u8])> {
224 let mut v = Vec::new();
225 let mut pos = 0;
226 while buf.len() - pos >= HEADER_LEN {
227 let h = FrameHeader::parse(&buf[pos..]);
228 if buf.len() - pos - HEADER_LEN < h.len {
229 break;
230 }
231 v.push((h, &buf[pos + HEADER_LEN..pos + HEADER_LEN + h.len]));
232 pos += HEADER_LEN + h.len;
233 }
234 v
235}
236
237#[cfg(test)]
238mod tests {
239 use super::*;
240
241 #[test]
242 fn layouts() {
243 let mut o = Vec::new();
244 write_data(&mut o, 3, b"hello", true);
245 assert_eq!(o, [0, 0, 5, 0, 1, 0, 0, 0, 3, b'h', b'e', b'l', b'l', b'o']);
246 let h = FrameHeader::parse(&o);
247 assert_eq!(h, FrameHeader { len: 5, kind: kind::DATA, flags: 1, stream: 3 });
248 assert!(h.has(flag::END_STREAM));
249 o.clear();
250 write_window_update(&mut o, 5, 1000);
251 assert_eq!(o, [0, 0, 4, 8, 0, 0, 0, 0, 5, 0, 0, 0x03, 0xe8]);
252 o.clear();
253 write_settings_ack(&mut o);
254 assert_eq!(o, [0, 0, 0, 4, 1, 0, 0, 0, 0]);
255 o.clear();
256 write_goaway(&mut o, 7, ErrorCode::PROTOCOL_ERROR, b"bad");
257 assert_eq!(&o[9..], &[0, 0, 0, 7, 0, 0, 0, 1, b'b', b'a', b'd']);
258 assert_eq!(ErrorCode::CANCEL.to_string(), "CANCEL (0x8)");
259 assert_eq!(format!("{:?}", ErrorCode(99)), "UNKNOWN");
260 assert_eq!(FrameHeader::parse(&[0, 0, 0, 0, 0, 0x80, 0, 0, 1]).stream, 1);
262 }
263
264 #[test]
265 fn headers_split_into_continuations() {
266 let block: Vec<u8> = (0..25u8).collect();
267 let mut o = Vec::new();
268 write_headers(&mut o, 1, &block, true, 10);
269 let f = split_frames(&o);
270 assert_eq!(f.len(), 3);
271 assert_eq!((f[0].0.kind, f[0].0.flags), (kind::HEADERS, flag::END_STREAM));
272 assert_eq!((f[1].0.kind, f[1].0.flags), (kind::CONTINUATION, 0));
273 assert_eq!((f[2].0.kind, f[2].0.flags), (kind::CONTINUATION, flag::END_HEADERS));
274 let joined: Vec<u8> = f.iter().flat_map(|x| x.1.to_vec()).collect();
275 assert_eq!(joined, block);
276 o.clear();
277 write_headers(&mut o, 1, &[1, 2], false, 10);
278 assert_eq!(split_frames(&o)[0].0.flags, flag::END_HEADERS);
279 }
280}