1use crate::frame::{self, FrameHeader, FrameType, flags, settings};
27use crate::hpack::{self, Decoder};
28use crate::{Error, headers, hpack::encode};
29
30pub const MAX_STREAMS: usize = 4;
33
34pub const MAX_HEADER_BLOCK: usize = 2048;
37
38pub const RECEIVE_WINDOW: u32 = 1 << 20;
46
47const DEFAULT_WINDOW: u32 = 65_535;
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51struct Stream {
52 id: u32,
53 consumed: u32,
55 open: bool,
56 send_window: i64,
57 head_request: bool,
58 connect_request: bool,
59 response_started: bool,
60 no_body: bool,
61 content_length: Option<u64>,
62 received: u64,
63}
64
65#[derive(Debug, PartialEq, Eq)]
67pub enum Event<'a> {
68 Nothing,
72 Headers { stream: u32, end_stream: bool },
74 Data {
77 stream: u32,
78 data: &'a [u8],
79 end_stream: bool,
80 },
81 Reset { stream: u32, code: u32 },
83 GoAway { code: u32 },
85}
86
87pub struct Connection {
88 decoder: Decoder,
89 streams: heapless::Vec<Stream, MAX_STREAMS>,
90 next_stream: u32,
91 header_block: heapless::Vec<u8, MAX_HEADER_BLOCK>,
93 header_stream: u32,
95 header_end_stream: bool,
96 consumed: u32,
98 peer_max_frame: usize,
100 send_window: u32,
101 peer_initial_window: u32,
102 peer_max_streams: u32,
103 goaway: bool,
104}
105
106impl Default for Connection {
107 fn default() -> Self {
108 Self::new()
109 }
110}
111
112impl Connection {
113 pub fn new() -> Self {
114 Self {
115 decoder: Decoder::new(hpack::DEFAULT_TABLE_SIZE),
116 streams: heapless::Vec::new(),
117 next_stream: 1,
119 header_block: heapless::Vec::new(),
120 header_stream: 0,
121 header_end_stream: false,
122 consumed: 0,
123 peer_max_frame: frame::DEFAULT_MAX_FRAME,
124 send_window: DEFAULT_WINDOW,
125 peer_initial_window: DEFAULT_WINDOW,
126 peer_max_streams: u32::MAX,
127 goaway: false,
128 }
129 }
130
131 pub fn start(&mut self, out: &mut [u8]) -> Result<usize, Error> {
134 let preface = frame::CLIENT_PREFACE;
135 out.get_mut(..preface.len())
136 .ok_or(Error::BufferTooSmall)?
137 .copy_from_slice(preface);
138 let mut len = preface.len();
139
140 let mut payload = [0u8; 24];
143 write_setting(
144 &mut payload[0..6],
145 settings::HEADER_TABLE_SIZE,
146 hpack::DEFAULT_TABLE_SIZE as u32,
147 );
148 write_setting(&mut payload[6..12], settings::ENABLE_PUSH, 0);
149 write_setting(
150 &mut payload[12..18],
151 settings::INITIAL_WINDOW_SIZE,
152 RECEIVE_WINDOW,
153 );
154 write_setting(
155 &mut payload[18..24],
156 settings::MAX_CONCURRENT_STREAMS,
157 MAX_STREAMS as u32,
158 );
159 len += frame::write_frame(FrameType::Settings, 0, 0, &payload, &mut out[len..])?;
160
161 let increment = (RECEIVE_WINDOW - DEFAULT_WINDOW).to_be_bytes();
164 len += frame::write_frame(FrameType::WindowUpdate, 0, 0, &increment, &mut out[len..])?;
165 Ok(len)
166 }
167
168 #[allow(clippy::too_many_arguments)]
174 pub fn request(
175 &mut self,
176 method: &str,
177 path: &str,
178 authority: &str,
179 scheme: &str,
180 extra: &[(&str, &str)],
181 body: &[u8],
182 out: &mut [u8],
183 ) -> Result<(u32, usize), Error> {
184 if self.goaway {
185 return Err(Error::GoAway);
186 }
187 let id = self.next_stream;
188 if self.streams.len() as u32 >= self.peer_max_streams {
189 return Err(Error::TooManyStreams);
190 }
191 if self.streams.is_full() || id > 0x7fff_ffff {
192 return Err(Error::TooManyStreams);
193 }
194
195 if method.is_empty()
196 || !method.bytes().all(headers::token)
197 || (method != "CONNECT"
198 && (!headers::path_valid(method, path) || !headers::scheme_valid(scheme)))
199 {
200 return Err(Error::Protocol);
201 }
202 let mut content_length = None;
203 let mut host = None;
204 for &(name, value) in extra {
205 headers::field(name, value, true)?;
206 if name == "host" && authority.is_empty() && host.replace(value).is_some() {
207 return Err(Error::Protocol);
208 }
209 if name == "content-length" {
210 headers::content_length(value, &mut content_length)?;
211 }
212 }
213 let authority = if authority.is_empty() {
214 host.unwrap_or("")
215 } else {
216 authority
217 };
218 if !headers::authority_valid(authority, scheme, method == "CONNECT") {
219 return Err(Error::Protocol);
220 }
221 if content_length.is_some_and(|length| length != body.len() as u64) {
222 return Err(Error::Protocol);
223 }
224
225 let mut block = [0u8; MAX_HEADER_BLOCK];
228 let mut block_len = 0;
229 block_len = encode::encode_header(":method", method, &mut block, block_len)?;
230 if method != "CONNECT" {
231 block_len = encode::encode_header(":path", path, &mut block, block_len)?;
232 block_len = encode::encode_header(":scheme", scheme, &mut block, block_len)?;
233 }
234 if !authority.is_empty() {
235 block_len = encode::encode_header(":authority", authority, &mut block, block_len)?;
236 }
237 let mut length_written = false;
238 for (name, value) in extra {
239 if *name == "host" {
242 continue;
243 }
244 if *name == "content-length" {
245 if length_written {
246 continue;
247 }
248 use core::fmt::Write;
251 let mut canonical = heapless::String::<20>::new();
252 write!(&mut canonical, "{}", body.len()).map_err(|_| Error::BufferTooSmall)?;
253 block_len = encode::encode_header(name, &canonical, &mut block, block_len)?;
254 length_written = true;
255 } else {
256 let value = if *name == "te" { "trailers" } else { value };
257 block_len = encode::encode_header(name, value, &mut block, block_len)?;
258 }
259 }
260
261 if block_len > self.peer_max_frame {
264 return Err(Error::FrameTooLarge);
265 }
266
267 if body.len() > self.peer_max_frame {
268 return Err(Error::FrameTooLarge);
269 }
270 if body.len() > self.send_window as usize || body.len() > self.peer_initial_window as usize
271 {
272 return Err(Error::FlowControl);
273 }
274 let required = frame::HEADER_LEN
275 + block_len
276 + if body.is_empty() {
277 0
278 } else {
279 frame::HEADER_LEN + body.len()
280 };
281 if out.len() < required {
282 return Err(Error::BufferTooSmall);
283 }
284
285 let end_stream = if body.is_empty() {
286 flags::END_STREAM
287 } else {
288 0
289 };
290 let mut len = frame::write_frame(
291 FrameType::Headers,
292 flags::END_HEADERS | end_stream,
293 id,
294 &block[..block_len],
295 out,
296 )?;
297
298 if !body.is_empty() {
299 len += frame::write_frame(
300 FrameType::Data,
301 flags::END_STREAM,
302 id,
303 body,
304 &mut out[len..],
305 )?;
306 }
307 self.streams
308 .push(Stream {
309 id,
310 consumed: 0,
311 open: true,
312 send_window: self.peer_initial_window as i64 - body.len() as i64,
313 head_request: method == "HEAD",
314 connect_request: method == "CONNECT",
315 response_started: false,
316 no_body: false,
317 content_length: None,
318 received: 0,
319 })
320 .map_err(|_| Error::TooManyStreams)?;
321 self.next_stream += 2;
322 self.send_window -= body.len() as u32;
323 Ok((id, len))
324 }
325
326 pub fn recv<'a>(
332 &mut self,
333 bytes: &'a [u8],
334 mut on_header: impl FnMut(&str, &str),
335 out: &mut [u8],
336 ) -> Result<(Event<'a>, usize), Error> {
337 let header = FrameHeader::parse(bytes)?;
338 let payload = bytes
339 .get(frame::HEADER_LEN..frame::HEADER_LEN + header.length)
340 .ok_or(Error::Incomplete)?;
341 if header.length > frame::DEFAULT_MAX_FRAME {
342 return Err(Error::FrameTooLarge);
343 }
344 if self.header_stream != 0 {
345 if header.kind != FrameType::Continuation || header.stream != self.header_stream {
346 return Err(Error::Protocol);
347 }
348 } else if header.kind == FrameType::Continuation {
349 return Err(Error::Protocol);
350 }
351 match header.kind {
352 FrameType::Settings
353 if header.stream != 0 || (header.has(flags::ACK) && !payload.is_empty()) =>
354 {
355 return Err(Error::Protocol);
356 }
357 FrameType::Ping if header.stream != 0 || payload.len() != 8 => {
358 return Err(Error::Protocol);
359 }
360 FrameType::GoAway if header.stream != 0 || payload.len() < 8 => {
361 return Err(Error::Protocol);
362 }
363 FrameType::Headers | FrameType::Data | FrameType::Continuation
364 if header.stream == 0 =>
365 {
366 return Err(Error::Protocol);
367 }
368 FrameType::RstStream if header.stream == 0 || payload.len() != 4 => {
369 return Err(Error::Protocol);
370 }
371 FrameType::Priority if header.stream == 0 || payload.len() != 5 => {
372 return Err(Error::Protocol);
373 }
374 FrameType::WindowUpdate
375 if payload.len() != 4 || read_u32(payload).unwrap() & 0x7fff_ffff == 0 =>
376 {
377 return Err(Error::Protocol);
378 }
379 _ => {}
380 }
381 if matches!(
382 header.kind,
383 FrameType::Headers | FrameType::Data | FrameType::RstStream | FrameType::WindowUpdate
384 ) && header.stream != 0
385 {
386 self.known_stream(header.stream)?;
387 }
388 let mut written = 0;
389
390 match header.kind {
391 FrameType::Settings => {
392 if !header.has(flags::ACK) {
393 self.apply_settings(payload)?;
394 written = frame::write_frame(FrameType::Settings, flags::ACK, 0, &[], out)?;
396 }
397 Ok((Event::Nothing, written))
398 }
399
400 FrameType::Ping => {
401 if !header.has(flags::ACK) {
402 written = frame::write_frame(FrameType::Ping, flags::ACK, 0, payload, out)?;
404 }
405 Ok((Event::Nothing, written))
406 }
407
408 FrameType::Headers | FrameType::Continuation => {
409 let block = if header.kind == FrameType::Headers {
410 self.header_block.clear();
411 self.header_stream = header.stream;
412 self.header_end_stream = header.has(flags::END_STREAM);
413 let body = frame::strip_padding(payload, header.flags)?;
414 if header.has(flags::PRIORITY) {
417 body.get(5..).ok_or(Error::Protocol)?
418 } else {
419 body
420 }
421 } else {
422 payload
423 };
424
425 self.header_block
426 .extend_from_slice(block)
427 .map_err(|_| Error::BufferTooSmall)?;
428
429 if !header.has(flags::END_HEADERS) {
430 return Ok((Event::Nothing, 0));
433 }
434
435 let stream = self.header_stream;
436 let end_stream = self.header_end_stream;
437 let active = self.streams.iter().position(|entry| entry.id == stream);
438 if let Some(index) = active {
439 if self.streams[index].response_started {
440 return Err(Error::Protocol);
442 }
443 let mut preflight = self.decoder.clone();
447 let mut fields = headers::ResponseHeaders::default();
448 let mut valid = Ok(());
449 preflight.decode(&self.header_block, |name, value| {
450 if valid.is_ok() {
451 valid = fields.field(name, value);
452 }
453 })?;
454 valid?;
455 let status = fields.status.ok_or(Error::Protocol)?;
456 if status < 200 {
457 if end_stream || fields.content_length.is_some() {
458 return Err(Error::Protocol);
459 }
460 } else {
461 let entry = &mut self.streams[index];
462 let tunnel = entry.connect_request && (200..300).contains(&status);
463 if !tunnel
468 && ((status == 204 && fields.content_length.is_some())
469 || (status == 205
470 && fields.content_length.is_some_and(|length| length != 0)))
471 {
472 return Err(Error::Protocol);
473 }
474 let no_body =
475 !tunnel && (entry.head_request || matches!(status, 204 | 205 | 304));
476 let expected = if no_body || tunnel {
477 None
478 } else {
479 fields.content_length
480 };
481 if end_stream && expected.is_some_and(|length| length != 0) {
482 return Err(Error::Protocol);
483 }
484 entry.response_started = true;
485 entry.no_body = no_body;
486 entry.content_length = expected;
487 }
488 self.decoder.decode(&self.header_block, &mut on_header)?;
489 } else {
490 self.decoder.decode(&self.header_block, |_, _| {})?;
493 }
494 self.header_stream = 0;
495 self.header_block.clear();
496 if active.is_none() {
497 return Ok((Event::Nothing, 0));
498 }
499 if end_stream {
500 self.close(stream);
501 }
502 Ok((Event::Headers { stream, end_stream }, 0))
503 }
504
505 FrameType::Data => {
506 let data = frame::strip_padding(payload, header.flags)?;
507 let end_stream = header.has(flags::END_STREAM);
508 let active = self
509 .streams
510 .iter()
511 .position(|entry| entry.id == header.stream);
512 let received = active
513 .map(|index| self.data_length(index, data.len(), end_stream))
514 .transpose()?;
515 written = self.credit(header.stream, header.length as u32, out)?;
518 let Some(index) = active else {
519 return Ok((Event::Nothing, written));
520 };
521 self.streams[index].received = received.unwrap();
522 if end_stream {
523 self.close(header.stream);
524 }
525 Ok((
526 Event::Data {
527 stream: header.stream,
528 data,
529 end_stream,
530 },
531 written,
532 ))
533 }
534
535 FrameType::RstStream => {
536 let code = read_u32(payload).ok_or(Error::Protocol)?;
537 if !self.streams.iter().any(|entry| entry.id == header.stream) {
538 return Ok((Event::Nothing, 0));
539 }
540 self.close(header.stream);
541 Ok((
542 Event::Reset {
543 stream: header.stream,
544 code,
545 },
546 0,
547 ))
548 }
549
550 FrameType::GoAway => {
551 let code = payload
553 .get(4..8)
554 .and_then(read_u32)
555 .ok_or(Error::Protocol)?;
556 self.goaway = true;
557 Ok((Event::GoAway { code }, 0))
558 }
559
560 FrameType::WindowUpdate => {
561 let increment = read_u32(payload).ok_or(Error::Protocol)? & 0x7fff_ffff;
562 if header.stream == 0 {
563 self.send_window = self
564 .send_window
565 .checked_add(increment)
566 .filter(|value| *value <= 0x7fff_ffff)
567 .ok_or(Error::Protocol)?;
568 } else if let Some(stream) = self.streams.iter_mut().find(|s| s.id == header.stream)
569 {
570 let window = stream.send_window + increment as i64;
571 if window > 0x7fff_ffff {
572 return Err(Error::Protocol);
573 }
574 stream.send_window = window;
575 }
576 Ok((Event::Nothing, 0))
577 }
578 FrameType::Priority => Ok((Event::Nothing, 0)),
579
580 FrameType::PushPromise => Err(Error::Protocol),
583
584 FrameType::Unknown(_) => Ok((Event::Nothing, 0)),
586 }
587 }
588
589 pub fn finish_data(&mut self, header: FrameHeader, out: &mut [u8]) -> Result<usize, Error> {
598 if header.has(flags::PADDED) {
599 return Err(Error::Protocol);
600 }
601 self.finish_data_with_length(header, header.length, out)
602 }
603
604 pub fn finish_data_with_length(
608 &mut self,
609 header: FrameHeader,
610 data_length: usize,
611 out: &mut [u8],
612 ) -> Result<usize, Error> {
613 if header.kind != FrameType::Data || header.stream == 0 || self.header_stream != 0 {
614 return Err(Error::Protocol);
615 }
616 if header.length > frame::DEFAULT_MAX_FRAME {
617 return Err(Error::FrameTooLarge);
618 }
619 let padding = header
620 .length
621 .checked_sub(data_length)
622 .ok_or(Error::Protocol)?;
623 if (header.has(flags::PADDED) && !(1..=256).contains(&padding))
624 || (!header.has(flags::PADDED) && padding != 0)
625 {
626 return Err(Error::Protocol);
627 }
628 self.known_stream(header.stream)?;
629 let active = self
630 .streams
631 .iter()
632 .position(|entry| entry.id == header.stream);
633 let received = active
634 .map(|index| self.data_length(index, data_length, header.has(flags::END_STREAM)))
635 .transpose()?;
636 let written = self.credit(header.stream, header.length as u32, out)?;
637 if let Some(index) = active {
638 self.streams[index].received = received.unwrap();
639 }
640 if header.has(flags::END_STREAM) {
641 self.close(header.stream);
642 }
643 Ok(written)
644 }
645
646 fn known_stream(&self, stream: u32) -> Result<(), Error> {
647 if stream & 1 == 0 || stream >= self.next_stream {
649 return Err(Error::Protocol);
650 }
651 Ok(())
652 }
653
654 fn data_length(&self, index: usize, length: usize, end_stream: bool) -> Result<u64, Error> {
655 let entry = &self.streams[index];
656 if !entry.response_started || (entry.no_body && length != 0) {
657 return Err(Error::Protocol);
658 }
659 let received = entry
660 .received
661 .checked_add(length as u64)
662 .ok_or(Error::Protocol)?;
663 if entry
664 .content_length
665 .is_some_and(|expected| received > expected || (end_stream && received != expected))
666 {
667 return Err(Error::Protocol);
668 }
669 Ok(received)
670 }
671
672 fn credit(&mut self, stream: u32, length: u32, out: &mut [u8]) -> Result<usize, Error> {
674 if length == 0 {
675 return Ok(0);
676 }
677 const THRESHOLD: u32 = RECEIVE_WINDOW / 2;
678 let consumed = self.consumed.checked_add(length).ok_or(Error::Protocol)?;
679 let stream_consumed = self
680 .streams
681 .iter()
682 .find(|s| s.id == stream)
683 .map(|entry| entry.consumed.checked_add(length).ok_or(Error::Protocol))
684 .transpose()?;
685 let connection_update = consumed >= THRESHOLD;
686 let stream_update = stream_consumed.is_some_and(|value| value >= THRESHOLD);
687 let required =
688 (connection_update as usize + stream_update as usize) * (frame::HEADER_LEN + 4);
689 if out.len() < required {
690 return Err(Error::BufferTooSmall);
691 }
692 let mut written = 0;
693 if connection_update {
694 written +=
695 frame::write_frame(FrameType::WindowUpdate, 0, 0, &consumed.to_be_bytes(), out)?;
696 }
697 if stream_update {
698 written += frame::write_frame(
699 FrameType::WindowUpdate,
700 0,
701 stream,
702 &stream_consumed.unwrap().to_be_bytes(),
703 &mut out[written..],
704 )?;
705 }
706 self.consumed = if connection_update { 0 } else { consumed };
707 if let Some(entry) = self.streams.iter_mut().find(|s| s.id == stream) {
708 entry.consumed = if stream_update {
709 0
710 } else {
711 stream_consumed.unwrap()
712 };
713 }
714 Ok(written)
715 }
716
717 fn apply_settings(&mut self, payload: &[u8]) -> Result<(), Error> {
718 if !payload.len().is_multiple_of(6) {
719 return Err(Error::Protocol);
720 }
721 for entry in payload.as_chunks::<6>().0 {
722 let identifier = u16::from_be_bytes([entry[0], entry[1]]);
723 let value = u32::from_be_bytes([entry[2], entry[3], entry[4], entry[5]]);
724 match identifier {
725 settings::MAX_FRAME_SIZE => {
726 if !(16_384..=16_777_215).contains(&value) {
727 return Err(Error::Protocol);
728 }
729 self.peer_max_frame = value as usize;
730 }
731 settings::INITIAL_WINDOW_SIZE => {
732 if value > 0x7fff_ffff {
733 return Err(Error::Protocol);
734 }
735 let delta = value as i64 - self.peer_initial_window as i64;
736 if self
737 .streams
738 .iter()
739 .any(|stream| stream.send_window + delta > 0x7fff_ffff)
740 {
741 return Err(Error::Protocol);
742 }
743 for stream in &mut self.streams {
744 stream.send_window += delta;
745 }
746 self.peer_initial_window = value;
747 }
748 settings::MAX_CONCURRENT_STREAMS => self.peer_max_streams = value,
749 settings::ENABLE_PUSH => return Err(Error::Protocol),
750 settings::HEADER_TABLE_SIZE => {}
754 _ => {}
756 }
757 }
758 Ok(())
759 }
760
761 fn close(&mut self, stream: u32) {
762 if let Some(entry) = self.streams.iter_mut().find(|s| s.id == stream) {
763 entry.open = false;
764 }
765 self.streams.retain(|s| s.open);
766 }
767
768 pub fn open_streams(&self) -> usize {
769 self.streams.len()
770 }
771}
772
773fn write_setting(out: &mut [u8], identifier: u16, value: u32) {
774 out[0..2].copy_from_slice(&identifier.to_be_bytes());
775 out[2..6].copy_from_slice(&value.to_be_bytes());
776}
777
778fn read_u32(bytes: &[u8]) -> Option<u32> {
779 Some(u32::from_be_bytes(bytes.get(..4)?.try_into().ok()?))
780}
781
782#[cfg(test)]
783mod tests {
784 use super::*;
785
786 fn frame_bytes(
788 kind: FrameType,
789 flags: u8,
790 stream: u32,
791 payload: &[u8],
792 ) -> heapless::Vec<u8, 512> {
793 let mut out = heapless::Vec::<u8, 512>::new();
794 out.resize_default(512).unwrap();
795 let len = frame::write_frame(kind, flags, stream, payload, &mut out).unwrap();
796 out.truncate(len);
797 out
798 }
799
800 fn open_connection() -> Connection {
801 let mut connection = Connection::new();
802 connection
803 .request("GET", "/", "h", "https", &[], b"", &mut [0; 256])
804 .unwrap();
805 connection
806 }
807
808 fn response_connection() -> Connection {
809 let mut connection = open_connection();
810 let headers = frame_bytes(FrameType::Headers, flags::END_HEADERS, 1, &[0x88]);
811 connection.recv(&headers, |_, _| {}, &mut [0; 64]).unwrap();
812 connection
813 }
814
815 #[test]
816 fn the_preface_is_exactly_what_the_rfc_requires() {
817 let mut connection = Connection::new();
818 let mut out = [0u8; 128];
819 let len = connection.start(&mut out).unwrap();
820 assert!(out[..len].starts_with(b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"));
821
822 let after = &out[frame::CLIENT_PREFACE.len()..len];
825 let settings = FrameHeader::parse(after).unwrap();
826 assert_eq!(settings.kind, FrameType::Settings);
827 assert_eq!(settings.stream, 0);
828
829 let update = &after[frame::HEADER_LEN + settings.length..];
830 let update_header = FrameHeader::parse(update).unwrap();
831 assert_eq!(update_header.kind, FrameType::WindowUpdate);
832 assert_eq!(update_header.stream, 0);
833 let increment = read_u32(&update[frame::HEADER_LEN..]).unwrap();
834 assert_eq!(increment, RECEIVE_WINDOW - DEFAULT_WINDOW);
835 }
836
837 #[test]
838 fn a_request_opens_an_odd_numbered_stream_and_ends_it() {
839 let mut connection = Connection::new();
840 let mut out = [0u8; 512];
841 let (stream, len) = connection
842 .request(
843 "POST",
844 "/machine/register",
845 "127.0.0.1:8080",
846 "http",
847 &[("content-type", "application/json")],
848 b"{}",
849 &mut out,
850 )
851 .unwrap();
852
853 assert_eq!(stream, 1);
855 let headers = FrameHeader::parse(&out).unwrap();
856 assert_eq!(headers.kind, FrameType::Headers);
857 assert!(headers.has(flags::END_HEADERS));
858 assert!(!headers.has(flags::END_STREAM), "a body follows");
859
860 let data = FrameHeader::parse(&out[frame::HEADER_LEN + headers.length..]).unwrap();
861 assert_eq!(data.kind, FrameType::Data);
862 assert!(data.has(flags::END_STREAM));
863 assert_eq!(len, frame::HEADER_LEN * 2 + headers.length + data.length);
864
865 let (second, _) = connection
867 .request("GET", "/", "h", "http", &[], b"", &mut out)
868 .unwrap();
869 assert_eq!(second, 3);
870 }
871
872 #[test]
873 fn settings_are_acknowledged_and_an_ack_is_not() {
874 let mut connection = Connection::new();
875 let mut out = [0u8; 128];
876
877 let settings = frame_bytes(FrameType::Settings, 0, 0, &[0, 5, 0, 0, 0x40, 0]);
878 let (event, written) = connection.recv(&settings, |_, _| {}, &mut out).unwrap();
879 assert_eq!(event, Event::Nothing);
880 let ack = FrameHeader::parse(&out[..written]).unwrap();
881 assert_eq!(ack.kind, FrameType::Settings);
882 assert!(ack.has(flags::ACK));
883 assert_eq!(ack.length, 0);
884
885 let their_ack = frame_bytes(FrameType::Settings, flags::ACK, 0, &[]);
887 let (_, written) = connection.recv(&their_ack, |_, _| {}, &mut out).unwrap();
888 assert_eq!(written, 0);
889 }
890
891 #[test]
892 fn peer_encoder_settings_do_not_reset_receive_hpack_state() {
893 let mut connection = Connection::new();
894 connection
895 .decoder
896 .decode(&[0x40, 0x01, b'x', 0x01, b'y'], |_, _| {})
897 .unwrap();
898 assert_eq!(connection.decoder.table().len(), 1);
899
900 let settings = frame_bytes(FrameType::Settings, 0, 0, &[0, 1, 0, 0, 0x10, 0]);
901 let mut out = [0u8; 64];
902 connection.recv(&settings, |_, _| {}, &mut out).unwrap();
903 assert_eq!(connection.decoder.table().len(), 1);
904 assert_eq!(
905 connection.decoder.table().capacity(),
906 hpack::DEFAULT_TABLE_SIZE
907 );
908 }
909
910 #[test]
911 fn a_ping_is_echoed_exactly() {
912 let mut connection = Connection::new();
913 let mut out = [0u8; 128];
914 let payload = [1, 2, 3, 4, 5, 6, 7, 8];
915 let ping = frame_bytes(FrameType::Ping, 0, 0, &payload);
916 let (_, written) = connection.recv(&ping, |_, _| {}, &mut out).unwrap();
917 let header = FrameHeader::parse(&out[..written]).unwrap();
918 assert!(header.has(flags::ACK));
919 assert_eq!(&out[frame::HEADER_LEN..written], &payload);
920 }
921
922 #[test]
923 fn a_header_block_split_across_continuation_frames_is_reassembled() {
924 let mut connection = open_connection();
927 let mut out = [0u8; 256];
928
929 let first = frame_bytes(FrameType::Headers, 0, 1, &[0x88]);
931 let (event, _) = connection.recv(&first, |_, _| {}, &mut out).unwrap();
932 assert_eq!(
933 event,
934 Event::Nothing,
935 "an unterminated block yields nothing"
936 );
937
938 let mut seen = heapless::Vec::<(heapless::String<32>, heapless::String<32>), 4>::new();
939 let second = frame_bytes(
940 FrameType::Continuation,
941 flags::END_HEADERS,
942 1,
943 &[0, 1, b'x', 1, b'y'],
944 );
945 let (event, _) = connection
946 .recv(
947 &second,
948 |name, value| {
949 let mut n = heapless::String::new();
950 let mut v = heapless::String::new();
951 n.push_str(name).unwrap();
952 v.push_str(value).unwrap();
953 seen.push((n, v)).unwrap();
954 },
955 &mut out,
956 )
957 .unwrap();
958
959 assert!(matches!(event, Event::Headers { stream: 1, .. }));
960 assert_eq!(seen.len(), 2);
961 assert_eq!(seen[0].0.as_str(), ":status");
962 assert_eq!(seen[0].1.as_str(), "200");
963 assert_eq!(seen[1].0.as_str(), "x");
964 }
965
966 #[test]
967 fn data_returns_the_payload_and_eventually_a_window_update() {
968 let mut connection = response_connection();
969 let mut out = [0u8; 256];
970
971 let data = frame_bytes(FrameType::Data, 0, 1, b"hello");
972 let (event, written) = connection.recv(&data, |_, _| {}, &mut out).unwrap();
973 assert_eq!(
974 event,
975 Event::Data {
976 stream: 1,
977 data: b"hello",
978 end_stream: false
979 }
980 );
981 assert_eq!(written, 0);
984 }
985
986 #[test]
987 fn a_long_response_gets_its_window_topped_up_before_it_can_stall() {
988 let mut connection = response_connection();
991 let mut out = [0u8; 256];
992 let payload = [0u8; 400];
993
994 let mut updates = 0;
995 let mut delivered = 0usize;
996 let frames = 2_000;
1000 for _ in 0..frames {
1001 let data = frame_bytes(FrameType::Data, 0, 1, &payload);
1002 let (event, written) = connection.recv(&data, |_, _| {}, &mut out).unwrap();
1003 if let Event::Data { data, .. } = event {
1004 delivered += data.len();
1005 }
1006 if written > 0 {
1007 updates += 1;
1008 let header = FrameHeader::parse(&out[..written]).unwrap();
1009 assert_eq!(header.kind, FrameType::WindowUpdate);
1010 }
1011 }
1012 assert_eq!(delivered, frames * 400);
1013 assert!(
1014 updates > 0,
1015 "the connection window must be replenished, or the server stops at 65535 bytes"
1016 );
1017 }
1018
1019 #[test]
1020 fn padding_and_priority_are_stripped_before_hpack_sees_the_block() {
1021 let mut connection = open_connection();
1022 let mut out = [0u8; 256];
1023 let payload = [2, 0, 0, 0, 0, 0, 0x88, 0xaa, 0xbb];
1025 let headers = frame_bytes(
1026 FrameType::Headers,
1027 flags::END_HEADERS | flags::PADDED | flags::PRIORITY,
1028 1,
1029 &payload,
1030 );
1031 let mut status = heapless::String::<8>::new();
1032 connection
1033 .recv(
1034 &headers,
1035 |name, value| {
1036 if name == ":status" {
1037 status.push_str(value).unwrap();
1038 }
1039 },
1040 &mut out,
1041 )
1042 .unwrap();
1043 assert_eq!(status.as_str(), "200");
1044 }
1045
1046 #[test]
1047 fn goaway_and_reset_are_reported_rather_than_hidden() {
1048 let mut connection = open_connection();
1049 let mut out = [0u8; 128];
1050
1051 let reset = frame_bytes(FrameType::RstStream, 0, 1, &[0, 0, 0, 8]);
1052 let (event, _) = connection.recv(&reset, |_, _| {}, &mut out).unwrap();
1053 assert_eq!(event, Event::Reset { stream: 1, code: 8 });
1054
1055 let goaway = frame_bytes(FrameType::GoAway, 0, 0, &[0, 0, 0, 1, 0, 0, 0, 2]);
1056 let (event, _) = connection.recv(&goaway, |_, _| {}, &mut out).unwrap();
1057 assert_eq!(event, Event::GoAway { code: 2 });
1058 }
1059
1060 #[test]
1061 fn a_promised_push_is_a_protocol_error_because_we_refused_push() {
1062 let mut connection = Connection::new();
1063 let mut out = [0u8; 128];
1064 let promise = frame_bytes(FrameType::PushPromise, flags::END_HEADERS, 1, &[0, 0, 0, 2]);
1065 assert_eq!(
1066 connection.recv(&promise, |_, _| {}, &mut out).err(),
1067 Some(Error::Protocol)
1068 );
1069 }
1070
1071 #[test]
1072 fn an_unknown_frame_type_is_discarded_not_fatal() {
1073 let mut connection = Connection::new();
1074 let mut out = [0u8; 128];
1075 let unknown = frame_bytes(FrameType::Unknown(0x63), 0, 0, b"whatever");
1076 let (event, written) = connection.recv(&unknown, |_, _| {}, &mut out).unwrap();
1077 assert_eq!(event, Event::Nothing);
1078 assert_eq!(written, 0);
1079 }
1080 #[test]
1081 fn failed_requests_do_not_consume_stream_slots_or_identifiers() {
1082 let mut connection = Connection::new();
1083 for _ in 0..MAX_STREAMS + 1 {
1084 assert_eq!(
1085 connection.request("GET", "/", "h", "https", &[], b"", &mut []),
1086 Err(Error::BufferTooSmall)
1087 );
1088 assert_eq!(connection.open_streams(), 0);
1089 }
1090 let mut out = [0u8; 128];
1091 assert_eq!(
1092 connection
1093 .request("GET", "/", "h", "https", &[], b"", &mut out)
1094 .unwrap()
1095 .0,
1096 1
1097 );
1098 }
1099
1100 #[test]
1101 fn continuation_must_follow_headers_on_the_same_stream() {
1102 for (kind, stream) in [
1103 (FrameType::Continuation, 3),
1104 (FrameType::Ping, 0),
1105 (FrameType::Headers, 3),
1106 ] {
1107 let mut connection = open_connection();
1108 let mut out = [0u8; 128];
1109 let first = frame_bytes(FrameType::Headers, 0, 1, &[0x88]);
1110 connection.recv(&first, |_, _| {}, &mut out).unwrap();
1111 let next = frame_bytes(kind, flags::END_HEADERS, stream, &[0x82]);
1112 assert_eq!(
1113 connection.recv(&next, |_, _| {}, &mut out).err(),
1114 Some(Error::Protocol)
1115 );
1116 }
1117 let mut connection = open_connection();
1118 let orphan = frame_bytes(FrameType::Continuation, flags::END_HEADERS, 1, &[0x88]);
1119 assert_eq!(
1120 connection.recv(&orphan, |_, _| {}, &mut [0u8; 128]).err(),
1121 Some(Error::Protocol)
1122 );
1123 }
1124 #[test]
1125 fn request_body_waits_for_connection_and_stream_credit() {
1126 let mut connection = Connection::new();
1127 let mut out = [0u8; 256];
1128 let zero = frame_bytes(FrameType::Settings, 0, 0, &[0, 4, 0, 0, 0, 0]);
1129 connection.recv(&zero, |_, _| {}, &mut out).unwrap();
1130 assert_eq!(
1131 connection.request("POST", "/", "h", "https", &[], b"a", &mut out),
1132 Err(Error::FlowControl)
1133 );
1134 assert_eq!(connection.open_streams(), 0);
1135 let one = frame_bytes(FrameType::Settings, 0, 0, &[0, 4, 0, 0, 0, 1]);
1136 connection.recv(&one, |_, _| {}, &mut out).unwrap();
1137 connection.send_window = 0;
1138 assert_eq!(
1139 connection.request("POST", "/", "h", "https", &[], b"a", &mut out),
1140 Err(Error::FlowControl)
1141 );
1142 let update = frame_bytes(FrameType::WindowUpdate, 0, 0, &[0, 0, 0, 1]);
1143 connection.recv(&update, |_, _| {}, &mut out).unwrap();
1144 assert_eq!(
1145 connection
1146 .request("POST", "/", "h", "https", &[], b"a", &mut out)
1147 .unwrap()
1148 .0,
1149 1
1150 );
1151 assert_eq!(connection.send_window, 0);
1152 }
1153
1154 #[test]
1155 fn exhausted_connection_credit_blocks_later_small_requests() {
1156 let mut connection = Connection::new();
1157 let mut out = [0u8; 17_000];
1158 for _ in 0..4 {
1159 let (id, _) = connection
1160 .request("POST", "/", "h", "https", &[], &[0; 16_000], &mut out)
1161 .unwrap();
1162 connection.close(id);
1163 }
1164 assert_eq!(
1165 connection.request("POST", "/", "h", "https", &[], &[0; 2_000], &mut out),
1166 Err(Error::FlowControl)
1167 );
1168 }
1169
1170 #[test]
1171 fn failed_credit_output_can_be_retried_without_double_counting() {
1172 let mut connection = Connection::new();
1173 let mut out = [0u8; 128];
1174 let (id, _) = connection
1175 .request("GET", "/", "h", "https", &[], b"", &mut out)
1176 .unwrap();
1177 let headers = frame_bytes(FrameType::Headers, flags::END_HEADERS, id, &[0x88]);
1178 connection.recv(&headers, |_, _| {}, &mut out).unwrap();
1179 connection.consumed = RECEIVE_WINDOW / 2 - 1;
1180 connection.streams[0].consumed = RECEIVE_WINDOW / 2 - 1;
1181 let data = frame_bytes(FrameType::Data, 0, id, b"a");
1182 assert_eq!(
1183 connection.recv(&data, |_, _| {}, &mut out[..13]).err(),
1184 Some(Error::BufferTooSmall)
1185 );
1186 assert_eq!(connection.consumed, RECEIVE_WINDOW / 2 - 1);
1187 let (_, written) = connection.recv(&data, |_, _| {}, &mut out).unwrap();
1188 assert_eq!(written, 26);
1189 assert_eq!(read_u32(&out[9..13]), Some(RECEIVE_WINDOW / 2));
1190 assert_eq!(read_u32(&out[22..26]), Some(RECEIVE_WINDOW / 2));
1191 }
1192
1193 #[test]
1194 fn settings_stream_limits_and_goaway_stop_new_requests() {
1195 let mut connection = Connection::new();
1196 let mut out = [0u8; 128];
1197 let zero = frame_bytes(FrameType::Settings, 0, 0, &[0, 3, 0, 0, 0, 0]);
1198 connection.recv(&zero, |_, _| {}, &mut out).unwrap();
1199 assert_eq!(
1200 connection.request("GET", "/", "h", "https", &[], b"", &mut out),
1201 Err(Error::TooManyStreams)
1202 );
1203 let goaway = frame_bytes(FrameType::GoAway, 0, 0, &[0; 8]);
1204 connection.recv(&goaway, |_, _| {}, &mut out).unwrap();
1205 assert_eq!(
1206 connection.request("GET", "/", "h", "https", &[], b"", &mut out),
1207 Err(Error::GoAway)
1208 );
1209 }
1210
1211 #[test]
1212 fn malformed_control_frames_are_rejected() {
1213 for (kind, flags, stream, payload) in [
1214 (FrameType::Settings, flags::ACK, 0, &[0u8; 6][..]),
1215 (FrameType::Settings, 0, 1, &[][..]),
1216 (FrameType::Ping, 0, 0, &[0; 7][..]),
1217 (FrameType::RstStream, 0, 0, &[0; 4][..]),
1218 (FrameType::WindowUpdate, 0, 0, &[0; 4][..]),
1219 (FrameType::Headers, flags::END_HEADERS, 0, &[0x88][..]),
1220 ] {
1221 let bytes = frame_bytes(kind, flags, stream, payload);
1222 assert_eq!(
1223 Connection::new()
1224 .recv(&bytes, |_, _| {}, &mut [0u8; 128])
1225 .err(),
1226 Some(Error::Protocol)
1227 );
1228 }
1229 }
1230}