1use std::fmt;
82
83use crate::blocking::MAX_FRAME_SIZE;
84use crate::control::RequestId;
85use crate::control_codec::{REQUEST_ID_LEN, TAG_LEN, TAG_REQUEST, read_id};
86use crate::error::ProtocolError;
87
88pub const PREFIX_LEN: usize = 4;
90
91#[derive(Debug, Clone, Copy, PartialEq, Eq)]
93pub struct Frame<'a> {
94 pub payload: &'a [u8],
96}
97
98impl Frame<'_> {
99 #[inline]
103 pub fn consumed(&self) -> usize {
104 PREFIX_LEN + self.payload.len()
105 }
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq)]
113pub struct FrameTooLarge {
114 pub declared: u32,
118 pub max: usize,
121}
122
123impl fmt::Display for FrameTooLarge {
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 write!(
126 f,
127 "frame too large: {} bytes (max {})",
128 self.declared, self.max
129 )
130 }
131}
132
133impl std::error::Error for FrameTooLarge {}
134
135impl From<FrameTooLarge> for std::io::Error {
136 fn from(e: FrameTooLarge) -> Self {
140 std::io::Error::new(std::io::ErrorKind::InvalidData, e)
141 }
142}
143
144#[inline]
149pub fn split_frame(buf: &[u8]) -> Result<Option<Frame<'_>>, FrameTooLarge> {
150 split_frame_limited(buf, MAX_FRAME_SIZE)
151}
152
153#[inline]
168pub fn split_frame_limited(
169 buf: &[u8],
170 max_payload: usize,
171) -> Result<Option<Frame<'_>>, FrameTooLarge> {
172 let Some((prefix, rest)) = buf.split_first_chunk::<PREFIX_LEN>() else {
173 return Ok(None);
174 };
175 let declared = u32::from_le_bytes(*prefix);
176 let len = match usize::try_from(declared) {
180 Ok(len) if len <= max_payload => len,
181 _ => {
182 return Err(FrameTooLarge {
183 declared,
184 max: max_payload,
185 });
186 }
187 };
188 Ok(rest.get(..len).map(|payload| Frame { payload }))
189}
190
191#[derive(Debug)]
214pub struct FrameDecoder {
215 buf: Vec<u8>,
223 start: usize,
226 max_payload: usize,
228 poisoned: Option<FrameTooLarge>,
231}
232
233impl Default for FrameDecoder {
234 fn default() -> Self {
235 Self::new()
236 }
237}
238
239impl FrameDecoder {
240 pub fn new() -> Self {
242 Self::with_max_payload(MAX_FRAME_SIZE)
243 }
244
245 pub fn with_max_payload(max_payload: usize) -> Self {
251 Self {
252 buf: Vec::with_capacity(PREFIX_LEN + max_payload.min(MAX_FRAME_SIZE)),
253 start: 0,
254 max_payload,
255 poisoned: None,
256 }
257 }
258
259 pub fn max_payload(&self) -> usize {
261 self.max_payload
262 }
263
264 pub fn is_poisoned(&self) -> bool {
266 self.poisoned.is_some()
267 }
268
269 pub fn pending(&self) -> &[u8] {
272 &self.buf[self.start..]
273 }
274
275 pub fn push(&mut self, bytes: &[u8]) {
279 if self.poisoned.is_some() {
280 return;
281 }
282 let remaining = self.buf.len() - self.start;
283 if self.start > 0 && self.start >= remaining {
284 self.buf.copy_within(self.start.., 0);
293 self.buf.truncate(remaining);
294 self.start = 0;
295 }
296 self.buf.extend_from_slice(bytes);
297 }
298
299 #[expect(clippy::should_implement_trait)] pub fn next(&mut self) -> Result<Option<&[u8]>, FrameTooLarge> {
306 if let Some(e) = self.poisoned {
307 return Err(e);
308 }
309 match split_frame_limited(&self.buf[self.start..], self.max_payload) {
310 Ok(Some(frame)) => {
311 let payload_start = self.start + PREFIX_LEN;
312 self.start += frame.consumed();
313 Ok(Some(&self.buf[payload_start..self.start]))
314 }
315 Ok(None) => Ok(None),
316 Err(e) => {
317 self.poisoned = Some(e);
318 self.buf = Vec::new();
322 self.start = 0;
323 Err(e)
324 }
325 }
326 }
327}
328
329pub const REQUEST_TAG_AND_ID_LEN: usize = TAG_LEN + REQUEST_ID_LEN;
336
337pub const REQUEST_HEADER_LEN: usize = PREFIX_LEN + REQUEST_TAG_AND_ID_LEN;
340
341pub const MAX_REQUEST_BODY: usize = MAX_FRAME_SIZE - REQUEST_TAG_AND_ID_LEN;
344
345const _: () = assert!(MAX_FRAME_SIZE <= u32::MAX as usize);
348
349#[inline]
355pub fn request_tag_and_id(id: RequestId) -> [u8; REQUEST_TAG_AND_ID_LEN] {
356 let mut out = [0u8; REQUEST_TAG_AND_ID_LEN];
357 out[0] = TAG_REQUEST;
358 out[TAG_LEN..].copy_from_slice(&id.0.to_le_bytes());
359 out
360}
361
362#[derive(Debug, Clone, Copy, PartialEq, Eq)]
364pub enum NotARequest {
365 Empty,
367 Tag(u8),
369 TooShort { len: usize },
372}
373
374impl fmt::Display for NotARequest {
375 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
376 match self {
377 Self::Empty => f.write_str("an empty frame where a request was expected"),
378 Self::Tag(tag) => write!(
379 f,
380 "a frame with tag {tag:#04x} where a request was expected"
381 ),
382 Self::TooShort { len } => write!(
383 f,
384 "a {len}-byte request frame, too short for its {REQUEST_ID_LEN}-byte ID"
385 ),
386 }
387 }
388}
389
390impl std::error::Error for NotARequest {}
391
392#[inline]
398pub fn split_request(payload: &[u8]) -> Result<(RequestId, &[u8]), NotARequest> {
399 match payload.first() {
400 None => Err(NotARequest::Empty),
401 Some(&TAG_REQUEST) => match read_id(payload) {
402 Some(id) => Ok((id, &payload[REQUEST_TAG_AND_ID_LEN..])),
403 None => Err(NotARequest::TooShort { len: payload.len() }),
404 },
405 Some(&tag) => Err(NotARequest::Tag(tag)),
406 }
407}
408
409#[derive(Debug, Clone, Copy, PartialEq, Eq)]
413pub enum RequestFrameError {
414 RequestTooLarge { len: usize },
419 BufferTooSmall { needed: usize, available: usize },
424}
425
426impl fmt::Display for RequestFrameError {
427 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
428 match self {
429 Self::RequestTooLarge { len } => write!(
430 f,
431 "request too large: {len} bytes with its tag and ID, the frame limit is {MAX_FRAME_SIZE}"
432 ),
433 Self::BufferTooSmall { needed, available } => write!(
434 f,
435 "request buffer too small: the frame needs {needed} bytes, the buffer holds {available}"
436 ),
437 }
438 }
439}
440
441impl std::error::Error for RequestFrameError {}
442
443impl From<RequestFrameError> for ProtocolError {
444 fn from(e: RequestFrameError) -> Self {
451 match e {
452 RequestFrameError::RequestTooLarge { len } => ProtocolError::MessageTooLarge(len),
453 RequestFrameError::BufferTooSmall { .. } => ProtocolError::Truncated,
454 }
455 }
456}
457
458#[inline]
467pub fn request_payload_len(body_len: usize) -> Result<u32, RequestFrameError> {
468 let len = REQUEST_TAG_AND_ID_LEN.saturating_add(body_len);
471 if len > MAX_FRAME_SIZE {
472 return Err(RequestFrameError::RequestTooLarge { len });
473 }
474 Ok(len as u32)
477}
478
479#[inline]
488pub fn request_body(buf: &mut [u8]) -> Result<&mut [u8], RequestFrameError> {
489 let available = buf.len();
490 match buf.get_mut(REQUEST_HEADER_LEN..) {
491 Some(body) => {
492 let region = body.len().min(MAX_REQUEST_BODY);
493 Ok(&mut body[..region])
494 }
495 None => Err(RequestFrameError::BufferTooSmall {
496 needed: REQUEST_HEADER_LEN,
497 available,
498 }),
499 }
500}
501
502#[inline]
543pub fn seal_request(
544 buf: &mut [u8],
545 id: RequestId,
546 body_len: usize,
547) -> Result<usize, RequestFrameError> {
548 let payload_len = request_payload_len(body_len)?;
549 let frame_len = REQUEST_HEADER_LEN + body_len;
551 let available = buf.len();
552 let Some(header) = buf
553 .get_mut(..frame_len)
554 .and_then(|frame| frame.first_chunk_mut::<REQUEST_HEADER_LEN>())
555 else {
556 return Err(RequestFrameError::BufferTooSmall {
557 needed: frame_len,
558 available,
559 });
560 };
561 header[..PREFIX_LEN].copy_from_slice(&payload_len.to_le_bytes());
562 header[PREFIX_LEN..].copy_from_slice(&request_tag_and_id(id));
563 Ok(frame_len)
564}
565
566#[inline]
614pub fn frame_request<E: From<RequestFrameError>>(
615 buf: &mut [u8],
616 id: RequestId,
617 encode: impl FnOnce(&mut [u8]) -> Result<usize, E>,
618) -> Result<usize, E> {
619 let body_len = encode(request_body(buf)?)?;
620 Ok(seal_request(buf, id, body_len)?)
621}
622
623#[cfg(test)]
624mod tests {
625 use super::*;
626 use proptest::prelude::*;
627
628 fn encode(frames: &[Vec<u8>]) -> Vec<u8> {
630 let mut out = Vec::new();
631 for f in frames {
632 out.extend_from_slice(&(f.len() as u32).to_le_bytes());
633 out.extend_from_slice(f);
634 }
635 out
636 }
637
638 fn split_all(buf: &[u8], max: usize) -> (Vec<Vec<u8>>, usize) {
640 let mut cursor = 0;
641 let mut out = Vec::new();
642 while let Some(frame) = split_frame_limited(&buf[cursor..], max).unwrap() {
643 out.push(frame.payload.to_vec());
644 cursor += frame.consumed();
645 }
646 (out, cursor)
647 }
648
649 fn decode_chunked(stream: &[u8], cuts: &[usize], max: usize) -> Vec<Vec<u8>> {
652 let mut dec = FrameDecoder::with_max_payload(max);
653 let mut out = Vec::new();
654 let mut prev = 0;
655 for &cut in cuts.iter().chain(std::iter::once(&stream.len())) {
656 dec.push(&stream[prev..cut]);
657 prev = cut;
658 while let Some(p) = dec.next().unwrap() {
659 out.push(p.to_vec());
660 }
661 }
662 assert!(dec.pending().is_empty());
663 out
664 }
665
666 #[test]
669 fn empty_and_partial_prefix_need_more() {
670 assert_eq!(split_frame(&[]), Ok(None));
671 assert_eq!(split_frame(&[3]), Ok(None));
672 assert_eq!(split_frame(&[3, 0, 0]), Ok(None));
673 }
674
675 #[test]
676 fn prefix_without_payload_needs_more() {
677 assert_eq!(split_frame(&[3, 0, 0, 0]), Ok(None));
678 assert_eq!(split_frame(&[3, 0, 0, 0, 0xAA, 0xBB]), Ok(None));
679 }
680
681 #[test]
682 fn complete_frame_ignores_trailing_bytes() {
683 let buf = [3, 0, 0, 0, 0xAA, 0xBB, 0xCC, 0xFF, 0xFF];
684 let frame = split_frame(&buf).unwrap().unwrap();
685 assert_eq!(frame.payload, &[0xAA, 0xBB, 0xCC]);
686 assert_eq!(frame.consumed(), 7);
687 }
688
689 #[test]
690 fn zero_length_frame_is_an_empty_payload() {
691 let buf = [0, 0, 0, 0, 9];
692 let frame = split_frame(&buf).unwrap().unwrap();
693 assert!(frame.payload.is_empty());
694 assert_eq!(frame.consumed(), PREFIX_LEN);
695 }
696
697 #[test]
698 fn exact_limit_succeeds() {
699 let stream = encode(&[vec![7u8; MAX_FRAME_SIZE]]);
700 let frame = split_frame(&stream).unwrap().unwrap();
701 assert_eq!(frame.payload.len(), MAX_FRAME_SIZE);
702 assert_eq!(frame.consumed(), stream.len());
703 }
704
705 #[test]
706 fn oversized_fails_on_the_prefix_alone() {
707 let declared = MAX_FRAME_SIZE as u32 + 1;
708 assert_eq!(
709 split_frame(&declared.to_le_bytes()),
710 Err(FrameTooLarge {
711 declared,
712 max: MAX_FRAME_SIZE
713 })
714 );
715 }
716
717 #[test]
718 fn max_u32_prefix_reports_the_declared_length() {
719 assert_eq!(
720 split_frame(&[0xFF; 4]),
721 Err(FrameTooLarge {
722 declared: u32::MAX,
723 max: MAX_FRAME_SIZE
724 })
725 );
726 }
727
728 #[test]
729 fn custom_limit_is_respected() {
730 let at = encode(&[vec![1u8; 256]]);
731 assert_eq!(
732 split_frame_limited(&at, 256)
733 .unwrap()
734 .unwrap()
735 .payload
736 .len(),
737 256
738 );
739 let over = encode(&[vec![1u8; 257]]);
740 assert_eq!(
741 split_frame_limited(&over[..PREFIX_LEN], 256),
742 Err(FrameTooLarge {
743 declared: 257,
744 max: 256
745 })
746 );
747 assert!(split_frame(&over).unwrap().is_some());
749 }
750
751 #[test]
752 fn zero_limit_admits_only_empty_frames() {
753 assert!(split_frame_limited(&[0, 0, 0, 0], 0).unwrap().is_some());
754 assert_eq!(
755 split_frame_limited(&[1, 0, 0, 0], 0),
756 Err(FrameTooLarge {
757 declared: 1,
758 max: 0
759 })
760 );
761 }
762
763 #[test]
764 fn limit_above_u32_admits_every_prefix() {
765 assert_eq!(split_frame_limited(&[0xFF; 4], usize::MAX), Ok(None));
766 }
767
768 #[test]
769 fn error_converts_to_invalid_data() {
770 let e: std::io::Error = FrameTooLarge {
771 declared: 2000,
772 max: 1024,
773 }
774 .into();
775 assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
776 assert_eq!(e.to_string(), "frame too large: 2000 bytes (max 1024)");
777 }
778
779 #[test]
782 fn every_truncation_yields_whole_frames_only() {
783 let frames = vec![vec![], vec![1], vec![2, 3, 4], vec![], vec![5; 40]];
784 let stream = encode(&frames);
785 for end in 0..=stream.len() {
786 let (got, consumed) = split_all(&stream[..end], MAX_FRAME_SIZE);
787 assert_eq!(got, frames[..got.len()], "end {end}");
788 assert_eq!(consumed, encode(&got).len(), "end {end}");
789 if got.len() < frames.len() {
791 assert!(end - consumed < PREFIX_LEN + frames[got.len()].len());
792 }
793 }
794 }
795
796 #[test]
799 fn decoder_splits_at_every_boundary() {
800 let frames = vec![vec![], vec![1], vec![2, 3, 4], vec![], vec![5; 40]];
801 let stream = encode(&frames);
802 for cut in 0..=stream.len() {
803 assert_eq!(decode_chunked(&stream, &[cut], MAX_FRAME_SIZE), frames);
804 }
805 for a in 0..=stream.len() {
806 for b in a..=stream.len() {
807 assert_eq!(decode_chunked(&stream, &[a, b], MAX_FRAME_SIZE), frames);
808 }
809 }
810 }
811
812 #[test]
813 fn decoder_byte_at_a_time() {
814 let frames = vec![vec![9; 3], vec![], vec![8; MAX_FRAME_SIZE]];
815 let stream = encode(&frames);
816 let cuts: Vec<usize> = (1..stream.len()).collect();
817 assert_eq!(decode_chunked(&stream, &cuts, MAX_FRAME_SIZE), frames);
818 }
819
820 #[test]
821 fn decoder_keeps_pipelined_bytes_pending() {
822 let mut dec = FrameDecoder::new();
823 dec.push(&encode(&[vec![1, 2]]));
824 dec.push(&[5, 0, 0, 0, 7]);
825 assert_eq!(dec.next().unwrap(), Some(&[1u8, 2][..]));
826 assert_eq!(dec.next().unwrap(), None);
827 assert_eq!(dec.pending(), &[5, 0, 0, 0, 7]);
828 dec.push(&[8, 9, 10, 11]);
830 assert_eq!(dec.next().unwrap(), Some(&[7u8, 8, 9, 10, 11][..]));
831 assert!(dec.pending().is_empty());
832 }
833
834 #[test]
835 fn decoder_interleaved_push_and_single_next() {
836 let frames: Vec<Vec<u8>> = (0..64u8).map(|i| vec![i; usize::from(i % 7)]).collect();
840 let stream = encode(&frames);
841 let mut dec = FrameDecoder::new();
842 let mut out = Vec::new();
843 for chunk in stream.chunks(5) {
844 let live_before = dec.pending().len();
845 dec.push(chunk);
846 assert!(dec.buf.len() <= 2 * live_before + chunk.len());
847 if let Some(p) = dec.next().unwrap() {
848 out.push(p.to_vec());
849 }
850 }
851 while let Some(p) = dec.next().unwrap() {
852 out.push(p.to_vec());
853 }
854 assert_eq!(out, frames);
855 assert!(dec.pending().is_empty());
856 }
857
858 #[test]
859 fn decoder_poisons_on_oversized_prefix() {
860 let mut dec = FrameDecoder::with_max_payload(256);
861 assert_eq!(dec.max_payload(), 256);
862 dec.push(&encode(&[vec![1]]));
863 dec.push(&257u32.to_le_bytes());
864 assert_eq!(dec.next().unwrap(), Some(&[1u8][..]));
866 let err = FrameTooLarge {
867 declared: 257,
868 max: 256,
869 };
870 assert_eq!(dec.next(), Err(err));
871 assert!(dec.is_poisoned());
872 assert!(dec.pending().is_empty());
873 dec.push(&encode(&[vec![2]]));
875 assert!(dec.pending().is_empty());
876 assert_eq!(dec.next(), Err(err));
877 }
878
879 #[test]
880 fn decoder_starts_empty() {
881 let mut dec = FrameDecoder::default();
882 assert_eq!(dec.max_payload(), MAX_FRAME_SIZE);
883 assert!(!dec.is_poisoned());
884 assert_eq!(dec.next(), Ok(None));
885 dec.push(&[]);
886 assert_eq!(dec.next(), Ok(None));
887 }
888
889 const ID: RequestId = RequestId(0x0807_0605_0403_0201);
894
895 fn request_frame_with(id: RequestId, body: &[u8]) -> Vec<u8> {
898 let mut frame = ((TAG_LEN + REQUEST_ID_LEN + body.len()) as u32)
899 .to_le_bytes()
900 .to_vec();
901 frame.push(TAG_REQUEST);
902 frame.extend_from_slice(&id.0.to_le_bytes());
903 frame.extend_from_slice(body);
904 frame
905 }
906
907 fn app_frame(body: &[u8]) -> Vec<u8> {
909 request_frame_with(ID, body)
910 }
911
912 fn frame_body(buf: &mut [u8], body: &[u8]) -> Result<usize, RequestFrameError> {
915 frame_body_as(buf, ID, body)
916 }
917
918 fn frame_body_as(
920 buf: &mut [u8],
921 id: RequestId,
922 body: &[u8],
923 ) -> Result<usize, RequestFrameError> {
924 frame_request(buf, id, |out| {
925 let Some(dst) = out.get_mut(..body.len()) else {
926 return Err(RequestFrameError::BufferTooSmall {
927 needed: body.len(),
928 available: out.len(),
929 });
930 };
931 dst.copy_from_slice(body);
932 Ok(body.len())
933 })
934 }
935
936 #[test]
937 fn request_constants_follow_the_frame_limit() {
938 assert_eq!(REQUEST_HEADER_LEN, PREFIX_LEN + TAG_LEN + REQUEST_ID_LEN);
939 assert_eq!(REQUEST_HEADER_LEN, 13);
940 assert_eq!(MAX_FRAME_SIZE, 1024);
942 assert_eq!(MAX_REQUEST_BODY, MAX_FRAME_SIZE - TAG_LEN - REQUEST_ID_LEN);
943 assert_eq!(MAX_REQUEST_BODY, 1015);
944 assert_eq!(
945 request_payload_len(MAX_REQUEST_BODY),
946 Ok(MAX_FRAME_SIZE as u32)
947 );
948 assert_eq!(
949 request_payload_len(MAX_REQUEST_BODY + 1),
950 Err(RequestFrameError::RequestTooLarge {
951 len: MAX_FRAME_SIZE + 1
952 })
953 );
954 assert_eq!(
955 request_payload_len(usize::MAX),
956 Err(RequestFrameError::RequestTooLarge { len: usize::MAX })
957 );
958 }
959
960 #[test]
961 fn request_body_is_the_rest_capped_at_the_widest_body() {
962 let mut buf = [0u8; 32];
963 assert_eq!(
964 request_body(&mut buf).unwrap().len(),
965 32 - REQUEST_HEADER_LEN
966 );
967 let mut wide = vec![0u8; REQUEST_HEADER_LEN + MAX_FRAME_SIZE + 16];
968 assert_eq!(request_body(&mut wide).unwrap().len(), MAX_REQUEST_BODY);
969 let mut header_only = [0u8; REQUEST_HEADER_LEN];
970 assert!(request_body(&mut header_only).unwrap().is_empty());
971 for len in 0..REQUEST_HEADER_LEN {
972 assert_eq!(
973 request_body(&mut vec![0u8; len]),
974 Err(RequestFrameError::BufferTooSmall {
975 needed: REQUEST_HEADER_LEN,
976 available: len
977 })
978 );
979 }
980 }
981
982 #[test]
983 fn seal_request_writes_the_header_and_nothing_else() {
984 let mut buf = [0xEE; 32];
985 buf[REQUEST_HEADER_LEN..REQUEST_HEADER_LEN + 3].copy_from_slice(b"abc");
986 let n = seal_request(&mut buf, ID, 3).unwrap();
987 assert_eq!(n, REQUEST_HEADER_LEN + 3);
988 assert_eq!(&buf[..n], app_frame(b"abc").as_slice());
989 assert_eq!(buf[PREFIX_LEN], TAG_REQUEST);
991 assert_eq!(
992 &buf[PREFIX_LEN + 1..REQUEST_HEADER_LEN],
993 &ID.0.to_le_bytes()
994 );
995 assert!(buf[n..].iter().all(|&b| b == 0xEE));
996
997 let mut buf = [0u8; REQUEST_HEADER_LEN];
1000 assert_eq!(seal_request(&mut buf, ID, 0), Ok(REQUEST_HEADER_LEN));
1001 assert_eq!(buf.as_slice(), app_frame(b"").as_slice());
1002
1003 for id in [0, 1, u64::MAX] {
1005 let mut buf = [0u8; REQUEST_HEADER_LEN];
1006 seal_request(&mut buf, RequestId(id), 0).unwrap();
1007 assert_eq!(buf.as_slice(), request_frame_with(RequestId(id), b""));
1008 }
1009 }
1010
1011 #[test]
1012 fn the_tag_and_id_are_laid_out_once() {
1013 let header = request_tag_and_id(ID);
1014 assert_eq!(header.len(), REQUEST_TAG_AND_ID_LEN);
1015 assert_eq!(header, request_frame_with(ID, b"")[PREFIX_LEN..]);
1016 }
1017
1018 #[test]
1019 fn split_request_reads_the_id_and_the_body() {
1020 let frame = app_frame(b"body");
1021 assert_eq!(split_request(&frame[PREFIX_LEN..]), Ok((ID, &b"body"[..])));
1022 let empty = app_frame(b"");
1024 assert_eq!(split_request(&empty[PREFIX_LEN..]), Ok((ID, &b""[..])));
1025 assert_eq!(split_request(&[]), Err(NotARequest::Empty));
1027 for len in 1..REQUEST_TAG_AND_ID_LEN {
1029 assert_eq!(
1030 split_request(&empty[PREFIX_LEN..PREFIX_LEN + len]),
1031 Err(NotARequest::TooShort { len })
1032 );
1033 }
1034 for tag in (0..=u8::MAX).filter(|&t| t != TAG_REQUEST) {
1036 let payload = [&[tag][..], &[0x11; 16]].concat();
1037 assert_eq!(split_request(&payload), Err(NotARequest::Tag(tag)));
1038 assert_eq!(split_request(&[tag]), Err(NotARequest::Tag(tag)));
1039 }
1040 assert!(NotARequest::Empty.to_string().contains("empty"));
1042 assert!(NotARequest::Tag(0x09).to_string().contains("0x09"));
1043 assert!(
1044 NotARequest::TooShort { len: 4 }
1045 .to_string()
1046 .contains("4-byte")
1047 );
1048 }
1049
1050 #[test]
1051 fn seal_request_refuses_without_writing() {
1052 let mut buf = [0x77u8; REQUEST_HEADER_LEN + 4];
1054 assert_eq!(
1055 seal_request(&mut buf, ID, 5),
1056 Err(RequestFrameError::BufferTooSmall {
1057 needed: REQUEST_HEADER_LEN + 5,
1058 available: REQUEST_HEADER_LEN + 4
1059 })
1060 );
1061 for len in 0..REQUEST_HEADER_LEN {
1063 let mut short = vec![0x77u8; len];
1064 assert_eq!(
1065 seal_request(&mut short, ID, 0),
1066 Err(RequestFrameError::BufferTooSmall {
1067 needed: REQUEST_HEADER_LEN,
1068 available: len
1069 })
1070 );
1071 assert!(short.iter().all(|&b| b == 0x77));
1072 }
1073 let mut wide = vec![0x77u8; REQUEST_HEADER_LEN + MAX_FRAME_SIZE + 16];
1076 assert_eq!(
1077 seal_request(&mut wide, ID, MAX_REQUEST_BODY + 1),
1078 Err(RequestFrameError::RequestTooLarge {
1079 len: MAX_FRAME_SIZE + 1
1080 })
1081 );
1082 assert_eq!(
1083 seal_request(&mut buf, ID, usize::MAX),
1084 Err(RequestFrameError::RequestTooLarge { len: usize::MAX })
1085 );
1086 assert!(wide.iter().all(|&b| b == 0x77));
1087 assert!(buf.iter().all(|&b| b == 0x77));
1088 }
1089
1090 #[test]
1091 fn frame_request_writes_the_header_in_front_of_the_body() {
1092 let mut buf = [0xEE; 32];
1093 let n = frame_body(&mut buf, b"abc").unwrap();
1094 assert_eq!(n, REQUEST_HEADER_LEN + 3);
1095 assert_eq!(&buf[..n], app_frame(b"abc").as_slice());
1096 assert!(buf[n..].iter().all(|&b| b == 0xEE));
1098
1099 let n = frame_request(&mut buf, ID, |out| {
1102 assert_eq!(out.len(), 32 - REQUEST_HEADER_LEN);
1103 Ok::<_, RequestFrameError>(0)
1104 })
1105 .unwrap();
1106 assert_eq!(&buf[..n], app_frame(b"").as_slice());
1107 }
1108
1109 #[test]
1110 fn frame_request_takes_the_widest_body_and_refuses_one_more() {
1111 let mut buf = vec![0u8; REQUEST_HEADER_LEN + MAX_FRAME_SIZE + 16];
1112
1113 let widest = vec![0xAB; MAX_REQUEST_BODY];
1114 let n = frame_body(&mut buf, &widest).unwrap();
1115 assert_eq!(n, PREFIX_LEN + MAX_FRAME_SIZE);
1116 let frame = split_frame(&buf[..n]).unwrap().unwrap();
1117 assert_eq!(frame.consumed(), n);
1118 assert_eq!(split_request(frame.payload), Ok((ID, widest.as_slice())));
1119
1120 let mut buf = vec![0x5C; REQUEST_HEADER_LEN + MAX_FRAME_SIZE + 16];
1124 let err = frame_request(&mut buf, ID, |out| {
1125 assert_eq!(out.len(), MAX_REQUEST_BODY);
1126 Ok::<_, RequestFrameError>(MAX_REQUEST_BODY + 1)
1127 })
1128 .unwrap_err();
1129 assert_eq!(
1130 err,
1131 RequestFrameError::RequestTooLarge {
1132 len: MAX_FRAME_SIZE + 1
1133 }
1134 );
1135 assert!(buf[..REQUEST_HEADER_LEN].iter().all(|&b| b == 0x5C));
1136
1137 let err =
1141 frame_request(&mut buf, ID, |_| Ok::<_, RequestFrameError>(usize::MAX)).unwrap_err();
1142 assert_eq!(err, RequestFrameError::RequestTooLarge { len: usize::MAX });
1143 let mut small = [0u8; 16];
1144 let err = frame_request(&mut small, ID, |_| {
1145 Ok::<_, RequestFrameError>(MAX_REQUEST_BODY + 1)
1146 })
1147 .unwrap_err();
1148 assert!(
1149 matches!(err, RequestFrameError::RequestTooLarge { .. }),
1150 "{err:?}"
1151 );
1152 }
1153
1154 #[test]
1155 fn frame_request_refuses_a_buffer_too_small() {
1156 for len in 0..REQUEST_HEADER_LEN {
1158 let mut buf = vec![0u8; len];
1159 let err = frame_request(&mut buf, ID, |_| -> Result<usize, RequestFrameError> {
1160 panic!("the encoder must not run without room for the header")
1161 })
1162 .unwrap_err();
1163 assert_eq!(
1164 err,
1165 RequestFrameError::BufferTooSmall {
1166 needed: REQUEST_HEADER_LEN,
1167 available: len
1168 }
1169 );
1170 assert!(err.to_string().contains("too small"), "{err}");
1171 }
1172
1173 let mut buf = [0u8; REQUEST_HEADER_LEN];
1175 assert_eq!(frame_body(&mut buf, b"").unwrap(), REQUEST_HEADER_LEN);
1176
1177 let mut buf = [0x77u8; REQUEST_HEADER_LEN + 4];
1180 let err = frame_request(&mut buf, ID, |_| Ok::<_, RequestFrameError>(5)).unwrap_err();
1181 assert_eq!(
1182 err,
1183 RequestFrameError::BufferTooSmall {
1184 needed: REQUEST_HEADER_LEN + 5,
1185 available: REQUEST_HEADER_LEN + 4
1186 }
1187 );
1188 assert!(buf[..REQUEST_HEADER_LEN].iter().all(|&b| b == 0x77));
1189 }
1190
1191 #[test]
1192 fn frame_request_passes_the_encoders_error_through() {
1193 #[derive(Debug, PartialEq)]
1194 enum CodecError {
1195 Mine,
1196 Framing(RequestFrameError),
1197 }
1198 impl From<RequestFrameError> for CodecError {
1199 fn from(e: RequestFrameError) -> Self {
1200 CodecError::Framing(e)
1201 }
1202 }
1203 let mut buf = [0x33u8; 24];
1204 assert_eq!(
1205 frame_request(&mut buf, ID, |_| Err(CodecError::Mine)),
1206 Err(CodecError::Mine)
1207 );
1208 assert!(buf.iter().all(|&b| b == 0x33));
1209 assert_eq!(
1211 frame_request(&mut buf[..2], ID, |_| Ok::<_, CodecError>(0)),
1212 Err(CodecError::Framing(RequestFrameError::BufferTooSmall {
1213 needed: REQUEST_HEADER_LEN,
1214 available: 2
1215 }))
1216 );
1217 }
1218
1219 fn encode_request_as_codec(body: &[u8], buf: &mut [u8]) -> Result<usize, ProtocolError> {
1222 let region = request_body(buf)?;
1223 let dst = region
1224 .get_mut(..body.len())
1225 .ok_or(ProtocolError::InvalidField("body"))?;
1226 dst.copy_from_slice(body);
1227 Ok(seal_request(buf, ID, body.len())?)
1228 }
1229
1230 #[test]
1231 fn a_protocol_error_codec_frames_with_question_mark() {
1232 let mut buf = [0u8; 24];
1233 assert_eq!(
1234 encode_request_as_codec(b"abc", &mut buf).unwrap(),
1235 REQUEST_HEADER_LEN + 3
1236 );
1237 assert_eq!(&buf[..REQUEST_HEADER_LEN + 3], app_frame(b"abc").as_slice());
1238 assert!(matches!(
1239 encode_request_as_codec(b"", &mut buf[..2]),
1240 Err(ProtocolError::Truncated)
1241 ));
1242 let err = frame_request(&mut [0u8; 16], ID, |_| {
1244 Ok::<_, ProtocolError>(MAX_REQUEST_BODY + 1)
1245 })
1246 .unwrap_err();
1247 assert!(
1248 matches!(err, ProtocolError::MessageTooLarge(len) if len == MAX_FRAME_SIZE + 1),
1249 "{err:?}"
1250 );
1251 assert!(matches!(
1252 ProtocolError::from(RequestFrameError::BufferTooSmall {
1253 needed: 9,
1254 available: 8
1255 }),
1256 ProtocolError::Truncated
1257 ));
1258 }
1259
1260 #[test]
1261 fn request_frame_errors_say_what_failed() {
1262 assert_eq!(
1263 RequestFrameError::RequestTooLarge { len: 2000 }.to_string(),
1264 format!(
1265 "request too large: 2000 bytes with its tag and ID, the frame limit is {MAX_FRAME_SIZE}"
1266 )
1267 );
1268 assert_eq!(
1269 RequestFrameError::BufferTooSmall {
1270 needed: 9,
1271 available: 8
1272 }
1273 .to_string(),
1274 "request buffer too small: the frame needs 9 bytes, the buffer holds 8"
1275 );
1276 }
1277
1278 #[test]
1279 fn frame_request_frames_at_an_offset_and_batches_back_to_back() {
1280 let bodies: [&[u8]; 4] = [b"one", b"", &[TAG_REQUEST, 0x00], b"four!"];
1281 let mut buf = [0xEE; 128];
1282 let start = 7;
1284 let mut end = start;
1285 let mut expected = Vec::new();
1286 for (n, body) in bodies.into_iter().enumerate() {
1287 let id = RequestId(n as u64 + 1);
1288 end += frame_body_as(&mut buf[end..], id, body).unwrap();
1289 expected.extend(request_frame_with(id, body));
1290 }
1291 assert!(buf[..start].iter().all(|&b| b == 0xEE));
1292 assert!(buf[end..].iter().all(|&b| b == 0xEE));
1293 assert_eq!(&buf[start..end], expected.as_slice());
1294 }
1295
1296 fn arb_frames(max: usize) -> impl Strategy<Value = Vec<Vec<u8>>> {
1299 prop::collection::vec(prop::collection::vec(any::<u8>(), 0..=max), 0..12)
1300 }
1301
1302 proptest! {
1303 #[test]
1306 fn any_chunking_yields_the_same_frames(
1307 frames in arb_frames(64),
1308 raw_cuts in prop::collection::vec(any::<prop::sample::Index>(), 0..16),
1309 ) {
1310 let stream = encode(&frames);
1311 let mut cuts: Vec<usize> =
1312 raw_cuts.iter().map(|i| i.index(stream.len() + 1)).collect();
1313 cuts.sort_unstable();
1314 prop_assert_eq!(decode_chunked(&stream, &cuts, 64), frames.clone());
1315 prop_assert_eq!(split_all(&stream, 64), (frames, stream.len()));
1316 }
1317
1318 #[test]
1321 fn oversized_prefix_fails_on_arrival(
1322 frames in arb_frames(32),
1323 max in 0usize..64,
1324 excess in 1u32..1_000_000,
1325 cut in any::<prop::sample::Index>(),
1326 ) {
1327 let good: Vec<Vec<u8>> =
1328 frames.into_iter().map(|mut f| { f.truncate(max); f }).collect();
1329 let declared = max as u32 + excess;
1330 let mut stream = encode(&good);
1331 stream.extend_from_slice(&declared.to_le_bytes());
1332 let cut = cut.index(stream.len() + 1);
1333
1334 let mut dec = FrameDecoder::with_max_payload(max);
1335 let mut got = Vec::new();
1336 let mut result = Ok(());
1337 for chunk in [&stream[..cut], &stream[cut..]] {
1338 dec.push(chunk);
1339 loop {
1340 match dec.next() {
1341 Ok(Some(p)) => got.push(p.to_vec()),
1342 Ok(None) => break,
1343 Err(e) => { result = Err(e); break; }
1344 }
1345 }
1346 }
1347 prop_assert_eq!(got, good);
1348 prop_assert_eq!(result, Err(FrameTooLarge { declared, max }));
1349 }
1350
1351 #[test]
1355 fn framed_requests_round_trip_through_the_decoder(
1356 requests in prop::collection::vec(
1357 (any::<u64>(), prop::collection::vec(any::<u8>(), 0..=64)),
1358 0..8,
1359 ),
1360 offset in 0usize..16,
1361 chunk in 1usize..32,
1362 ) {
1363 let mut buf = vec![0u8; offset + requests.len() * (REQUEST_HEADER_LEN + 64)];
1364 let mut end = offset;
1365 for (id, body) in &requests {
1366 end += frame_body_as(&mut buf[end..], RequestId(*id), body).unwrap();
1367 }
1368 let mut decoder = FrameDecoder::new();
1369 let mut got = Vec::new();
1370 for piece in buf[offset..end].chunks(chunk) {
1371 decoder.push(piece);
1372 while let Some(payload) = decoder.next().unwrap() {
1373 let (id, body) = split_request(payload).unwrap();
1374 got.push((id.0, body.to_vec()));
1375 }
1376 }
1377 prop_assert_eq!(got, requests);
1378 prop_assert!(decoder.pending().is_empty());
1379 }
1380 }
1381}