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 = 4096;
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}
57
58#[derive(Debug, PartialEq, Eq)]
60pub enum Event<'a> {
61 Nothing,
64 Headers { stream: u32, end_stream: bool },
66 Data {
69 stream: u32,
70 data: &'a [u8],
71 end_stream: bool,
72 },
73 Reset { stream: u32, code: u32 },
75 GoAway { code: u32 },
77}
78
79pub struct Connection {
80 decoder: Decoder,
81 streams: heapless::Vec<Stream, MAX_STREAMS>,
82 next_stream: u32,
83 header_block: heapless::Vec<u8, MAX_HEADER_BLOCK>,
85 header_stream: u32,
87 header_end_stream: bool,
88 consumed: u32,
90 peer_max_frame: usize,
92}
93
94impl Default for Connection {
95 fn default() -> Self {
96 Self::new()
97 }
98}
99
100impl Connection {
101 pub fn new() -> Self {
102 Self {
103 decoder: Decoder::new(hpack::DEFAULT_TABLE_SIZE),
104 streams: heapless::Vec::new(),
105 next_stream: 1,
107 header_block: heapless::Vec::new(),
108 header_stream: 0,
109 header_end_stream: false,
110 consumed: 0,
111 peer_max_frame: frame::DEFAULT_MAX_FRAME,
112 }
113 }
114
115 pub fn start(&mut self, out: &mut [u8]) -> Result<usize, Error> {
118 let preface = frame::CLIENT_PREFACE;
119 out.get_mut(..preface.len())
120 .ok_or(Error::BufferTooSmall)?
121 .copy_from_slice(preface);
122 let mut len = preface.len();
123
124 let mut payload = [0u8; 18];
127 write_setting(&mut payload[0..6], settings::ENABLE_PUSH, 0);
128 write_setting(
129 &mut payload[6..12],
130 settings::INITIAL_WINDOW_SIZE,
131 RECEIVE_WINDOW,
132 );
133 write_setting(
134 &mut payload[12..18],
135 settings::MAX_CONCURRENT_STREAMS,
136 MAX_STREAMS as u32,
137 );
138 len += frame::write_frame(FrameType::Settings, 0, 0, &payload, &mut out[len..])?;
139
140 let increment = (RECEIVE_WINDOW - DEFAULT_WINDOW).to_be_bytes();
143 len += frame::write_frame(FrameType::WindowUpdate, 0, 0, &increment, &mut out[len..])?;
144 Ok(len)
145 }
146
147 #[allow(clippy::too_many_arguments)]
151 pub fn request(
152 &mut self,
153 method: &str,
154 path: &str,
155 authority: &str,
156 scheme: &str,
157 extra: &[(&str, &str)],
158 body: &[u8],
159 out: &mut [u8],
160 ) -> Result<(u32, usize), Error> {
161 let id = self.next_stream;
162 self.streams
163 .push(Stream {
164 id,
165 consumed: 0,
166 open: true,
167 })
168 .map_err(|_| Error::TooManyStreams)?;
169 self.next_stream += 2;
170
171 let mut block = [0u8; MAX_HEADER_BLOCK];
174 let mut block_len = 0;
175 block_len = encode::encode_header(":method", method, &mut block, block_len)?;
176 block_len = encode::encode_header(":path", path, &mut block, block_len)?;
177 block_len = encode::encode_header(":scheme", scheme, &mut block, block_len)?;
178 block_len = encode::encode_header(":authority", authority, &mut block, block_len)?;
179 for (name, value) in extra {
180 block_len = encode::encode_header(name, value, &mut block, block_len)?;
181 }
182
183 if block_len > self.peer_max_frame {
186 return Err(Error::FrameTooLarge);
187 }
188
189 let end_stream = if body.is_empty() {
190 flags::END_STREAM
191 } else {
192 0
193 };
194 let mut len = frame::write_frame(
195 FrameType::Headers,
196 flags::END_HEADERS | end_stream,
197 id,
198 &block[..block_len],
199 out,
200 )?;
201
202 if !body.is_empty() {
203 if body.len() > self.peer_max_frame {
204 return Err(Error::FrameTooLarge);
205 }
206 len += frame::write_frame(
207 FrameType::Data,
208 flags::END_STREAM,
209 id,
210 body,
211 &mut out[len..],
212 )?;
213 }
214 Ok((id, len))
215 }
216
217 pub fn recv<'a>(
223 &mut self,
224 bytes: &'a [u8],
225 mut on_header: impl FnMut(&str, &str),
226 out: &mut [u8],
227 ) -> Result<(Event<'a>, usize), Error> {
228 let header = FrameHeader::parse(bytes)?;
229 let payload = bytes
230 .get(frame::HEADER_LEN..frame::HEADER_LEN + header.length)
231 .ok_or(Error::Incomplete)?;
232 let mut written = 0;
233
234 match header.kind {
235 FrameType::Settings => {
236 if !header.has(flags::ACK) {
237 self.apply_settings(payload)?;
238 written = frame::write_frame(FrameType::Settings, flags::ACK, 0, &[], out)?;
240 }
241 Ok((Event::Nothing, written))
242 }
243
244 FrameType::Ping => {
245 if !header.has(flags::ACK) {
246 written = frame::write_frame(FrameType::Ping, flags::ACK, 0, payload, out)?;
248 }
249 Ok((Event::Nothing, written))
250 }
251
252 FrameType::Headers | FrameType::Continuation => {
253 let block = if header.kind == FrameType::Headers {
254 self.header_block.clear();
255 self.header_stream = header.stream;
256 self.header_end_stream = header.has(flags::END_STREAM);
257 let body = frame::strip_padding(payload, header.flags)?;
258 if header.has(flags::PRIORITY) {
261 body.get(5..).ok_or(Error::Protocol)?
262 } else {
263 body
264 }
265 } else {
266 payload
267 };
268
269 self.header_block
270 .extend_from_slice(block)
271 .map_err(|_| Error::BufferTooSmall)?;
272
273 if !header.has(flags::END_HEADERS) {
274 return Ok((Event::Nothing, 0));
277 }
278
279 let stream = self.header_stream;
280 let end_stream = self.header_end_stream;
281 self.decoder.decode(&self.header_block, &mut on_header)?;
282 if end_stream {
283 self.close(stream);
284 }
285 Ok((Event::Headers { stream, end_stream }, 0))
286 }
287
288 FrameType::Data => {
289 let data = frame::strip_padding(payload, header.flags)?;
290 written = self.credit(header.stream, header.length as u32, out)?;
293 let end_stream = header.has(flags::END_STREAM);
294 if end_stream {
295 self.close(header.stream);
296 }
297 Ok((
298 Event::Data {
299 stream: header.stream,
300 data,
301 end_stream,
302 },
303 written,
304 ))
305 }
306
307 FrameType::RstStream => {
308 let code = read_u32(payload).ok_or(Error::Protocol)?;
309 self.close(header.stream);
310 Ok((
311 Event::Reset {
312 stream: header.stream,
313 code,
314 },
315 0,
316 ))
317 }
318
319 FrameType::GoAway => {
320 let code = payload
322 .get(4..8)
323 .and_then(read_u32)
324 .ok_or(Error::Protocol)?;
325 Ok((Event::GoAway { code }, 0))
326 }
327
328 FrameType::WindowUpdate | FrameType::Priority => Ok((Event::Nothing, 0)),
333
334 FrameType::PushPromise => Err(Error::Protocol),
337
338 FrameType::Unknown(_) => Ok((Event::Nothing, 0)),
340 }
341 }
342
343 fn credit(&mut self, stream: u32, length: u32, out: &mut [u8]) -> Result<usize, Error> {
345 if length == 0 {
346 return Ok(0);
347 }
348 let mut written = 0;
349
350 const THRESHOLD: u32 = RECEIVE_WINDOW / 2;
353
354 self.consumed += length;
355 if self.consumed >= THRESHOLD {
356 let increment = self.consumed.to_be_bytes();
357 written += frame::write_frame(FrameType::WindowUpdate, 0, 0, &increment, out)?;
358 self.consumed = 0;
359 }
360
361 if let Some(entry) = self.streams.iter_mut().find(|s| s.id == stream) {
362 entry.consumed += length;
363 if entry.consumed >= THRESHOLD {
364 let increment = entry.consumed.to_be_bytes();
365 written += frame::write_frame(
366 FrameType::WindowUpdate,
367 0,
368 stream,
369 &increment,
370 &mut out[written..],
371 )?;
372 entry.consumed = 0;
373 }
374 }
375 Ok(written)
376 }
377
378 fn apply_settings(&mut self, payload: &[u8]) -> Result<(), Error> {
379 if !payload.len().is_multiple_of(6) {
380 return Err(Error::Protocol);
381 }
382 for entry in payload.chunks_exact(6) {
383 let identifier = u16::from_be_bytes([entry[0], entry[1]]);
384 let value = u32::from_be_bytes([entry[2], entry[3], entry[4], entry[5]]);
385 match identifier {
386 settings::MAX_FRAME_SIZE => self.peer_max_frame = value as usize,
387 settings::HEADER_TABLE_SIZE => {
391 self.decoder = Decoder::new(value as usize);
392 }
393 _ => {}
396 }
397 }
398 Ok(())
399 }
400
401 fn close(&mut self, stream: u32) {
402 if let Some(entry) = self.streams.iter_mut().find(|s| s.id == stream) {
403 entry.open = false;
404 }
405 self.streams.retain(|s| s.open);
406 }
407
408 pub fn open_streams(&self) -> usize {
409 self.streams.len()
410 }
411}
412
413fn write_setting(out: &mut [u8], identifier: u16, value: u32) {
414 out[0..2].copy_from_slice(&identifier.to_be_bytes());
415 out[2..6].copy_from_slice(&value.to_be_bytes());
416}
417
418fn read_u32(bytes: &[u8]) -> Option<u32> {
419 Some(u32::from_be_bytes(bytes.get(..4)?.try_into().ok()?))
420}
421
422#[cfg(test)]
423mod tests {
424 use super::*;
425
426 fn frame_bytes(
428 kind: FrameType,
429 flags: u8,
430 stream: u32,
431 payload: &[u8],
432 ) -> heapless::Vec<u8, 512> {
433 let mut out = heapless::Vec::<u8, 512>::new();
434 out.resize_default(512).unwrap();
435 let len = frame::write_frame(kind, flags, stream, payload, &mut out).unwrap();
436 out.truncate(len);
437 out
438 }
439
440 #[test]
441 fn the_preface_is_exactly_what_the_rfc_requires() {
442 let mut connection = Connection::new();
443 let mut out = [0u8; 128];
444 let len = connection.start(&mut out).unwrap();
445 assert!(out[..len].starts_with(b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"));
446
447 let after = &out[frame::CLIENT_PREFACE.len()..len];
450 let settings = FrameHeader::parse(after).unwrap();
451 assert_eq!(settings.kind, FrameType::Settings);
452 assert_eq!(settings.stream, 0);
453
454 let update = &after[frame::HEADER_LEN + settings.length..];
455 let update_header = FrameHeader::parse(update).unwrap();
456 assert_eq!(update_header.kind, FrameType::WindowUpdate);
457 assert_eq!(update_header.stream, 0);
458 let increment = read_u32(&update[frame::HEADER_LEN..]).unwrap();
459 assert_eq!(increment, RECEIVE_WINDOW - DEFAULT_WINDOW);
460 }
461
462 #[test]
463 fn a_request_opens_an_odd_numbered_stream_and_ends_it() {
464 let mut connection = Connection::new();
465 let mut out = [0u8; 512];
466 let (stream, len) = connection
467 .request(
468 "POST",
469 "/machine/register",
470 "127.0.0.1:8080",
471 "http",
472 &[("content-type", "application/json")],
473 b"{}",
474 &mut out,
475 )
476 .unwrap();
477
478 assert_eq!(stream, 1);
480 let headers = FrameHeader::parse(&out).unwrap();
481 assert_eq!(headers.kind, FrameType::Headers);
482 assert!(headers.has(flags::END_HEADERS));
483 assert!(!headers.has(flags::END_STREAM), "a body follows");
484
485 let data = FrameHeader::parse(&out[frame::HEADER_LEN + headers.length..]).unwrap();
486 assert_eq!(data.kind, FrameType::Data);
487 assert!(data.has(flags::END_STREAM));
488 assert_eq!(len, frame::HEADER_LEN * 2 + headers.length + data.length);
489
490 let (second, _) = connection
492 .request("GET", "/", "h", "http", &[], b"", &mut out)
493 .unwrap();
494 assert_eq!(second, 3);
495 }
496
497 #[test]
498 fn settings_are_acknowledged_and_an_ack_is_not() {
499 let mut connection = Connection::new();
500 let mut out = [0u8; 128];
501
502 let settings = frame_bytes(FrameType::Settings, 0, 0, &[0, 5, 0, 0, 0x40, 0]);
503 let (event, written) = connection.recv(&settings, |_, _| {}, &mut out).unwrap();
504 assert_eq!(event, Event::Nothing);
505 let ack = FrameHeader::parse(&out[..written]).unwrap();
506 assert_eq!(ack.kind, FrameType::Settings);
507 assert!(ack.has(flags::ACK));
508 assert_eq!(ack.length, 0);
509
510 let their_ack = frame_bytes(FrameType::Settings, flags::ACK, 0, &[]);
512 let (_, written) = connection.recv(&their_ack, |_, _| {}, &mut out).unwrap();
513 assert_eq!(written, 0);
514 }
515
516 #[test]
517 fn a_ping_is_echoed_exactly() {
518 let mut connection = Connection::new();
519 let mut out = [0u8; 128];
520 let payload = [1, 2, 3, 4, 5, 6, 7, 8];
521 let ping = frame_bytes(FrameType::Ping, 0, 0, &payload);
522 let (_, written) = connection.recv(&ping, |_, _| {}, &mut out).unwrap();
523 let header = FrameHeader::parse(&out[..written]).unwrap();
524 assert!(header.has(flags::ACK));
525 assert_eq!(&out[frame::HEADER_LEN..written], &payload);
526 }
527
528 #[test]
529 fn a_header_block_split_across_continuation_frames_is_reassembled() {
530 let mut connection = Connection::new();
533 let mut out = [0u8; 256];
534
535 let first = frame_bytes(FrameType::Headers, 0, 1, &[0x88]);
537 let (event, _) = connection.recv(&first, |_, _| {}, &mut out).unwrap();
538 assert_eq!(
539 event,
540 Event::Nothing,
541 "an unterminated block yields nothing"
542 );
543
544 let mut seen = heapless::Vec::<(heapless::String<32>, heapless::String<32>), 4>::new();
545 let second = frame_bytes(FrameType::Continuation, flags::END_HEADERS, 1, &[0x82]);
546 let (event, _) = connection
547 .recv(
548 &second,
549 |name, value| {
550 let mut n = heapless::String::new();
551 let mut v = heapless::String::new();
552 n.push_str(name).unwrap();
553 v.push_str(value).unwrap();
554 seen.push((n, v)).unwrap();
555 },
556 &mut out,
557 )
558 .unwrap();
559
560 assert!(matches!(event, Event::Headers { stream: 1, .. }));
561 assert_eq!(seen.len(), 2);
562 assert_eq!(seen[0].0.as_str(), ":status");
563 assert_eq!(seen[0].1.as_str(), "200");
564 assert_eq!(seen[1].0.as_str(), ":method");
565 }
566
567 #[test]
568 fn data_returns_the_payload_and_eventually_a_window_update() {
569 let mut connection = Connection::new();
570 let mut out = [0u8; 256];
571
572 let data = frame_bytes(FrameType::Data, 0, 1, b"hello");
573 let (event, written) = connection.recv(&data, |_, _| {}, &mut out).unwrap();
574 assert_eq!(
575 event,
576 Event::Data {
577 stream: 1,
578 data: b"hello",
579 end_stream: false
580 }
581 );
582 assert_eq!(written, 0);
585 }
586
587 #[test]
588 fn a_long_response_gets_its_window_topped_up_before_it_can_stall() {
589 let mut connection = Connection::new();
592 let mut out = [0u8; 256];
593 let payload = [0u8; 400];
594
595 let mut updates = 0;
596 let mut delivered = 0usize;
597 let frames = 2_000;
601 for _ in 0..frames {
602 let data = frame_bytes(FrameType::Data, 0, 1, &payload);
603 let (event, written) = connection.recv(&data, |_, _| {}, &mut out).unwrap();
604 if let Event::Data { data, .. } = event {
605 delivered += data.len();
606 }
607 if written > 0 {
608 updates += 1;
609 let header = FrameHeader::parse(&out[..written]).unwrap();
610 assert_eq!(header.kind, FrameType::WindowUpdate);
611 }
612 }
613 assert_eq!(delivered, frames * 400);
614 assert!(
615 updates > 0,
616 "the connection window must be replenished, or the server stops at 65535 bytes"
617 );
618 }
619
620 #[test]
621 fn padding_and_priority_are_stripped_before_hpack_sees_the_block() {
622 let mut connection = Connection::new();
623 let mut out = [0u8; 256];
624 let payload = [2, 0, 0, 0, 0, 0, 0x88, 0xaa, 0xbb];
626 let headers = frame_bytes(
627 FrameType::Headers,
628 flags::END_HEADERS | flags::PADDED | flags::PRIORITY,
629 1,
630 &payload,
631 );
632 let mut status = heapless::String::<8>::new();
633 connection
634 .recv(
635 &headers,
636 |name, value| {
637 if name == ":status" {
638 status.push_str(value).unwrap();
639 }
640 },
641 &mut out,
642 )
643 .unwrap();
644 assert_eq!(status.as_str(), "200");
645 }
646
647 #[test]
648 fn goaway_and_reset_are_reported_rather_than_hidden() {
649 let mut connection = Connection::new();
650 let mut out = [0u8; 128];
651
652 let reset = frame_bytes(FrameType::RstStream, 0, 1, &[0, 0, 0, 8]);
653 let (event, _) = connection.recv(&reset, |_, _| {}, &mut out).unwrap();
654 assert_eq!(event, Event::Reset { stream: 1, code: 8 });
655
656 let goaway = frame_bytes(FrameType::GoAway, 0, 0, &[0, 0, 0, 1, 0, 0, 0, 2]);
657 let (event, _) = connection.recv(&goaway, |_, _| {}, &mut out).unwrap();
658 assert_eq!(event, Event::GoAway { code: 2 });
659 }
660
661 #[test]
662 fn a_promised_push_is_a_protocol_error_because_we_refused_push() {
663 let mut connection = Connection::new();
664 let mut out = [0u8; 128];
665 let promise = frame_bytes(FrameType::PushPromise, flags::END_HEADERS, 1, &[0, 0, 0, 2]);
666 assert_eq!(
667 connection.recv(&promise, |_, _| {}, &mut out).err(),
668 Some(Error::Protocol)
669 );
670 }
671
672 #[test]
673 fn an_unknown_frame_type_is_discarded_not_fatal() {
674 let mut connection = Connection::new();
675 let mut out = [0u8; 128];
676 let unknown = frame_bytes(FrameType::Unknown(0x63), 0, 0, b"whatever");
677 let (event, written) = connection.recv(&unknown, |_, _| {}, &mut out).unwrap();
678 assert_eq!(event, Event::Nothing);
679 assert_eq!(written, 0);
680 }
681}