1use bytes::Bytes;
12use tokio_util::{
13 bytes::{Buf, BufMut, BytesMut},
14 codec::{Decoder, Encoder},
15};
16
17mod two_part;
18pub mod zero_copy_decoder;
19
20pub use two_part::{TwoPartCodec, TwoPartMessage, TwoPartMessageType};
21pub use zero_copy_decoder::{TcpRequestMessageZeroCopy, ZeroCopyTcpDecoder};
22
23const TCP_REQUEST_ENDPOINT_LEN_WIDTH: usize = 2;
24const TCP_REQUEST_HEADERS_LEN_WIDTH: usize = 2;
25const TCP_REQUEST_PAYLOAD_LEN_WIDTH: usize = 4;
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28struct TcpRequestWireHeader {
29 endpoint_len: usize,
30 headers_len: usize,
31 payload_len: usize,
32 header_size: usize,
33 total_len: usize,
34}
35
36impl TcpRequestWireHeader {
37 fn endpoint_start(&self) -> usize {
38 TCP_REQUEST_ENDPOINT_LEN_WIDTH
39 }
40
41 fn endpoint_end(&self) -> usize {
42 self.endpoint_start() + self.endpoint_len
43 }
44
45 fn headers_start(&self) -> usize {
46 self.endpoint_end() + TCP_REQUEST_HEADERS_LEN_WIDTH
47 }
48
49 fn headers_end(&self) -> usize {
50 self.headers_start() + self.headers_len
51 }
52
53 fn payload_start(&self) -> usize {
54 self.header_size
55 }
56}
57
58fn tcp_request_header_size(endpoint_len: usize, headers_len: usize) -> usize {
59 TCP_REQUEST_ENDPOINT_LEN_WIDTH
60 + endpoint_len
61 + TCP_REQUEST_HEADERS_LEN_WIDTH
62 + headers_len
63 + TCP_REQUEST_PAYLOAD_LEN_WIDTH
64}
65
66fn tcp_request_total_len(
67 endpoint_len: usize,
68 headers_len: usize,
69 payload_len: usize,
70) -> Result<TcpRequestWireHeader, std::io::Error> {
71 let header_size = tcp_request_header_size(endpoint_len, headers_len);
72 let total_len = header_size.checked_add(payload_len).ok_or_else(|| {
73 std::io::Error::new(
74 std::io::ErrorKind::InvalidData,
75 "TCP request message length overflow",
76 )
77 })?;
78
79 Ok(TcpRequestWireHeader {
80 endpoint_len,
81 headers_len,
82 payload_len,
83 header_size,
84 total_len,
85 })
86}
87
88fn validate_tcp_request_encode_lengths(
89 endpoint_len: usize,
90 headers_len: usize,
91 payload_len: usize,
92) -> Result<TcpRequestWireHeader, std::io::Error> {
93 if endpoint_len > u16::MAX as usize {
94 return Err(std::io::Error::new(
95 std::io::ErrorKind::InvalidInput,
96 format!("Endpoint path too long: {} bytes", endpoint_len),
97 ));
98 }
99
100 if headers_len > u16::MAX as usize {
101 return Err(std::io::Error::new(
102 std::io::ErrorKind::InvalidInput,
103 format!("Headers too large: {} bytes", headers_len),
104 ));
105 }
106
107 if payload_len > u32::MAX as usize {
108 return Err(std::io::Error::new(
109 std::io::ErrorKind::InvalidInput,
110 format!("Payload too large: {} bytes", payload_len),
111 ));
112 }
113
114 tcp_request_total_len(endpoint_len, headers_len, payload_len)
115}
116
117fn tcp_request_endpoint_len(bytes: &[u8]) -> Result<usize, std::io::Error> {
118 if bytes.len() < TCP_REQUEST_ENDPOINT_LEN_WIDTH {
119 return Err(std::io::Error::new(
120 std::io::ErrorKind::UnexpectedEof,
121 "Not enough bytes for endpoint path length",
122 ));
123 }
124
125 Ok(u16::from_be_bytes([bytes[0], bytes[1]]) as usize)
126}
127
128fn tcp_request_headers_len(bytes: &[u8], endpoint_len: usize) -> Result<usize, std::io::Error> {
129 let endpoint_end = TCP_REQUEST_ENDPOINT_LEN_WIDTH + endpoint_len;
130 if bytes.len() < endpoint_end {
131 return Err(std::io::Error::new(
132 std::io::ErrorKind::UnexpectedEof,
133 "Not enough bytes for endpoint path",
134 ));
135 }
136
137 if bytes.len() < endpoint_end + TCP_REQUEST_HEADERS_LEN_WIDTH {
138 return Err(std::io::Error::new(
139 std::io::ErrorKind::UnexpectedEof,
140 "Not enough bytes for headers length",
141 ));
142 }
143
144 Ok(u16::from_be_bytes([bytes[endpoint_end], bytes[endpoint_end + 1]]) as usize)
145}
146
147fn parse_tcp_request_frame_header(bytes: &[u8]) -> Result<TcpRequestWireHeader, std::io::Error> {
148 let endpoint_len = tcp_request_endpoint_len(bytes)?;
149 let headers_len = tcp_request_headers_len(bytes, endpoint_len)?;
150
151 let headers_end =
152 TCP_REQUEST_ENDPOINT_LEN_WIDTH + endpoint_len + TCP_REQUEST_HEADERS_LEN_WIDTH + headers_len;
153 if bytes.len() < headers_end {
154 return Err(std::io::Error::new(
155 std::io::ErrorKind::UnexpectedEof,
156 "Not enough bytes for headers",
157 ));
158 }
159
160 if bytes.len() < headers_end + TCP_REQUEST_PAYLOAD_LEN_WIDTH {
161 return Err(std::io::Error::new(
162 std::io::ErrorKind::UnexpectedEof,
163 "Not enough bytes for payload length",
164 ));
165 }
166
167 let payload_len = u32::from_be_bytes([
168 bytes[headers_end],
169 bytes[headers_end + 1],
170 bytes[headers_end + 2],
171 bytes[headers_end + 3],
172 ]) as usize;
173
174 tcp_request_total_len(endpoint_len, headers_len, payload_len)
175}
176
177fn parse_tcp_request_frame(bytes: &[u8]) -> Result<TcpRequestWireHeader, std::io::Error> {
178 let parsed = parse_tcp_request_frame_header(bytes)?;
179 if bytes.len() < parsed.total_len {
180 return Err(std::io::Error::new(
181 std::io::ErrorKind::UnexpectedEof,
182 format!(
183 "Not enough bytes for payload: expected {}, got {}",
184 parsed.payload_len,
185 bytes.len().saturating_sub(parsed.payload_start())
186 ),
187 ));
188 }
189
190 Ok(parsed)
191}
192
193fn check_tcp_request_max_message_size(
194 total_len: usize,
195 max_message_size: usize,
196) -> Result<(), std::io::Error> {
197 if total_len > max_message_size {
198 return Err(std::io::Error::new(
199 std::io::ErrorKind::InvalidData,
200 format!(
201 "message too large: {} bytes (max: {} bytes)",
202 total_len, max_message_size
203 ),
204 ));
205 }
206
207 Ok(())
208}
209
210#[derive(Debug, Clone, PartialEq, Eq)]
220pub struct TcpRequestMessage {
221 pub endpoint_path: String,
222 pub headers: std::collections::HashMap<String, String>,
223 pub payload: Bytes,
224}
225
226#[derive(Debug, Clone, PartialEq, Eq)]
231pub struct TcpRequestFrame {
232 pub header: Bytes,
233 pub payload: Bytes,
234}
235
236impl TcpRequestFrame {
237 pub fn encoded_len(&self) -> usize {
238 self.header.len() + self.payload.len()
239 }
240}
241
242impl TcpRequestMessage {
243 pub fn new(endpoint_path: String, payload: Bytes) -> Self {
244 Self {
245 endpoint_path,
246 headers: std::collections::HashMap::new(),
247 payload,
248 }
249 }
250
251 pub fn with_headers(
252 endpoint_path: String,
253 headers: std::collections::HashMap<String, String>,
254 payload: Bytes,
255 ) -> Self {
256 Self {
257 endpoint_path,
258 headers,
259 payload,
260 }
261 }
262
263 pub fn encode(&self) -> Result<Bytes, std::io::Error> {
265 let endpoint_bytes = self.endpoint_path.as_bytes();
266 let endpoint_len = endpoint_bytes.len();
267
268 let headers_json = serde_json::to_vec(&self.headers).map_err(|e| {
270 std::io::Error::new(
271 std::io::ErrorKind::InvalidInput,
272 format!("Failed to encode headers: {}", e),
273 )
274 })?;
275 let headers_len = headers_json.len();
276
277 let parsed =
278 validate_tcp_request_encode_lengths(endpoint_len, headers_len, self.payload.len())?;
279
280 let mut buf = BytesMut::with_capacity(parsed.total_len);
282
283 buf.put_u16(endpoint_len as u16);
285
286 buf.put_slice(endpoint_bytes);
288
289 buf.put_u16(headers_len as u16);
291
292 buf.put_slice(&headers_json);
294
295 buf.put_u32(self.payload.len() as u32);
297
298 buf.put_slice(&self.payload);
300
301 Ok(buf.freeze())
303 }
304
305 pub fn into_frame(self) -> Result<TcpRequestFrame, std::io::Error> {
309 let endpoint_bytes = self.endpoint_path.as_bytes();
310 let endpoint_len = endpoint_bytes.len();
311
312 let headers_json = serde_json::to_vec(&self.headers).map_err(|e| {
313 std::io::Error::new(
314 std::io::ErrorKind::InvalidInput,
315 format!("Failed to encode headers: {}", e),
316 )
317 })?;
318 let headers_len = headers_json.len();
319 let payload_len = self.payload.len();
320
321 let parsed = validate_tcp_request_encode_lengths(endpoint_len, headers_len, payload_len)?;
322 let mut header = BytesMut::with_capacity(parsed.header_size);
323
324 header.put_u16(endpoint_len as u16);
325 header.put_slice(endpoint_bytes);
326 header.put_u16(headers_len as u16);
327 header.put_slice(&headers_json);
328 header.put_u32(payload_len as u32);
329
330 Ok(TcpRequestFrame {
331 header: header.freeze(),
332 payload: self.payload,
333 })
334 }
335
336 pub fn decode(bytes: &Bytes) -> Result<Self, std::io::Error> {
338 let parsed = parse_tcp_request_frame(bytes)?;
339
340 let endpoint_path =
342 String::from_utf8(bytes[parsed.endpoint_start()..parsed.endpoint_end()].to_vec())
343 .map_err(|e| {
344 std::io::Error::new(
345 std::io::ErrorKind::InvalidData,
346 format!("Invalid UTF-8 in endpoint path: {}", e),
347 )
348 })?;
349
350 let headers: std::collections::HashMap<String, String> = serde_json::from_slice(
352 &bytes[parsed.headers_start()..parsed.headers_end()],
353 )
354 .map_err(|e| {
355 std::io::Error::new(
356 std::io::ErrorKind::InvalidData,
357 format!("Invalid JSON in headers: {}", e),
358 )
359 })?;
360
361 let payload = bytes.slice(parsed.payload_start()..parsed.total_len);
363
364 Ok(Self {
365 endpoint_path,
366 headers,
367 payload,
368 })
369 }
370}
371
372#[derive(Debug, Clone, PartialEq, Eq)]
378pub struct TcpResponseMessage {
379 pub data: Bytes,
380}
381
382impl TcpResponseMessage {
383 pub fn new(data: Bytes) -> Self {
384 Self { data }
385 }
386
387 pub fn empty() -> Self {
388 Self { data: Bytes::new() }
389 }
390
391 pub fn encode(&self) -> Result<Bytes, std::io::Error> {
393 if self.data.len() > u32::MAX as usize {
394 return Err(std::io::Error::new(
395 std::io::ErrorKind::InvalidInput,
396 format!("Response too large: {} bytes", self.data.len()),
397 ));
398 }
399
400 let mut buf = BytesMut::with_capacity(4 + self.data.len());
402
403 buf.put_u32(self.data.len() as u32);
405
406 buf.put_slice(&self.data);
408
409 Ok(buf.freeze())
411 }
412
413 pub fn decode(bytes: &Bytes) -> Result<Self, std::io::Error> {
415 if bytes.len() < 4 {
416 return Err(std::io::Error::new(
417 std::io::ErrorKind::UnexpectedEof,
418 "Not enough bytes for response length",
419 ));
420 }
421
422 let len = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as usize;
424
425 if bytes.len() < 4 + len {
426 return Err(std::io::Error::new(
427 std::io::ErrorKind::UnexpectedEof,
428 format!(
429 "Not enough bytes for response: expected {}, got {}",
430 len,
431 bytes.len() - 4
432 ),
433 ));
434 }
435
436 let data = bytes.slice(4..4 + len);
438
439 Ok(Self { data })
440 }
441}
442
443#[derive(Clone, Default)]
446pub struct TcpResponseCodec {
447 max_message_size: Option<usize>,
448}
449
450impl TcpResponseCodec {
451 pub fn new(max_message_size: Option<usize>) -> Self {
452 Self { max_message_size }
453 }
454}
455
456impl Decoder for TcpResponseCodec {
457 type Item = TcpResponseMessage;
458 type Error = std::io::Error;
459
460 fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
461 if src.len() < 4 {
463 return Ok(None);
464 }
465
466 let data_len = u32::from_be_bytes([src[0], src[1], src[2], src[3]]) as usize;
468 let total_len = 4 + data_len;
469
470 if let Some(max_size) = self.max_message_size
472 && total_len > max_size
473 {
474 return Err(std::io::Error::new(
475 std::io::ErrorKind::InvalidData,
476 format!(
477 "Response too large: {} bytes (max: {} bytes)",
478 total_len, max_size
479 ),
480 ));
481 }
482
483 if src.len() < total_len {
485 return Ok(None);
486 }
487
488 src.advance(4);
490
491 let data = src.split_to(data_len).freeze();
493
494 Ok(Some(TcpResponseMessage { data }))
495 }
496}
497
498impl Encoder<TcpResponseMessage> for TcpResponseCodec {
499 type Error = std::io::Error;
500
501 fn encode(&mut self, item: TcpResponseMessage, dst: &mut BytesMut) -> Result<(), Self::Error> {
502 if item.data.len() > u32::MAX as usize {
503 return Err(std::io::Error::new(
504 std::io::ErrorKind::InvalidInput,
505 format!("Response too large: {} bytes", item.data.len()),
506 ));
507 }
508
509 let total_len = 4 + item.data.len();
510
511 if let Some(max_size) = self.max_message_size
513 && total_len > max_size
514 {
515 return Err(std::io::Error::new(
516 std::io::ErrorKind::InvalidInput,
517 format!(
518 "Response too large: {} bytes (max: {} bytes)",
519 total_len, max_size
520 ),
521 ));
522 }
523
524 dst.reserve(total_len);
526
527 dst.put_u32(item.data.len() as u32);
529
530 dst.put_slice(&item.data);
532
533 Ok(())
534 }
535}
536
537#[cfg(test)]
538mod tests {
539 use super::*;
540
541 #[test]
542 fn test_tcp_request_encode_decode() {
543 let msg = TcpRequestMessage::new(
544 "test.endpoint".to_string(),
545 Bytes::from(vec![1, 2, 3, 4, 5]),
546 );
547
548 let encoded = msg.encode().unwrap();
549 let decoded = TcpRequestMessage::decode(&encoded).unwrap();
550
551 assert_eq!(decoded, msg);
552 }
553
554 #[test]
555 fn test_tcp_request_empty_payload() {
556 let msg = TcpRequestMessage::new("test".to_string(), Bytes::new());
557
558 let encoded = msg.encode().unwrap();
559 let decoded = TcpRequestMessage::decode(&encoded).unwrap();
560
561 assert_eq!(decoded, msg);
562 }
563
564 #[test]
565 fn test_tcp_request_into_frame_matches_encode() {
566 let mut basic_headers = std::collections::HashMap::new();
567 basic_headers.insert("request-id".to_string(), "abc-123".to_string());
568
569 let mut multibyte_headers = std::collections::HashMap::new();
570 multibyte_headers.insert("trace".to_string(), "snowman-โ".to_string());
571 multibyte_headers.insert("emoji".to_string(), "rocket-๐".to_string());
572
573 let mut large_headers = std::collections::HashMap::new();
574 large_headers.insert("x-long".to_string(), "v".repeat(4096));
575
576 let cases = [
577 (
578 "test.endpoint".to_string(),
579 basic_headers,
580 Bytes::from_static(b"payload-body"),
581 ),
582 (
583 "empty.payload".to_string(),
584 std::collections::HashMap::new(),
585 Bytes::new(),
586 ),
587 (
588 "unicode.endpoint".to_string(),
589 multibyte_headers,
590 Bytes::from("ใใใซใกใฏ"),
591 ),
592 (
593 "large.payload".to_string(),
594 large_headers,
595 Bytes::from(vec![42u8; 64 * 1024]),
596 ),
597 ];
598
599 for (endpoint, headers, payload) in cases {
600 let msg = TcpRequestMessage::with_headers(endpoint, headers, payload.clone());
601 let encoded = msg.clone().encode().unwrap();
602 let frame = msg.into_frame().unwrap();
603
604 assert_eq!(frame.encoded_len(), encoded.len());
605 if !payload.is_empty() {
606 assert_eq!(frame.payload.as_ptr(), payload.as_ptr());
607 }
608
609 let mut combined = BytesMut::with_capacity(frame.encoded_len());
610 combined.put_slice(&frame.header);
611 combined.put_slice(&frame.payload);
612 assert_eq!(combined.freeze(), encoded);
613 }
614 }
615
616 #[test]
617 fn test_tcp_request_large_payload() {
618 let payload = Bytes::from(vec![42u8; 1024 * 1024]); let msg = TcpRequestMessage::new("large".to_string(), payload);
620
621 let encoded = msg.encode().unwrap();
622 let decoded = TcpRequestMessage::decode(&encoded).unwrap();
623
624 assert_eq!(decoded, msg);
625 }
626
627 #[test]
628 fn test_tcp_request_decode_truncated() {
629 let msg = TcpRequestMessage::new("test".to_string(), Bytes::from(vec![1, 2, 3, 4, 5]));
630 let encoded = msg.encode().unwrap();
631
632 let truncated = encoded.slice(..encoded.len() - 2);
634 let result = TcpRequestMessage::decode(&truncated);
635
636 assert!(result.is_err());
637 }
638
639 #[test]
640 fn test_tcp_request_decode_invalid_endpoint_utf8() {
641 let mut encoded = BytesMut::new();
642 encoded.put_u16(2);
643 encoded.put_slice(&[0xff, 0xff]);
644 encoded.put_u16(2);
645 encoded.put_slice(b"{}");
646 encoded.put_u32(0);
647
648 let result = TcpRequestMessage::decode(&encoded.freeze());
649
650 assert!(result.is_err());
651 let err = result.unwrap_err();
652 assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);
653 assert!(err.to_string().contains("Invalid UTF-8"));
654 }
655
656 #[test]
657 fn test_tcp_request_decode_invalid_headers_json() {
658 let mut encoded = BytesMut::new();
659 encoded.put_u16(4);
660 encoded.put_slice(b"test");
661 encoded.put_u16(1);
662 encoded.put_slice(b"{");
663 encoded.put_u32(0);
664
665 let result = TcpRequestMessage::decode(&encoded.freeze());
666
667 assert!(result.is_err());
668 let err = result.unwrap_err();
669 assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);
670 assert!(err.to_string().contains("Invalid JSON"));
671 }
672
673 #[test]
674 fn test_tcp_request_empty_endpoint_path() {
675 let msg = TcpRequestMessage::new(String::new(), Bytes::from_static(b"payload"));
676
677 let encoded = msg.encode().unwrap();
678 let decoded = TcpRequestMessage::decode(&encoded).unwrap();
679
680 assert_eq!(decoded, msg);
681 }
682
683 #[test]
684 fn test_tcp_response_encode_decode() {
685 let msg = TcpResponseMessage::new(Bytes::from(vec![1, 2, 3, 4, 5]));
686
687 let encoded = msg.encode().unwrap();
688 let decoded = TcpResponseMessage::decode(&encoded).unwrap();
689
690 assert_eq!(decoded, msg);
691 }
692
693 #[test]
694 fn test_tcp_response_empty() {
695 let msg = TcpResponseMessage::empty();
696
697 let encoded = msg.encode().unwrap();
698 let decoded = TcpResponseMessage::decode(&encoded).unwrap();
699
700 assert_eq!(decoded, msg);
701 assert_eq!(decoded.data.len(), 0);
702 }
703
704 #[test]
705 fn test_tcp_response_decode_truncated() {
706 let msg = TcpResponseMessage::new(Bytes::from(vec![1, 2, 3, 4, 5]));
707 let encoded = msg.encode().unwrap();
708
709 let truncated = encoded.slice(..3);
711 let result = TcpResponseMessage::decode(&truncated);
712
713 assert!(result.is_err());
714 }
715
716 #[test]
717 fn test_tcp_request_unicode_endpoint() {
718 let msg = TcpRequestMessage::new("ัะตัั.็ซฏ็น".to_string(), Bytes::from(vec![1, 2, 3]));
719
720 let encoded = msg.encode().unwrap();
721 let decoded = TcpRequestMessage::decode(&encoded).unwrap();
722
723 assert_eq!(decoded, msg);
724 }
725
726 #[test]
727 fn test_tcp_response_codec() {
728 use tokio_util::codec::{Decoder, Encoder};
729
730 let msg = TcpResponseMessage::new(Bytes::from(vec![1, 2, 3, 4, 5]));
731
732 let mut codec = TcpResponseCodec::new(None);
733 let mut buf = BytesMut::new();
734
735 codec.encode(msg.clone(), &mut buf).unwrap();
737
738 let decoded = codec.decode(&mut buf).unwrap().unwrap();
740 assert_eq!(decoded, msg);
741 }
742
743 #[test]
744 fn test_tcp_response_codec_partial() {
745 use tokio_util::codec::Decoder;
746
747 let msg = TcpResponseMessage::new(Bytes::from(vec![1, 2, 3, 4, 5]));
748
749 let encoded = msg.encode().unwrap();
750 let mut codec = TcpResponseCodec::new(None);
751
752 let mut buf = BytesMut::from(&encoded[..3]);
754 assert!(codec.decode(&mut buf).unwrap().is_none());
755
756 buf.extend_from_slice(&encoded[3..]);
758 let decoded = codec.decode(&mut buf).unwrap().unwrap();
759 assert_eq!(decoded, msg);
760 }
761
762 #[test]
763 fn test_tcp_response_codec_max_size() {
764 use tokio_util::codec::Encoder;
765
766 let msg = TcpResponseMessage::new(Bytes::from(vec![1, 2, 3, 4, 5]));
767
768 let mut codec = TcpResponseCodec::new(Some(5)); let mut buf = BytesMut::new();
770
771 let result = codec.encode(msg, &mut buf);
772 assert!(result.is_err());
773 }
774}