1use crate::frame::{self, FrameHeader, FrameType, flags, settings};
27use crate::hpack::{self, Decoder};
28use crate::{Error, 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}
58
59#[derive(Debug, PartialEq, Eq)]
61pub enum Event<'a> {
62 Nothing,
65 Headers { stream: u32, end_stream: bool },
67 Data {
70 stream: u32,
71 data: &'a [u8],
72 end_stream: bool,
73 },
74 Reset { stream: u32, code: u32 },
76 GoAway { code: u32 },
78}
79
80pub struct Connection {
81 decoder: Decoder,
82 streams: heapless::Vec<Stream, MAX_STREAMS>,
83 next_stream: u32,
84 header_block: heapless::Vec<u8, MAX_HEADER_BLOCK>,
86 header_stream: u32,
88 header_end_stream: bool,
89 consumed: u32,
91 peer_max_frame: usize,
93 send_window: u32,
94 peer_initial_window: u32,
95 peer_max_streams: u32,
96 goaway: bool,
97}
98
99impl Default for Connection {
100 fn default() -> Self {
101 Self::new()
102 }
103}
104
105impl Connection {
106 pub fn new() -> Self {
107 Self {
108 decoder: Decoder::new(hpack::DEFAULT_TABLE_SIZE),
109 streams: heapless::Vec::new(),
110 next_stream: 1,
112 header_block: heapless::Vec::new(),
113 header_stream: 0,
114 header_end_stream: false,
115 consumed: 0,
116 peer_max_frame: frame::DEFAULT_MAX_FRAME,
117 send_window: DEFAULT_WINDOW,
118 peer_initial_window: DEFAULT_WINDOW,
119 peer_max_streams: u32::MAX,
120 goaway: false,
121 }
122 }
123
124 pub fn start(&mut self, out: &mut [u8]) -> Result<usize, Error> {
127 let preface = frame::CLIENT_PREFACE;
128 out.get_mut(..preface.len())
129 .ok_or(Error::BufferTooSmall)?
130 .copy_from_slice(preface);
131 let mut len = preface.len();
132
133 let mut payload = [0u8; 24];
136 write_setting(
137 &mut payload[0..6],
138 settings::HEADER_TABLE_SIZE,
139 hpack::DEFAULT_TABLE_SIZE as u32,
140 );
141 write_setting(&mut payload[6..12], settings::ENABLE_PUSH, 0);
142 write_setting(
143 &mut payload[12..18],
144 settings::INITIAL_WINDOW_SIZE,
145 RECEIVE_WINDOW,
146 );
147 write_setting(
148 &mut payload[18..24],
149 settings::MAX_CONCURRENT_STREAMS,
150 MAX_STREAMS as u32,
151 );
152 len += frame::write_frame(FrameType::Settings, 0, 0, &payload, &mut out[len..])?;
153
154 let increment = (RECEIVE_WINDOW - DEFAULT_WINDOW).to_be_bytes();
157 len += frame::write_frame(FrameType::WindowUpdate, 0, 0, &increment, &mut out[len..])?;
158 Ok(len)
159 }
160
161 #[allow(clippy::too_many_arguments)]
165 pub fn request(
166 &mut self,
167 method: &str,
168 path: &str,
169 authority: &str,
170 scheme: &str,
171 extra: &[(&str, &str)],
172 body: &[u8],
173 out: &mut [u8],
174 ) -> Result<(u32, usize), Error> {
175 if self.goaway {
176 return Err(Error::GoAway);
177 }
178 let id = self.next_stream;
179 if self.streams.len() as u32 >= self.peer_max_streams {
180 return Err(Error::TooManyStreams);
181 }
182 if self.streams.is_full() || id > 0x7fff_ffff {
183 return Err(Error::TooManyStreams);
184 }
185
186 let mut block = [0u8; MAX_HEADER_BLOCK];
189 let mut block_len = 0;
190 block_len = encode::encode_header(":method", method, &mut block, block_len)?;
191 block_len = encode::encode_header(":path", path, &mut block, block_len)?;
192 block_len = encode::encode_header(":scheme", scheme, &mut block, block_len)?;
193 block_len = encode::encode_header(":authority", authority, &mut block, block_len)?;
194 for (name, value) in extra {
195 block_len = encode::encode_header(name, value, &mut block, block_len)?;
196 }
197
198 if block_len > self.peer_max_frame {
201 return Err(Error::FrameTooLarge);
202 }
203
204 if body.len() > self.peer_max_frame {
205 return Err(Error::FrameTooLarge);
206 }
207 if body.len() > self.send_window as usize || body.len() > self.peer_initial_window as usize
208 {
209 return Err(Error::FlowControl);
210 }
211 let required = frame::HEADER_LEN
212 + block_len
213 + if body.is_empty() {
214 0
215 } else {
216 frame::HEADER_LEN + body.len()
217 };
218 if out.len() < required {
219 return Err(Error::BufferTooSmall);
220 }
221
222 let end_stream = if body.is_empty() {
223 flags::END_STREAM
224 } else {
225 0
226 };
227 let mut len = frame::write_frame(
228 FrameType::Headers,
229 flags::END_HEADERS | end_stream,
230 id,
231 &block[..block_len],
232 out,
233 )?;
234
235 if !body.is_empty() {
236 len += frame::write_frame(
237 FrameType::Data,
238 flags::END_STREAM,
239 id,
240 body,
241 &mut out[len..],
242 )?;
243 }
244 self.streams
245 .push(Stream {
246 id,
247 consumed: 0,
248 open: true,
249 send_window: self.peer_initial_window as i64 - body.len() as i64,
250 })
251 .map_err(|_| Error::TooManyStreams)?;
252 self.next_stream += 2;
253 self.send_window -= body.len() as u32;
254 Ok((id, len))
255 }
256
257 pub fn recv<'a>(
263 &mut self,
264 bytes: &'a [u8],
265 mut on_header: impl FnMut(&str, &str),
266 out: &mut [u8],
267 ) -> Result<(Event<'a>, usize), Error> {
268 let header = FrameHeader::parse(bytes)?;
269 let payload = bytes
270 .get(frame::HEADER_LEN..frame::HEADER_LEN + header.length)
271 .ok_or(Error::Incomplete)?;
272 if header.length > frame::DEFAULT_MAX_FRAME {
273 return Err(Error::FrameTooLarge);
274 }
275 if self.header_stream != 0 {
276 if header.kind != FrameType::Continuation || header.stream != self.header_stream {
277 return Err(Error::Protocol);
278 }
279 } else if header.kind == FrameType::Continuation {
280 return Err(Error::Protocol);
281 }
282 match header.kind {
283 FrameType::Settings
284 if header.stream != 0 || (header.has(flags::ACK) && !payload.is_empty()) =>
285 {
286 return Err(Error::Protocol);
287 }
288 FrameType::Ping if header.stream != 0 || payload.len() != 8 => {
289 return Err(Error::Protocol);
290 }
291 FrameType::GoAway if header.stream != 0 || payload.len() < 8 => {
292 return Err(Error::Protocol);
293 }
294 FrameType::Headers | FrameType::Data | FrameType::Continuation
295 if header.stream == 0 =>
296 {
297 return Err(Error::Protocol);
298 }
299 FrameType::RstStream if header.stream == 0 || payload.len() != 4 => {
300 return Err(Error::Protocol);
301 }
302 FrameType::Priority if header.stream == 0 || payload.len() != 5 => {
303 return Err(Error::Protocol);
304 }
305 FrameType::WindowUpdate
306 if payload.len() != 4 || read_u32(payload).unwrap() & 0x7fff_ffff == 0 =>
307 {
308 return Err(Error::Protocol);
309 }
310 _ => {}
311 }
312 let mut written = 0;
313
314 match header.kind {
315 FrameType::Settings => {
316 if !header.has(flags::ACK) {
317 self.apply_settings(payload)?;
318 written = frame::write_frame(FrameType::Settings, flags::ACK, 0, &[], out)?;
320 }
321 Ok((Event::Nothing, written))
322 }
323
324 FrameType::Ping => {
325 if !header.has(flags::ACK) {
326 written = frame::write_frame(FrameType::Ping, flags::ACK, 0, payload, out)?;
328 }
329 Ok((Event::Nothing, written))
330 }
331
332 FrameType::Headers | FrameType::Continuation => {
333 let block = if header.kind == FrameType::Headers {
334 self.header_block.clear();
335 self.header_stream = header.stream;
336 self.header_end_stream = header.has(flags::END_STREAM);
337 let body = frame::strip_padding(payload, header.flags)?;
338 if header.has(flags::PRIORITY) {
341 body.get(5..).ok_or(Error::Protocol)?
342 } else {
343 body
344 }
345 } else {
346 payload
347 };
348
349 self.header_block
350 .extend_from_slice(block)
351 .map_err(|_| Error::BufferTooSmall)?;
352
353 if !header.has(flags::END_HEADERS) {
354 return Ok((Event::Nothing, 0));
357 }
358
359 let stream = self.header_stream;
360 let end_stream = self.header_end_stream;
361 self.decoder.decode(&self.header_block, &mut on_header)?;
362 self.header_stream = 0;
363 self.header_block.clear();
364 if end_stream {
365 self.close(stream);
366 }
367 Ok((Event::Headers { stream, end_stream }, 0))
368 }
369
370 FrameType::Data => {
371 let data = frame::strip_padding(payload, header.flags)?;
372 written = self.credit(header.stream, header.length as u32, out)?;
375 let end_stream = header.has(flags::END_STREAM);
376 if end_stream {
377 self.close(header.stream);
378 }
379 Ok((
380 Event::Data {
381 stream: header.stream,
382 data,
383 end_stream,
384 },
385 written,
386 ))
387 }
388
389 FrameType::RstStream => {
390 let code = read_u32(payload).ok_or(Error::Protocol)?;
391 self.close(header.stream);
392 Ok((
393 Event::Reset {
394 stream: header.stream,
395 code,
396 },
397 0,
398 ))
399 }
400
401 FrameType::GoAway => {
402 let code = payload
404 .get(4..8)
405 .and_then(read_u32)
406 .ok_or(Error::Protocol)?;
407 self.goaway = true;
408 Ok((Event::GoAway { code }, 0))
409 }
410
411 FrameType::WindowUpdate => {
412 let increment = read_u32(payload).ok_or(Error::Protocol)? & 0x7fff_ffff;
413 if header.stream == 0 {
414 self.send_window = self
415 .send_window
416 .checked_add(increment)
417 .filter(|value| *value <= 0x7fff_ffff)
418 .ok_or(Error::Protocol)?;
419 } else if let Some(stream) = self.streams.iter_mut().find(|s| s.id == header.stream)
420 {
421 let window = stream.send_window + increment as i64;
422 if window > 0x7fff_ffff {
423 return Err(Error::Protocol);
424 }
425 stream.send_window = window;
426 }
427 Ok((Event::Nothing, 0))
428 }
429 FrameType::Priority => Ok((Event::Nothing, 0)),
430
431 FrameType::PushPromise => Err(Error::Protocol),
434
435 FrameType::Unknown(_) => Ok((Event::Nothing, 0)),
437 }
438 }
439
440 pub fn finish_data(&mut self, header: FrameHeader, out: &mut [u8]) -> Result<usize, Error> {
448 if header.kind != FrameType::Data || header.stream == 0 || self.header_stream != 0 {
449 return Err(Error::Protocol);
450 }
451 if header.length > frame::DEFAULT_MAX_FRAME {
452 return Err(Error::FrameTooLarge);
453 }
454 let written = self.credit(header.stream, header.length as u32, out)?;
455 if header.has(flags::END_STREAM) {
456 self.close(header.stream);
457 }
458 Ok(written)
459 }
460
461 fn credit(&mut self, stream: u32, length: u32, out: &mut [u8]) -> Result<usize, Error> {
463 if length == 0 {
464 return Ok(0);
465 }
466 const THRESHOLD: u32 = RECEIVE_WINDOW / 2;
467 let consumed = self.consumed.checked_add(length).ok_or(Error::Protocol)?;
468 let stream_consumed = self
469 .streams
470 .iter()
471 .find(|s| s.id == stream)
472 .map(|entry| entry.consumed.checked_add(length).ok_or(Error::Protocol))
473 .transpose()?;
474 let connection_update = consumed >= THRESHOLD;
475 let stream_update = stream_consumed.is_some_and(|value| value >= THRESHOLD);
476 let required =
477 (connection_update as usize + stream_update as usize) * (frame::HEADER_LEN + 4);
478 if out.len() < required {
479 return Err(Error::BufferTooSmall);
480 }
481 let mut written = 0;
482 if connection_update {
483 written +=
484 frame::write_frame(FrameType::WindowUpdate, 0, 0, &consumed.to_be_bytes(), out)?;
485 }
486 if stream_update {
487 written += frame::write_frame(
488 FrameType::WindowUpdate,
489 0,
490 stream,
491 &stream_consumed.unwrap().to_be_bytes(),
492 &mut out[written..],
493 )?;
494 }
495 self.consumed = if connection_update { 0 } else { consumed };
496 if let Some(entry) = self.streams.iter_mut().find(|s| s.id == stream) {
497 entry.consumed = if stream_update {
498 0
499 } else {
500 stream_consumed.unwrap()
501 };
502 }
503 Ok(written)
504 }
505
506 fn apply_settings(&mut self, payload: &[u8]) -> Result<(), Error> {
507 if !payload.len().is_multiple_of(6) {
508 return Err(Error::Protocol);
509 }
510 for entry in payload.as_chunks::<6>().0 {
511 let identifier = u16::from_be_bytes([entry[0], entry[1]]);
512 let value = u32::from_be_bytes([entry[2], entry[3], entry[4], entry[5]]);
513 match identifier {
514 settings::MAX_FRAME_SIZE => {
515 if !(16_384..=16_777_215).contains(&value) {
516 return Err(Error::Protocol);
517 }
518 self.peer_max_frame = value as usize;
519 }
520 settings::INITIAL_WINDOW_SIZE => {
521 if value > 0x7fff_ffff {
522 return Err(Error::Protocol);
523 }
524 let delta = value as i64 - self.peer_initial_window as i64;
525 if self
526 .streams
527 .iter()
528 .any(|stream| stream.send_window + delta > 0x7fff_ffff)
529 {
530 return Err(Error::Protocol);
531 }
532 for stream in &mut self.streams {
533 stream.send_window += delta;
534 }
535 self.peer_initial_window = value;
536 }
537 settings::MAX_CONCURRENT_STREAMS => self.peer_max_streams = value,
538 settings::ENABLE_PUSH => return Err(Error::Protocol),
539 settings::HEADER_TABLE_SIZE => {}
543 _ => {}
545 }
546 }
547 Ok(())
548 }
549
550 fn close(&mut self, stream: u32) {
551 if let Some(entry) = self.streams.iter_mut().find(|s| s.id == stream) {
552 entry.open = false;
553 }
554 self.streams.retain(|s| s.open);
555 }
556
557 pub fn open_streams(&self) -> usize {
558 self.streams.len()
559 }
560}
561
562fn write_setting(out: &mut [u8], identifier: u16, value: u32) {
563 out[0..2].copy_from_slice(&identifier.to_be_bytes());
564 out[2..6].copy_from_slice(&value.to_be_bytes());
565}
566
567fn read_u32(bytes: &[u8]) -> Option<u32> {
568 Some(u32::from_be_bytes(bytes.get(..4)?.try_into().ok()?))
569}
570
571#[cfg(test)]
572mod tests {
573 use super::*;
574
575 fn frame_bytes(
577 kind: FrameType,
578 flags: u8,
579 stream: u32,
580 payload: &[u8],
581 ) -> heapless::Vec<u8, 512> {
582 let mut out = heapless::Vec::<u8, 512>::new();
583 out.resize_default(512).unwrap();
584 let len = frame::write_frame(kind, flags, stream, payload, &mut out).unwrap();
585 out.truncate(len);
586 out
587 }
588
589 #[test]
590 fn the_preface_is_exactly_what_the_rfc_requires() {
591 let mut connection = Connection::new();
592 let mut out = [0u8; 128];
593 let len = connection.start(&mut out).unwrap();
594 assert!(out[..len].starts_with(b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"));
595
596 let after = &out[frame::CLIENT_PREFACE.len()..len];
599 let settings = FrameHeader::parse(after).unwrap();
600 assert_eq!(settings.kind, FrameType::Settings);
601 assert_eq!(settings.stream, 0);
602
603 let update = &after[frame::HEADER_LEN + settings.length..];
604 let update_header = FrameHeader::parse(update).unwrap();
605 assert_eq!(update_header.kind, FrameType::WindowUpdate);
606 assert_eq!(update_header.stream, 0);
607 let increment = read_u32(&update[frame::HEADER_LEN..]).unwrap();
608 assert_eq!(increment, RECEIVE_WINDOW - DEFAULT_WINDOW);
609 }
610
611 #[test]
612 fn a_request_opens_an_odd_numbered_stream_and_ends_it() {
613 let mut connection = Connection::new();
614 let mut out = [0u8; 512];
615 let (stream, len) = connection
616 .request(
617 "POST",
618 "/machine/register",
619 "127.0.0.1:8080",
620 "http",
621 &[("content-type", "application/json")],
622 b"{}",
623 &mut out,
624 )
625 .unwrap();
626
627 assert_eq!(stream, 1);
629 let headers = FrameHeader::parse(&out).unwrap();
630 assert_eq!(headers.kind, FrameType::Headers);
631 assert!(headers.has(flags::END_HEADERS));
632 assert!(!headers.has(flags::END_STREAM), "a body follows");
633
634 let data = FrameHeader::parse(&out[frame::HEADER_LEN + headers.length..]).unwrap();
635 assert_eq!(data.kind, FrameType::Data);
636 assert!(data.has(flags::END_STREAM));
637 assert_eq!(len, frame::HEADER_LEN * 2 + headers.length + data.length);
638
639 let (second, _) = connection
641 .request("GET", "/", "h", "http", &[], b"", &mut out)
642 .unwrap();
643 assert_eq!(second, 3);
644 }
645
646 #[test]
647 fn settings_are_acknowledged_and_an_ack_is_not() {
648 let mut connection = Connection::new();
649 let mut out = [0u8; 128];
650
651 let settings = frame_bytes(FrameType::Settings, 0, 0, &[0, 5, 0, 0, 0x40, 0]);
652 let (event, written) = connection.recv(&settings, |_, _| {}, &mut out).unwrap();
653 assert_eq!(event, Event::Nothing);
654 let ack = FrameHeader::parse(&out[..written]).unwrap();
655 assert_eq!(ack.kind, FrameType::Settings);
656 assert!(ack.has(flags::ACK));
657 assert_eq!(ack.length, 0);
658
659 let their_ack = frame_bytes(FrameType::Settings, flags::ACK, 0, &[]);
661 let (_, written) = connection.recv(&their_ack, |_, _| {}, &mut out).unwrap();
662 assert_eq!(written, 0);
663 }
664
665 #[test]
666 fn peer_encoder_settings_do_not_reset_receive_hpack_state() {
667 let mut connection = Connection::new();
668 connection
669 .decoder
670 .decode(&[0x40, 0x01, b'x', 0x01, b'y'], |_, _| {})
671 .unwrap();
672 assert_eq!(connection.decoder.table().len(), 1);
673
674 let settings = frame_bytes(FrameType::Settings, 0, 0, &[0, 1, 0, 0, 0x10, 0]);
675 let mut out = [0u8; 64];
676 connection.recv(&settings, |_, _| {}, &mut out).unwrap();
677 assert_eq!(connection.decoder.table().len(), 1);
678 assert_eq!(
679 connection.decoder.table().capacity(),
680 hpack::DEFAULT_TABLE_SIZE
681 );
682 }
683
684 #[test]
685 fn a_ping_is_echoed_exactly() {
686 let mut connection = Connection::new();
687 let mut out = [0u8; 128];
688 let payload = [1, 2, 3, 4, 5, 6, 7, 8];
689 let ping = frame_bytes(FrameType::Ping, 0, 0, &payload);
690 let (_, written) = connection.recv(&ping, |_, _| {}, &mut out).unwrap();
691 let header = FrameHeader::parse(&out[..written]).unwrap();
692 assert!(header.has(flags::ACK));
693 assert_eq!(&out[frame::HEADER_LEN..written], &payload);
694 }
695
696 #[test]
697 fn a_header_block_split_across_continuation_frames_is_reassembled() {
698 let mut connection = Connection::new();
701 let mut out = [0u8; 256];
702
703 let first = frame_bytes(FrameType::Headers, 0, 1, &[0x88]);
705 let (event, _) = connection.recv(&first, |_, _| {}, &mut out).unwrap();
706 assert_eq!(
707 event,
708 Event::Nothing,
709 "an unterminated block yields nothing"
710 );
711
712 let mut seen = heapless::Vec::<(heapless::String<32>, heapless::String<32>), 4>::new();
713 let second = frame_bytes(FrameType::Continuation, flags::END_HEADERS, 1, &[0x82]);
714 let (event, _) = connection
715 .recv(
716 &second,
717 |name, value| {
718 let mut n = heapless::String::new();
719 let mut v = heapless::String::new();
720 n.push_str(name).unwrap();
721 v.push_str(value).unwrap();
722 seen.push((n, v)).unwrap();
723 },
724 &mut out,
725 )
726 .unwrap();
727
728 assert!(matches!(event, Event::Headers { stream: 1, .. }));
729 assert_eq!(seen.len(), 2);
730 assert_eq!(seen[0].0.as_str(), ":status");
731 assert_eq!(seen[0].1.as_str(), "200");
732 assert_eq!(seen[1].0.as_str(), ":method");
733 }
734
735 #[test]
736 fn data_returns_the_payload_and_eventually_a_window_update() {
737 let mut connection = Connection::new();
738 let mut out = [0u8; 256];
739
740 let data = frame_bytes(FrameType::Data, 0, 1, b"hello");
741 let (event, written) = connection.recv(&data, |_, _| {}, &mut out).unwrap();
742 assert_eq!(
743 event,
744 Event::Data {
745 stream: 1,
746 data: b"hello",
747 end_stream: false
748 }
749 );
750 assert_eq!(written, 0);
753 }
754
755 #[test]
756 fn a_long_response_gets_its_window_topped_up_before_it_can_stall() {
757 let mut connection = Connection::new();
760 let mut out = [0u8; 256];
761 let payload = [0u8; 400];
762
763 let mut updates = 0;
764 let mut delivered = 0usize;
765 let frames = 2_000;
769 for _ in 0..frames {
770 let data = frame_bytes(FrameType::Data, 0, 1, &payload);
771 let (event, written) = connection.recv(&data, |_, _| {}, &mut out).unwrap();
772 if let Event::Data { data, .. } = event {
773 delivered += data.len();
774 }
775 if written > 0 {
776 updates += 1;
777 let header = FrameHeader::parse(&out[..written]).unwrap();
778 assert_eq!(header.kind, FrameType::WindowUpdate);
779 }
780 }
781 assert_eq!(delivered, frames * 400);
782 assert!(
783 updates > 0,
784 "the connection window must be replenished, or the server stops at 65535 bytes"
785 );
786 }
787
788 #[test]
789 fn padding_and_priority_are_stripped_before_hpack_sees_the_block() {
790 let mut connection = Connection::new();
791 let mut out = [0u8; 256];
792 let payload = [2, 0, 0, 0, 0, 0, 0x88, 0xaa, 0xbb];
794 let headers = frame_bytes(
795 FrameType::Headers,
796 flags::END_HEADERS | flags::PADDED | flags::PRIORITY,
797 1,
798 &payload,
799 );
800 let mut status = heapless::String::<8>::new();
801 connection
802 .recv(
803 &headers,
804 |name, value| {
805 if name == ":status" {
806 status.push_str(value).unwrap();
807 }
808 },
809 &mut out,
810 )
811 .unwrap();
812 assert_eq!(status.as_str(), "200");
813 }
814
815 #[test]
816 fn goaway_and_reset_are_reported_rather_than_hidden() {
817 let mut connection = Connection::new();
818 let mut out = [0u8; 128];
819
820 let reset = frame_bytes(FrameType::RstStream, 0, 1, &[0, 0, 0, 8]);
821 let (event, _) = connection.recv(&reset, |_, _| {}, &mut out).unwrap();
822 assert_eq!(event, Event::Reset { stream: 1, code: 8 });
823
824 let goaway = frame_bytes(FrameType::GoAway, 0, 0, &[0, 0, 0, 1, 0, 0, 0, 2]);
825 let (event, _) = connection.recv(&goaway, |_, _| {}, &mut out).unwrap();
826 assert_eq!(event, Event::GoAway { code: 2 });
827 }
828
829 #[test]
830 fn a_promised_push_is_a_protocol_error_because_we_refused_push() {
831 let mut connection = Connection::new();
832 let mut out = [0u8; 128];
833 let promise = frame_bytes(FrameType::PushPromise, flags::END_HEADERS, 1, &[0, 0, 0, 2]);
834 assert_eq!(
835 connection.recv(&promise, |_, _| {}, &mut out).err(),
836 Some(Error::Protocol)
837 );
838 }
839
840 #[test]
841 fn an_unknown_frame_type_is_discarded_not_fatal() {
842 let mut connection = Connection::new();
843 let mut out = [0u8; 128];
844 let unknown = frame_bytes(FrameType::Unknown(0x63), 0, 0, b"whatever");
845 let (event, written) = connection.recv(&unknown, |_, _| {}, &mut out).unwrap();
846 assert_eq!(event, Event::Nothing);
847 assert_eq!(written, 0);
848 }
849 #[test]
850 fn failed_requests_do_not_consume_stream_slots_or_identifiers() {
851 let mut connection = Connection::new();
852 for _ in 0..MAX_STREAMS + 1 {
853 assert_eq!(
854 connection.request("GET", "/", "h", "https", &[], b"", &mut []),
855 Err(Error::BufferTooSmall)
856 );
857 assert_eq!(connection.open_streams(), 0);
858 }
859 let mut out = [0u8; 128];
860 assert_eq!(
861 connection
862 .request("GET", "/", "h", "https", &[], b"", &mut out)
863 .unwrap()
864 .0,
865 1
866 );
867 }
868
869 #[test]
870 fn continuation_must_follow_headers_on_the_same_stream() {
871 for (kind, stream) in [
872 (FrameType::Continuation, 3),
873 (FrameType::Ping, 0),
874 (FrameType::Headers, 3),
875 ] {
876 let mut connection = Connection::new();
877 let mut out = [0u8; 128];
878 let first = frame_bytes(FrameType::Headers, 0, 1, &[0x88]);
879 connection.recv(&first, |_, _| {}, &mut out).unwrap();
880 let next = frame_bytes(kind, flags::END_HEADERS, stream, &[0x82]);
881 assert_eq!(
882 connection.recv(&next, |_, _| {}, &mut out).err(),
883 Some(Error::Protocol)
884 );
885 }
886 let mut connection = Connection::new();
887 let orphan = frame_bytes(FrameType::Continuation, flags::END_HEADERS, 1, &[0x88]);
888 assert_eq!(
889 connection.recv(&orphan, |_, _| {}, &mut [0u8; 128]).err(),
890 Some(Error::Protocol)
891 );
892 }
893 #[test]
894 fn request_body_waits_for_connection_and_stream_credit() {
895 let mut connection = Connection::new();
896 let mut out = [0u8; 256];
897 let zero = frame_bytes(FrameType::Settings, 0, 0, &[0, 4, 0, 0, 0, 0]);
898 connection.recv(&zero, |_, _| {}, &mut out).unwrap();
899 assert_eq!(
900 connection.request("POST", "/", "h", "https", &[], b"a", &mut out),
901 Err(Error::FlowControl)
902 );
903 assert_eq!(connection.open_streams(), 0);
904 let one = frame_bytes(FrameType::Settings, 0, 0, &[0, 4, 0, 0, 0, 1]);
905 connection.recv(&one, |_, _| {}, &mut out).unwrap();
906 connection.send_window = 0;
907 assert_eq!(
908 connection.request("POST", "/", "h", "https", &[], b"a", &mut out),
909 Err(Error::FlowControl)
910 );
911 let update = frame_bytes(FrameType::WindowUpdate, 0, 0, &[0, 0, 0, 1]);
912 connection.recv(&update, |_, _| {}, &mut out).unwrap();
913 assert_eq!(
914 connection
915 .request("POST", "/", "h", "https", &[], b"a", &mut out)
916 .unwrap()
917 .0,
918 1
919 );
920 assert_eq!(connection.send_window, 0);
921 }
922
923 #[test]
924 fn exhausted_connection_credit_blocks_later_small_requests() {
925 let mut connection = Connection::new();
926 let mut out = [0u8; 17_000];
927 for _ in 0..4 {
928 let (id, _) = connection
929 .request("POST", "/", "h", "https", &[], &[0; 16_000], &mut out)
930 .unwrap();
931 connection.close(id);
932 }
933 assert_eq!(
934 connection.request("POST", "/", "h", "https", &[], &[0; 2_000], &mut out),
935 Err(Error::FlowControl)
936 );
937 }
938
939 #[test]
940 fn failed_credit_output_can_be_retried_without_double_counting() {
941 let mut connection = Connection::new();
942 let mut out = [0u8; 128];
943 let (id, _) = connection
944 .request("GET", "/", "h", "https", &[], b"", &mut out)
945 .unwrap();
946 connection.consumed = RECEIVE_WINDOW / 2 - 1;
947 connection.streams[0].consumed = RECEIVE_WINDOW / 2 - 1;
948 let data = frame_bytes(FrameType::Data, 0, id, b"a");
949 assert_eq!(
950 connection.recv(&data, |_, _| {}, &mut out[..13]).err(),
951 Some(Error::BufferTooSmall)
952 );
953 assert_eq!(connection.consumed, RECEIVE_WINDOW / 2 - 1);
954 let (_, written) = connection.recv(&data, |_, _| {}, &mut out).unwrap();
955 assert_eq!(written, 26);
956 assert_eq!(read_u32(&out[9..13]), Some(RECEIVE_WINDOW / 2));
957 assert_eq!(read_u32(&out[22..26]), Some(RECEIVE_WINDOW / 2));
958 }
959
960 #[test]
961 fn settings_stream_limits_and_goaway_stop_new_requests() {
962 let mut connection = Connection::new();
963 let mut out = [0u8; 128];
964 let zero = frame_bytes(FrameType::Settings, 0, 0, &[0, 3, 0, 0, 0, 0]);
965 connection.recv(&zero, |_, _| {}, &mut out).unwrap();
966 assert_eq!(
967 connection.request("GET", "/", "h", "https", &[], b"", &mut out),
968 Err(Error::TooManyStreams)
969 );
970 let goaway = frame_bytes(FrameType::GoAway, 0, 0, &[0; 8]);
971 connection.recv(&goaway, |_, _| {}, &mut out).unwrap();
972 assert_eq!(
973 connection.request("GET", "/", "h", "https", &[], b"", &mut out),
974 Err(Error::GoAway)
975 );
976 }
977
978 #[test]
979 fn malformed_control_frames_are_rejected() {
980 for (kind, flags, stream, payload) in [
981 (FrameType::Settings, flags::ACK, 0, &[0u8; 6][..]),
982 (FrameType::Settings, 0, 1, &[][..]),
983 (FrameType::Ping, 0, 0, &[0; 7][..]),
984 (FrameType::RstStream, 0, 0, &[0; 4][..]),
985 (FrameType::WindowUpdate, 0, 0, &[0; 4][..]),
986 (FrameType::Headers, flags::END_HEADERS, 0, &[0x88][..]),
987 ] {
988 let bytes = frame_bytes(kind, flags, stream, payload);
989 assert_eq!(
990 Connection::new()
991 .recv(&bytes, |_, _| {}, &mut [0u8; 128])
992 .err(),
993 Some(Error::Protocol)
994 );
995 }
996 }
997}