changelog shortlog graph tags branches changeset files revisions annotate raw help

Mercurial > core / rust/lib/net/src/codec/dm.rs

changeset 698: 96958d3eb5b0
parent: c7165d93a9eb
author: Richard Westhaver <ellis@rwest.io>
date: Fri, 04 Oct 2024 22:04:59 -0400
permissions: -rw-r--r--
description: fixes
1 //! A state-less messaging protocol
2 use tokio_util::codec::{Encoder, Decoder};
3 use bytes::{BytesMut, Buf};
4 mod build;
5 use build::Builder;
6 
7 pub const MAX: usize = usize::MAX;
8 #[derive(Debug)]
9 pub struct DmCodec {
10  builder: Builder,
11  state: DecodeState,
12 }
13 
14 #[derive(Debug, Clone, Copy)]
15 pub enum DecodeState {
16  Head,
17  Data(usize),
18 }
19 
20 impl Encoder<String> for DmCodec {
21  type Error = std::io::Error;
22  fn encode(&mut self, item: String, dst: &mut BytesMut) -> Result<(), Self::Error> {
23  // Don't send a string if it is longer than the other end will
24  // accept.
25  if item.len() > MAX {
26  return Err(std::io::Error::new(
27  std::io::ErrorKind::InvalidData,
28  format!("Frame of length {} is too large.", item.len())
29  ));
30  }
31 
32  // Convert the length into a byte array.
33  // The cast to u32 cannot overflow due to the length check above.
34  let len_slice = u32::to_le_bytes(item.len() as u32);
35 
36  // Reserve space in the buffer.
37  dst.reserve(4 + item.len());
38 
39  // Write the length and string to the buffer.
40  dst.extend_from_slice(&len_slice);
41  dst.extend_from_slice(item.as_bytes());
42  Ok(())
43  }
44 }
45 
46 impl Decoder for DmCodec {
47  type Item = String;
48  type Error = std::io::Error;
49 
50  fn decode(
51  &mut self,
52  src: &mut BytesMut
53  ) -> Result<Option<Self::Item>, Self::Error> {
54  if src.len() < 4 {
55  // Not enough data to read length marker.
56  return Ok(None);
57  }
58 
59  // Read length marker.
60  let mut length_bytes = [0u8; 4];
61  length_bytes.copy_from_slice(&src[..4]);
62  let length = u32::from_le_bytes(length_bytes) as usize;
63 
64  // Check that the length is not too large to avoid a denial of
65  // service attack where the server runs out of memory.
66  if length > MAX {
67  return Err(std::io::Error::new(
68  std::io::ErrorKind::InvalidData,
69  format!("Frame of length {} is too large.", length)
70  ));
71  }
72 
73  if src.len() < 4 + length {
74  // The full string has not yet arrived.
75  //
76  // We reserve more space in the buffer. This is not strictly
77  // necessary, but is a good idea performance-wise.
78  src.reserve(4 + length - src.len());
79 
80  // We inform the Framed that we need more bytes to form the next
81  // frame.
82  return Ok(None);
83  }
84 
85  // Use advance to modify src such that it no longer contains
86  // this frame.
87  let data = src[4..4 + length].to_vec();
88  src.advance(4 + length);
89 
90  // Convert the data to a string, or fail if it is not valid utf-8.
91  match String::from_utf8(data) {
92  Ok(string) => Ok(Some(string)),
93  Err(utf8_error) => {
94  Err(std::io::Error::new(
95  std::io::ErrorKind::InvalidData,
96  utf8_error.utf8_error(),
97  ))
98  },
99  }
100  }
101 }