1use super::error::{H2Error, Reason};
20use bytes::{Bytes, BytesMut};
21
22pub const FRAME_HEADER_LEN: usize = 9;
24pub const DEFAULT_MAX_FRAME_SIZE: usize = 16_384;
26pub const MAX_FRAME_SIZE_LIMIT: usize = 16_777_215;
28pub const DEFAULT_INITIAL_WINDOW_SIZE: u32 = 1_048_576;
30pub const MAX_WINDOW_SIZE: u32 = 2_147_483_647;
32pub const CLIENT_PREFACE: &[u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
34
35const DATA_TYPE: u8 = 0x00;
36const HEADERS_TYPE: u8 = 0x01;
37const PRIORITY_TYPE: u8 = 0x02;
38const RST_STREAM_TYPE: u8 = 0x03;
39const SETTINGS_TYPE: u8 = 0x04;
40const PUSH_PROMISE_TYPE: u8 = 0x05;
41const PING_TYPE: u8 = 0x06;
42const GOAWAY_TYPE: u8 = 0x07;
43const WINDOW_UPDATE_TYPE: u8 = 0x08;
44const CONTINUATION_TYPE: u8 = 0x09;
45
46const FLAG_END_STREAM: u8 = 0x01;
48const FLAG_ACK: u8 = 0x01;
49const FLAG_END_HEADERS: u8 = 0x04;
50const FLAG_PADDED: u8 = 0x08;
51const FLAG_PRIORITY: u8 = 0x20;
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub struct Priority {
56 pub exclusive: bool,
57 pub dependency: u32,
58 pub weight: u8,
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub struct Setting {
64 pub id: u16,
65 pub value: u32,
66}
67
68#[derive(Debug, Clone, PartialEq, Eq)]
74pub enum Frame {
75 Data {
76 stream_id: u32,
77 end_stream: bool,
78 data: Bytes,
79 },
80 Headers {
81 stream_id: u32,
82 end_stream: bool,
83 end_headers: bool,
84 priority: Option<Priority>,
85 block: Bytes,
86 },
87 Priority {
88 stream_id: u32,
89 priority: Priority,
90 },
91 Reset {
92 stream_id: u32,
93 error_code: u32,
94 },
95 Settings {
96 ack: bool,
97 settings: Vec<Setting>,
98 },
99 PushPromise {
100 stream_id: u32,
101 end_headers: bool,
102 promised_stream_id: u32,
103 block: Bytes,
104 },
105 Ping {
106 ack: bool,
107 payload: [u8; 8],
108 },
109 GoAway {
110 last_stream_id: u32,
111 error_code: u32,
112 debug: Bytes,
113 },
114 WindowUpdate {
115 stream_id: u32,
116 increment: u32,
117 },
118 Continuation {
119 stream_id: u32,
120 end_headers: bool,
121 block: Bytes,
122 },
123 Unknown {
126 typ: u8,
127 flags: u8,
128 stream_id: u32,
129 payload: Bytes,
130 },
131}
132
133#[derive(Debug)]
135pub struct FrameDecoder {
136 buf: BytesMut,
137 max_frame_size: usize,
138 block_stream: Option<u32>,
142}
143
144impl FrameDecoder {
145 #[inline]
148 pub fn new(max_frame_size: usize) -> FrameDecoder {
149 FrameDecoder {
150 buf: BytesMut::new(),
151 max_frame_size,
152 block_stream: None,
153 }
154 }
155
156 #[inline]
158 pub fn extend(&mut self, bytes: &[u8]) {
159 self.buf.extend_from_slice(bytes);
160 }
161
162 #[inline]
164 pub fn max_frame_size(&self) -> usize {
165 self.max_frame_size
166 }
167
168 #[inline]
170 pub fn set_max_frame_size(&mut self, max_frame_size: usize) {
171 self.max_frame_size = max_frame_size;
172 }
173
174 #[inline]
176 pub fn block_stream(&self) -> Option<u32> {
177 self.block_stream
178 }
179
180 #[inline]
184 pub fn clear_block(&mut self) {
185 self.block_stream = None;
186 }
187
188 #[inline]
191 pub fn next_frame(&mut self) -> Result<Option<Frame>, H2Error> {
192 if self.buf.len() < FRAME_HEADER_LEN {
193 return Ok(None);
194 }
195
196 let payload_len = u32::from_be_bytes([0, self.buf[0], self.buf[1], self.buf[2]]) as usize;
199 let typ = self.buf[3];
200 let flags = self.buf[4];
201 let raw_stream_id =
202 u32::from_be_bytes([self.buf[5], self.buf[6], self.buf[7], self.buf[8]]);
203 let stream_id = raw_stream_id & 0x7fff_ffff;
207
208 if payload_len > self.max_frame_size {
209 return Err(H2Error::frame_size(
210 "frame payload exceeds SETTINGS_MAX_FRAME_SIZE",
211 ));
212 }
213
214 let total = FRAME_HEADER_LEN + payload_len;
215 if self.buf.len() < total {
216 return Ok(None);
217 }
218
219 let _header = self.buf.split_to(FRAME_HEADER_LEN);
220 let payload = self.buf.split_to(payload_len).freeze();
221 let frame = parse_frame(typ, flags, stream_id, payload, self)?;
222 Ok(Some(frame))
223 }
224}
225
226#[inline]
228fn parse_frame(
229 typ: u8,
230 flags: u8,
231 stream_id: u32,
232 payload: Bytes,
233 decoder: &mut FrameDecoder,
234) -> Result<Frame, H2Error> {
235 let mut body = &payload[..];
236
237 if let Some(open_stream) = decoder.block_stream {
239 if typ != CONTINUATION_TYPE {
240 return Err(H2Error::protocol(
241 "frame received while field block was open",
242 ));
243 }
244 if stream_id != open_stream {
245 return Err(H2Error::protocol(
246 "CONTINUATION frame on a different stream than the open field block",
247 ));
248 }
249 } else if typ == CONTINUATION_TYPE {
250 return Err(H2Error::protocol(
251 "CONTINUATION frame without a preceding HEADERS or PUSH_PROMISE",
252 ));
253 }
254
255 let frame = match typ {
256 DATA_TYPE => {
257 require_stream(stream_id)?;
258 let end_stream = flags & FLAG_END_STREAM != 0;
259 let pad_len = take_padding(&mut body, flags & FLAG_PADDED != 0)?;
260 Frame::Data {
261 stream_id,
262 end_stream,
263 data: payload_slice(&payload, body, pad_len),
264 }
265 }
266 HEADERS_TYPE => {
267 require_stream(stream_id)?;
268 let end_stream = flags & FLAG_END_STREAM != 0;
269 let end_headers = flags & FLAG_END_HEADERS != 0;
270 let pad_len = take_padding(&mut body, flags & FLAG_PADDED != 0)?;
271 let priority = if flags & FLAG_PRIORITY != 0 {
272 Some(read_priority(&mut body, stream_id)?)
273 } else {
274 None
275 };
276 if !end_headers {
277 decoder.block_stream = Some(stream_id);
278 }
279 Frame::Headers {
280 stream_id,
281 end_stream,
282 end_headers,
283 priority,
284 block: payload_slice(&payload, body, pad_len),
285 }
286 }
287 PRIORITY_TYPE => {
288 require_stream(stream_id)?;
289 if body.len() != 5 {
290 return Err(H2Error::frame_size(
291 "PRIORITY frame payload must be exactly 5 octets",
292 ));
293 }
294 let priority = read_priority(&mut body, stream_id)?;
295 Frame::Priority {
296 stream_id,
297 priority,
298 }
299 }
300 RST_STREAM_TYPE => {
301 require_stream(stream_id)?;
302 if body.len() != 4 {
303 return Err(H2Error::frame_size(
304 "RST_STREAM frame payload must be exactly 4 octets",
305 ));
306 }
307 Frame::Reset {
308 stream_id,
309 error_code: read_u32(body),
310 }
311 }
312 SETTINGS_TYPE => {
313 if stream_id != 0 {
314 return Err(H2Error::protocol(
315 "SETTINGS frame must use stream identifier 0",
316 ));
317 }
318 let ack = flags & FLAG_ACK != 0;
319 if ack && !body.is_empty() {
320 return Err(H2Error::frame_size(
321 "SETTINGS frame with ACK flag must have an empty payload",
322 ));
323 }
324 if !body.len().is_multiple_of(6) {
325 return Err(H2Error::frame_size(
326 "SETTINGS frame payload must be a multiple of 6 octets",
327 ));
328 }
329 let mut settings = Vec::with_capacity(body.len() / 6);
330 while !body.is_empty() {
331 let id = u16::from_be_bytes([body[0], body[1]]);
332 let value = u32::from_be_bytes([body[2], body[3], body[4], body[5]]);
333 validate_setting(id, value)?;
334 settings.push(Setting { id, value });
335 body = &body[6..];
336 }
337 if !ack {
341 for setting in &settings {
342 if setting.id == 0x05 {
343 decoder.set_max_frame_size(setting.value as usize);
344 }
345 }
346 }
347 Frame::Settings { ack, settings }
348 }
349 PUSH_PROMISE_TYPE => {
350 require_stream(stream_id)?;
351 let end_headers = flags & FLAG_END_HEADERS != 0;
352 let pad_len = take_padding(&mut body, flags & FLAG_PADDED != 0)?;
353 if body.len() < 4 {
354 return Err(H2Error::frame_size(
355 "PUSH_PROMISE frame payload must be at least 4 octets",
356 ));
357 }
358 let promised_stream_id = read_u32(&body[..4]) & 0x7fff_ffff;
359 if promised_stream_id == 0 {
360 return Err(H2Error::protocol(
361 "PUSH_PROMISE promised stream identifier is 0",
362 ));
363 }
364 if !end_headers {
365 decoder.block_stream = Some(stream_id);
366 }
367 body = &body[4..];
368 Frame::PushPromise {
369 stream_id,
370 end_headers,
371 promised_stream_id,
372 block: payload_slice(&payload, body, pad_len),
373 }
374 }
375 PING_TYPE => {
376 if stream_id != 0 {
377 return Err(H2Error::protocol("PING frame must use stream identifier 0"));
378 }
379 if body.len() != 8 {
380 return Err(H2Error::frame_size(
381 "PING frame payload must be exactly 8 octets",
382 ));
383 }
384 Frame::Ping {
385 ack: flags & FLAG_ACK != 0,
386 payload: body[..8]
387 .try_into()
388 .expect("PING payload is exactly 8 octets (validated above)"),
389 }
390 }
391 GOAWAY_TYPE => {
392 if stream_id != 0 {
393 return Err(H2Error::protocol(
394 "GOAWAY frame must use stream identifier 0",
395 ));
396 }
397 if body.len() < 8 {
398 return Err(H2Error::frame_size(
399 "GOAWAY frame payload must be at least 8 octets",
400 ));
401 }
402 let last_stream_id = read_u32(&body[..4]) & 0x7fff_ffff;
403 let error_code = read_u32(&body[4..8]);
404 Frame::GoAway {
405 last_stream_id,
406 error_code,
407 debug: payload.slice(8..),
408 }
409 }
410 WINDOW_UPDATE_TYPE => {
411 if body.len() != 4 {
412 return Err(H2Error::frame_size(
413 "WINDOW_UPDATE frame payload must be exactly 4 octets",
414 ));
415 }
416 let increment = read_u32(body) & 0x7fff_ffff;
417 if increment == 0 {
418 return Err(H2Error::protocol("WINDOW_UPDATE frame with zero increment"));
419 }
420 Frame::WindowUpdate {
421 stream_id,
422 increment,
423 }
424 }
425 CONTINUATION_TYPE => {
426 let end_headers = flags & FLAG_END_HEADERS != 0;
427 if end_headers {
428 decoder.block_stream = None;
429 }
430 Frame::Continuation {
431 stream_id,
432 end_headers,
433 block: payload,
434 }
435 }
436 _ => Frame::Unknown {
437 typ,
438 flags,
439 stream_id,
440 payload,
441 },
442 };
443
444 Ok(frame)
445}
446
447#[inline]
451fn payload_slice(payload: &Bytes, body: &[u8], pad_len: usize) -> Bytes {
452 let start = payload.len() - pad_len - body.len();
453 payload.slice(start..start + body.len())
454}
455
456#[inline]
462fn take_padding(body: &mut &[u8], padded: bool) -> Result<usize, H2Error> {
463 if !padded {
464 return Ok(0);
465 }
466 let pad_len = *body
467 .first()
468 .ok_or_else(|| H2Error::frame_size("PADDED frame payload too short for pad length"))?
469 as usize;
470 if pad_len >= body.len() {
471 return Err(H2Error::protocol(
472 "padding length is the length of the frame payload or greater",
473 ));
474 }
475 *body = &body[1..body.len() - pad_len];
476 Ok(pad_len)
477}
478
479#[inline]
482fn read_priority(body: &mut &[u8], stream_id: u32) -> Result<Priority, H2Error> {
483 if body.len() < 5 {
484 return Err(H2Error::frame_size(
485 "frame payload too short for priority fields",
486 ));
487 }
488 let exclusive = body[0] & 0x80 != 0;
489 let dependency = u32::from_be_bytes([body[0], body[1], body[2], body[3]]) & 0x7fff_ffff;
490 if dependency == stream_id {
491 return Err(H2Error::protocol(
492 "stream priority depends on its own stream identifier",
493 ));
494 }
495 let weight = body[4];
496 *body = &body[5..];
497 Ok(Priority {
498 exclusive,
499 dependency,
500 weight,
501 })
502}
503
504#[inline]
505fn require_stream(stream_id: u32) -> Result<(), H2Error> {
506 if stream_id == 0 {
507 Err(H2Error::new(
508 Reason::ProtocolError,
509 "frame must use a non-zero stream identifier",
510 ))
511 } else {
512 Ok(())
513 }
514}
515
516#[inline]
520fn validate_setting(id: u16, value: u32) -> Result<(), H2Error> {
521 match id {
522 0x02 => {
523 if value > 1 {
525 return Err(H2Error::protocol("SETTINGS_ENABLE_PUSH must be 0 or 1"));
526 }
527 }
528 0x04 => {
529 if value > MAX_WINDOW_SIZE {
531 return Err(H2Error::new(
532 Reason::FlowControlError,
533 "SETTINGS_INITIAL_WINDOW_SIZE exceeds 2^31-1",
534 ));
535 }
536 }
537 0x05 if !(DEFAULT_MAX_FRAME_SIZE..=MAX_FRAME_SIZE_LIMIT).contains(&(value as usize)) => {
538 return Err(H2Error::protocol(
540 "SETTINGS_MAX_FRAME_SIZE outside 16384..16777215",
541 ));
542 }
543 _ => {}
544 }
545 Ok(())
546}
547
548#[inline]
549fn read_u32(bytes: &[u8]) -> u32 {
550 u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]])
551}
552
553#[derive(Debug, Clone, Copy, Default)]
557pub struct FrameWriter {
558 pub max_frame_size: usize,
561}
562
563impl FrameWriter {
564 pub const fn new(max_frame_size: usize) -> FrameWriter {
565 FrameWriter { max_frame_size }
566 }
567
568 #[inline]
569 fn header(out: &mut Vec<u8>, payload_len: usize, typ: u8, flags: u8, stream_id: u32) {
570 out.push(((payload_len >> 16) & 0xff) as u8);
571 out.push(((payload_len >> 8) & 0xff) as u8);
572 out.push((payload_len & 0xff) as u8);
573 out.push(typ);
574 out.push(flags);
575 out.push(((stream_id >> 24) & 0x7f) as u8);
576 out.push(((stream_id >> 16) & 0xff) as u8);
577 out.push(((stream_id >> 8) & 0xff) as u8);
578 out.push((stream_id & 0xff) as u8);
579 }
580
581 #[inline]
582 pub fn write_data(&self, out: &mut Vec<u8>, stream_id: u32, end_stream: bool, data: &[u8]) {
583 let flags = if end_stream { FLAG_END_STREAM } else { 0 };
584 FrameWriter::header(out, data.len(), DATA_TYPE, flags, stream_id);
585 out.extend_from_slice(data);
586 }
587
588 #[inline]
590 pub fn write_headers(
591 &self,
592 out: &mut Vec<u8>,
593 stream_id: u32,
594 end_stream: bool,
595 end_headers: bool,
596 priority: Option<Priority>,
597 block: &[u8],
598 ) {
599 let mut flags = 0;
600 if end_stream {
601 flags |= FLAG_END_STREAM;
602 }
603 if end_headers {
604 flags |= FLAG_END_HEADERS;
605 }
606 let extra = if priority.is_some() { 5 } else { 0 };
607 if extra != 0 {
608 flags |= FLAG_PRIORITY;
609 }
610 FrameWriter::header(out, block.len() + extra, HEADERS_TYPE, flags, stream_id);
611 if let Some(p) = priority {
612 let dep = p.dependency & 0x7fff_ffff | if p.exclusive { 0x8000_0000 } else { 0 };
613 out.extend_from_slice(&dep.to_be_bytes());
614 out.push(p.weight);
615 }
616 out.extend_from_slice(block);
617 }
618
619 #[inline]
623 pub fn write_field_block(
624 &self,
625 out: &mut Vec<u8>,
626 stream_id: u32,
627 end_stream: bool,
628 block: &[u8],
629 ) {
630 let capacity = self.max_frame_size;
631 if block.len() <= capacity {
632 self.write_headers(out, stream_id, end_stream, true, None, block);
633 return;
634 }
635 let first = &block[..capacity];
636 self.write_headers(out, stream_id, end_stream, false, None, first);
637 let mut rest = &block[capacity..];
638 while rest.len() > capacity {
639 self.write_continuation(out, stream_id, false, &rest[..capacity]);
640 rest = &rest[capacity..];
641 }
642 self.write_continuation(out, stream_id, true, rest);
643 }
644
645 #[inline]
646 pub fn write_priority(&self, out: &mut Vec<u8>, stream_id: u32, priority: Priority) {
647 let dep =
648 priority.dependency & 0x7fff_ffff | if priority.exclusive { 0x8000_0000 } else { 0 };
649 FrameWriter::header(out, 5, PRIORITY_TYPE, 0, stream_id);
650 out.extend_from_slice(&dep.to_be_bytes());
651 out.push(priority.weight);
652 }
653
654 #[inline]
655 pub fn write_reset(&self, out: &mut Vec<u8>, stream_id: u32, error_code: u32) {
656 FrameWriter::header(out, 4, RST_STREAM_TYPE, 0, stream_id);
657 out.extend_from_slice(&error_code.to_be_bytes());
658 }
659
660 #[inline]
661 pub fn write_settings(&self, out: &mut Vec<u8>, settings: &[Setting]) {
662 FrameWriter::header(out, settings.len() * 6, SETTINGS_TYPE, 0, 0);
663 for setting in settings {
664 out.extend_from_slice(&setting.id.to_be_bytes());
665 out.extend_from_slice(&setting.value.to_be_bytes());
666 }
667 }
668
669 #[inline]
670 pub fn write_settings_ack(&self, out: &mut Vec<u8>) {
671 FrameWriter::header(out, 0, SETTINGS_TYPE, FLAG_ACK, 0);
672 }
673
674 #[inline]
675 pub fn write_push_promise(
676 &self,
677 out: &mut Vec<u8>,
678 stream_id: u32,
679 promised_stream_id: u32,
680 block: &[u8],
681 ) {
682 FrameWriter::header(
683 out,
684 4 + block.len(),
685 PUSH_PROMISE_TYPE,
686 FLAG_END_HEADERS,
687 stream_id,
688 );
689 out.extend_from_slice(&(promised_stream_id & 0x7fff_ffff).to_be_bytes());
690 out.extend_from_slice(block);
691 }
692
693 #[inline]
694 pub fn write_ping(&self, out: &mut Vec<u8>, payload: &[u8; 8]) {
695 FrameWriter::header(out, 8, PING_TYPE, 0, 0);
696 out.extend_from_slice(payload);
697 }
698
699 #[inline]
700 pub fn write_ping_ack(&self, out: &mut Vec<u8>, payload: &[u8; 8]) {
701 FrameWriter::header(out, 8, PING_TYPE, FLAG_ACK, 0);
702 out.extend_from_slice(payload);
703 }
704
705 #[inline]
706 pub fn write_goaway(
707 &self,
708 out: &mut Vec<u8>,
709 last_stream_id: u32,
710 error_code: u32,
711 debug: &[u8],
712 ) {
713 FrameWriter::header(out, 8 + debug.len(), GOAWAY_TYPE, 0, 0);
714 out.extend_from_slice(&(last_stream_id & 0x7fff_ffff).to_be_bytes());
715 out.extend_from_slice(&error_code.to_be_bytes());
716 out.extend_from_slice(debug);
717 }
718
719 #[inline]
720 pub fn write_window_update(&self, out: &mut Vec<u8>, stream_id: u32, increment: u32) {
721 FrameWriter::header(out, 4, WINDOW_UPDATE_TYPE, 0, stream_id);
722 out.extend_from_slice(&(increment & 0x7fff_ffff).to_be_bytes());
723 }
724
725 #[inline]
726 pub fn write_continuation(
727 &self,
728 out: &mut Vec<u8>,
729 stream_id: u32,
730 end_headers: bool,
731 block: &[u8],
732 ) {
733 let flags = if end_headers { FLAG_END_HEADERS } else { 0 };
734 FrameWriter::header(out, block.len(), CONTINUATION_TYPE, flags, stream_id);
735 out.extend_from_slice(block);
736 }
737}
738
739#[cfg(test)]
740mod tests;