1use bytes::{BufMut, Bytes, BytesMut};
2use std::io;
3use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
4
5use crate::error::{PgWireError, Result};
6
7pub const MAX_MESSAGE_SIZE: usize = 1024 * 1024 * 1024;
13
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct BackendMessage {
16 pub tag: u8,
17 pub payload: Bytes, }
19
20impl BackendMessage {
21 #[inline]
23 pub fn is_error(&self) -> bool {
24 self.tag == b'E'
25 }
26
27 #[inline]
29 pub fn is_ready_for_query(&self) -> bool {
30 self.tag == b'Z'
31 }
32
33 #[inline]
35 pub fn is_copy_both_response(&self) -> bool {
36 self.tag == b'W'
37 }
38
39 #[inline]
41 pub fn is_copy_data(&self) -> bool {
42 self.tag == b'd'
43 }
44
45 #[inline]
47 pub fn is_auth_request(&self) -> bool {
48 self.tag == b'R'
49 }
50}
51
52pub async fn read_backend_message<R: AsyncRead + Unpin>(rd: &mut R) -> Result<BackendMessage> {
53 let mut reader = MessageReader::new();
54 reader.read(rd).await
55}
56
57pub struct MessageReader {
71 hdr: [u8; 5],
72 hdr_filled: usize,
73 payload: BytesMut,
74 payload_filled: usize,
75 payload_len: Option<usize>,
78 tag: u8,
79 max_payload: usize,
82 refused: Option<(usize, usize)>,
86}
87
88impl MessageReader {
89 pub fn new() -> Self {
90 Self::with_capacity(4096)
91 }
92
93 pub fn with_capacity(capacity: usize) -> Self {
94 Self {
95 hdr: [0u8; 5],
96 hdr_filled: 0,
97 payload: BytesMut::with_capacity(capacity),
98 payload_filled: 0,
99 payload_len: None,
100 tag: 0,
101 max_payload: MAX_MESSAGE_SIZE,
102 refused: None,
103 }
104 }
105
106 pub fn with_max_message_size(mut self, max: usize) -> Self {
119 self.max_payload = max.min(MAX_MESSAGE_SIZE);
120 self
121 }
122
123 pub async fn read<R: AsyncRead + Unpin>(&mut self, rd: &mut R) -> Result<BackendMessage> {
128 if let Some((payload_bytes, limit_bytes)) = self.refused {
133 return Err(PgWireError::MessageTooLarge {
134 payload_bytes,
135 limit_bytes,
136 });
137 }
138
139 while self.hdr_filled < 5 {
141 let n = rd.read(&mut self.hdr[self.hdr_filled..]).await?;
142 if n == 0 {
143 return Err(PgWireError::Io(std::sync::Arc::new(io::Error::new(
144 io::ErrorKind::UnexpectedEof,
145 "EOF while reading backend message header",
146 ))));
147 }
148 self.hdr_filled += n;
149 }
150
151 if self.payload_len.is_none() {
153 let len = i32::from_be_bytes([self.hdr[1], self.hdr[2], self.hdr[3], self.hdr[4]]);
154
155 if len < 4 {
156 self.hdr_filled = 0;
159 return Err(PgWireError::Protocol(format!(
160 "invalid backend message length: {len}"
161 )));
162 }
163
164 let payload_len = (len - 4) as usize;
165
166 if payload_len > self.max_payload {
167 self.hdr_filled = 0;
168 self.refused = Some((payload_len, self.max_payload));
169 return Err(PgWireError::MessageTooLarge {
170 payload_bytes: payload_len,
171 limit_bytes: self.max_payload,
172 });
173 }
174
175 self.tag = self.hdr[0];
176 self.payload.clear();
177 self.payload.resize(payload_len, 0);
178 self.payload_filled = 0;
179 self.payload_len = Some(payload_len);
180 }
181
182 let payload_len = self.payload_len.unwrap();
183
184 while self.payload_filled < payload_len {
186 let n = rd.read(&mut self.payload[self.payload_filled..]).await?;
187 if n == 0 {
188 return Err(PgWireError::Io(std::sync::Arc::new(io::Error::new(
189 io::ErrorKind::UnexpectedEof,
190 "EOF while reading backend message payload",
191 ))));
192 }
193 self.payload_filled += n;
194 }
195
196 let payload = self.payload.split().freeze();
198 let tag = self.tag;
199 self.hdr_filled = 0;
200 self.payload_len = None;
201 self.payload_filled = 0;
202
203 Ok(BackendMessage { tag, payload })
204 }
205}
206
207impl Default for MessageReader {
208 fn default() -> Self {
209 Self::new()
210 }
211}
212
213pub async fn read_backend_message_into<R: AsyncRead + Unpin>(
218 rd: &mut R,
219 buf: &mut BytesMut,
220) -> Result<BackendMessage> {
221 let mut hdr = [0u8; 5];
222 rd.read_exact(&mut hdr).await?;
223 let tag = hdr[0];
224 let len = i32::from_be_bytes([hdr[1], hdr[2], hdr[3], hdr[4]]);
225
226 if len < 4 {
227 return Err(PgWireError::Protocol(format!(
228 "invalid backend message length: {len}"
229 )));
230 }
231
232 let payload_len = (len - 4) as usize;
233
234 if payload_len > MAX_MESSAGE_SIZE {
235 return Err(PgWireError::MessageTooLarge {
236 payload_bytes: payload_len,
237 limit_bytes: MAX_MESSAGE_SIZE,
238 });
239 }
240
241 buf.clear();
242 buf.resize(payload_len, 0);
243 rd.read_exact(&mut buf[..]).await?;
244 Ok(BackendMessage {
245 tag,
246 payload: buf.split().freeze(),
247 })
248}
249
250pub async fn write_ssl_request<W: AsyncWrite + Unpin>(wr: &mut W) -> Result<()> {
251 let mut buf = [0u8; 8];
252 buf[0..4].copy_from_slice(&(8i32).to_be_bytes());
253 buf[4..8].copy_from_slice(&(80877103i32).to_be_bytes());
254 wr.write_all(&buf).await?;
255 wr.flush().await?;
256 Ok(())
257}
258
259pub async fn write_startup_message<W: AsyncWrite + Unpin>(
260 wr: &mut W,
261 protocol_version: i32,
262 params: &[(&str, &str)],
263) -> Result<()> {
264 let mut buf = BytesMut::with_capacity(256);
265 buf.put_i32(0); buf.put_i32(protocol_version);
267
268 for (k, v) in params {
269 buf.extend_from_slice(k.as_bytes());
270 buf.put_u8(0);
271 buf.extend_from_slice(v.as_bytes());
272 buf.put_u8(0);
273 }
274 buf.put_u8(0); let len = buf.len() as i32;
277 buf[0..4].copy_from_slice(&len.to_be_bytes());
278
279 wr.write_all(&buf).await?;
280 wr.flush().await?;
281 Ok(())
282}
283
284pub async fn write_query<W: AsyncWrite + Unpin>(wr: &mut W, sql: &str) -> Result<()> {
285 let mut buf = BytesMut::with_capacity(sql.len() + 64);
286 buf.put_u8(b'Q');
287 buf.put_i32(0);
288 buf.extend_from_slice(sql.as_bytes());
289 buf.put_u8(0);
290
291 let len = (buf.len() - 1) as i32;
292 buf[1..5].copy_from_slice(&len.to_be_bytes());
293
294 wr.write_all(&buf).await?;
295 wr.flush().await?;
296 Ok(())
297}
298
299pub async fn write_password_message<W: AsyncWrite + Unpin>(
300 wr: &mut W,
301 payload: &[u8],
302) -> Result<()> {
303 let mut buf = BytesMut::with_capacity(payload.len() + 16);
304 buf.put_u8(b'p');
305 buf.put_i32(0);
306 buf.extend_from_slice(payload);
307
308 let len = (buf.len() - 1) as i32;
309 buf[1..5].copy_from_slice(&len.to_be_bytes());
310
311 wr.write_all(&buf).await?;
312 wr.flush().await?;
313 Ok(())
314}
315
316pub async fn write_copy_data<W: AsyncWrite + Unpin>(wr: &mut W, payload: &[u8]) -> Result<()> {
317 let mut buf = BytesMut::with_capacity(payload.len() + 16);
318 buf.put_u8(b'd');
319 buf.put_i32(0);
320 buf.extend_from_slice(payload);
321
322 let len = (buf.len() - 1) as i32;
323 buf[1..5].copy_from_slice(&len.to_be_bytes());
324
325 wr.write_all(&buf).await?;
326 wr.flush().await?;
327 Ok(())
328}
329
330pub async fn write_copy_done<W: AsyncWrite + Unpin>(wr: &mut W) -> Result<()> {
331 let mut buf = BytesMut::with_capacity(5);
332 buf.put_u8(b'c'); buf.put_i32(4); wr.write_all(&buf).await?;
335 wr.flush().await?;
336 Ok(())
337}
338
339#[cfg(test)]
340mod tests {
341 use super::*;
342 use std::io::Cursor;
343 use tokio::io::AsyncWriteExt;
344
345 #[tokio::test]
346 async fn read_backend_message_parses_valid_message() {
347 let data = [b'Z', 0, 0, 0, 5, b'I'];
349 let mut cursor = Cursor::new(&data[..]);
350
351 let msg = read_backend_message(&mut cursor).await.unwrap();
352 assert_eq!(msg.tag, b'Z');
353 assert_eq!(&msg.payload[..], b"I");
354 assert!(msg.is_ready_for_query());
355 }
356
357 #[tokio::test]
358 async fn read_backend_message_handles_empty_payload() {
359 let data = [b'N', 0, 0, 0, 4];
361 let mut cursor = Cursor::new(&data[..]);
362
363 let msg = read_backend_message(&mut cursor).await.unwrap();
364 assert_eq!(msg.tag, b'N');
365 assert!(msg.payload.is_empty());
366 }
367
368 #[tokio::test]
369 async fn read_backend_message_rejects_invalid_length() {
370 let data = [b'Z', 0, 0, 0, 3];
372 let mut cursor = Cursor::new(&data[..]);
373
374 let err = read_backend_message(&mut cursor).await.unwrap_err();
375 assert!(err.to_string().contains("invalid backend message length"));
376 }
377
378 #[tokio::test]
379 async fn message_reader_reads_complete_message() {
380 let data = [b'Z', 0, 0, 0, 5, b'I'];
382 let mut cursor = Cursor::new(&data[..]);
383
384 let mut reader = MessageReader::new();
385 let msg = reader.read(&mut cursor).await.unwrap();
386 assert_eq!(msg.tag, b'Z');
387 assert_eq!(&msg.payload[..], b"I");
388 }
389
390 #[tokio::test]
391 async fn message_reader_reads_back_to_back_messages() {
392 let data = [b'Z', 0, 0, 0, 5, b'I', b'N', 0, 0, 0, 4];
394 let mut cursor = Cursor::new(&data[..]);
395
396 let mut reader = MessageReader::new();
397
398 let m1 = reader.read(&mut cursor).await.unwrap();
399 assert_eq!(m1.tag, b'Z');
400 assert_eq!(&m1.payload[..], b"I");
401
402 let m2 = reader.read(&mut cursor).await.unwrap();
403 assert_eq!(m2.tag, b'N');
404 assert!(m2.payload.is_empty());
405 }
406
407 #[tokio::test]
416 async fn message_reader_resumes_after_cancellation_mid_header() {
417 let (mut writer, mut rd) = tokio::io::duplex(64);
418 let mut reader = MessageReader::new();
419
420 let header = [b'd', 0, 0, 0, 8];
422 let payload = b"abcd";
423
424 writer.write_all(&header[..3]).await.unwrap();
426
427 let timed_out =
428 tokio::time::timeout(std::time::Duration::from_millis(20), reader.read(&mut rd)).await;
429 assert!(
430 timed_out.is_err(),
431 "read must time out while waiting for remaining header bytes"
432 );
433
434 writer.write_all(&header[3..]).await.unwrap();
437 writer.write_all(payload).await.unwrap();
438
439 let msg = reader.read(&mut rd).await.unwrap();
440 assert_eq!(msg.tag, b'd');
441 assert_eq!(&msg.payload[..], payload);
442 }
443
444 #[tokio::test]
446 async fn message_reader_resumes_after_cancellation_mid_payload() {
447 let (mut writer, mut rd) = tokio::io::duplex(64);
448 let mut reader = MessageReader::new();
449
450 let payload: [u8; 16] = std::array::from_fn(|i| i as u8);
452 let len = (4 + payload.len()) as i32;
453 let header = [
454 b'd',
455 (len >> 24) as u8,
456 (len >> 16) as u8,
457 (len >> 8) as u8,
458 len as u8,
459 ];
460
461 writer.write_all(&header).await.unwrap();
463 writer.write_all(&payload[..5]).await.unwrap();
464
465 let timed_out =
466 tokio::time::timeout(std::time::Duration::from_millis(20), reader.read(&mut rd)).await;
467 assert!(
468 timed_out.is_err(),
469 "read must time out while waiting for remaining payload bytes"
470 );
471
472 writer.write_all(&payload[5..]).await.unwrap();
474
475 let msg = reader.read(&mut rd).await.unwrap();
476 assert_eq!(msg.tag, b'd');
477 assert_eq!(&msg.payload[..], &payload[..]);
478 }
479
480 #[tokio::test]
481 async fn message_reader_rejects_invalid_length() {
482 let data = [b'Z', 0, 0, 0, 3];
483 let mut cursor = Cursor::new(&data[..]);
484
485 let mut reader = MessageReader::new();
486 let err = reader.read(&mut cursor).await.unwrap_err();
487 assert!(err.to_string().contains("invalid backend message length"));
488 }
489
490 #[tokio::test]
491 async fn message_reader_rejects_a_message_over_its_configured_limit() {
492 let data = [b'd', 0, 0, 0, 14];
494 let mut cursor = Cursor::new(&data[..]);
495
496 let mut reader = MessageReader::new().with_max_message_size(8);
497 let err = reader.read(&mut cursor).await.unwrap_err();
498 assert!(matches!(
499 err,
500 PgWireError::MessageTooLarge {
501 payload_bytes: 10,
502 limit_bytes: 8
503 }
504 ));
505 assert!(!err.is_transient());
506 }
507
508 #[tokio::test]
509 async fn message_reader_is_poisoned_after_refusing_an_oversized_message() {
510 let mut data = vec![b'd', 0, 0, 0, 14];
514 data.extend_from_slice(b"0123456789");
515 data.extend_from_slice(&[b'k', 0, 0, 0, 7]);
516 data.extend_from_slice(b"abc");
517 let mut cursor = Cursor::new(&data[..]);
518
519 let mut reader = MessageReader::new().with_max_message_size(8);
520 assert!(reader.read(&mut cursor).await.is_err());
521
522 for _ in 0..3 {
523 let err = reader.read(&mut cursor).await.unwrap_err();
524 assert!(matches!(
525 err,
526 PgWireError::MessageTooLarge {
527 payload_bytes: 10,
528 limit_bytes: 8
529 }
530 ));
531 }
532 }
533
534 #[tokio::test]
535 async fn message_reader_does_not_consume_a_refused_payload() {
536 let bogus = i32::MAX;
539 let mut data = vec![b'd'];
540 data.extend_from_slice(&bogus.to_be_bytes());
541 data.extend_from_slice(b"payload bytes that must stay on the wire");
542 let mut cursor = Cursor::new(&data[..]);
543
544 let mut reader = MessageReader::new().with_max_message_size(8);
545 assert!(reader.read(&mut cursor).await.is_err());
546 assert_eq!(cursor.position(), 5);
547 }
548
549 #[tokio::test]
550 async fn message_reader_reaches_the_oversized_verdict_across_a_cancelled_header() {
551 use tokio::io::AsyncWriteExt;
552
553 let len = 4 + 10_000i32;
555 let hdr = {
556 let mut v = vec![b'd'];
557 v.extend_from_slice(&len.to_be_bytes());
558 v
559 };
560
561 let (mut client, mut server) = tokio::io::duplex(64);
562 let mut reader = MessageReader::new().with_max_message_size(8);
563
564 server.write_all(&hdr[..2]).await.unwrap();
567 assert!(
568 tokio::time::timeout(
569 std::time::Duration::from_millis(50),
570 reader.read(&mut client)
571 )
572 .await
573 .is_err(),
574 "expected the read to be waiting for the rest of the header"
575 );
576
577 server.write_all(&hdr[2..]).await.unwrap();
580 let err = tokio::time::timeout(std::time::Duration::from_secs(5), reader.read(&mut client))
581 .await
582 .expect("reader lost the partial header and is still waiting")
583 .unwrap_err();
584
585 assert!(matches!(
586 err,
587 PgWireError::MessageTooLarge {
588 payload_bytes: 10_000,
589 limit_bytes: 8
590 }
591 ));
592
593 server.write_all(&[b'x'; 32]).await.unwrap();
596 let err = reader.read(&mut client).await.unwrap_err();
597 assert!(matches!(
598 err,
599 PgWireError::MessageTooLarge {
600 payload_bytes: 10_000,
601 limit_bytes: 8
602 }
603 ));
604 }
605
606 #[tokio::test]
607 async fn message_reader_accepts_a_message_at_its_configured_limit() {
608 let mut data = vec![b'd', 0, 0, 0, 12];
609 data.extend_from_slice(b"12345678");
610 let mut cursor = Cursor::new(&data[..]);
611
612 let mut reader = MessageReader::new().with_max_message_size(8);
613 let msg = reader.read(&mut cursor).await.unwrap();
614 assert_eq!(&msg.payload[..], b"12345678");
615 }
616
617 #[test]
618 fn message_reader_limit_cannot_be_raised_above_the_protocol_cap() {
619 let reader = MessageReader::new().with_max_message_size(usize::MAX);
620 assert_eq!(reader.max_payload, MAX_MESSAGE_SIZE);
621 }
622
623 #[tokio::test]
624 async fn read_backend_message_rejects_oversized_message() {
625 let huge_len = (MAX_MESSAGE_SIZE as i32) + 5;
627 let data = [
628 b'Z',
629 (huge_len >> 24) as u8,
630 (huge_len >> 16) as u8,
631 (huge_len >> 8) as u8,
632 huge_len as u8,
633 ];
634 let mut cursor = Cursor::new(&data[..]);
635
636 let err = read_backend_message(&mut cursor).await.unwrap_err();
637 assert!(err.to_string().contains("too large"));
638 }
639
640 #[tokio::test]
641 async fn write_ssl_request_produces_valid_bytes() {
642 let mut buf = Vec::new();
643 write_ssl_request(&mut buf).await.unwrap();
644
645 assert_eq!(buf.len(), 8);
646 assert_eq!(&buf[0..4], &8i32.to_be_bytes());
648 assert_eq!(&buf[4..8], &80877103i32.to_be_bytes());
650 }
651
652 #[tokio::test]
653 async fn write_startup_message_includes_params() {
654 let mut buf = Vec::new();
655 let params = [("user", "postgres"), ("database", "test")];
656 write_startup_message(&mut buf, 196608, ¶ms)
657 .await
658 .unwrap();
659
660 let s = String::from_utf8_lossy(&buf);
662 assert!(s.contains("user"));
663 assert!(s.contains("postgres"));
664 assert!(s.contains("database"));
665 assert!(s.contains("test"));
666
667 let len = i32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]) as usize;
669 assert_eq!(len, buf.len());
670 }
671
672 #[tokio::test]
673 async fn write_query_produces_valid_message() {
674 let mut buf = Vec::new();
675 write_query(&mut buf, "SELECT 1").await.unwrap();
676
677 assert_eq!(buf[0], b'Q');
679
680 let len = i32::from_be_bytes([buf[1], buf[2], buf[3], buf[4]]) as usize;
682 assert_eq!(len, buf.len() - 1);
683
684 assert!(buf[5..].starts_with(b"SELECT 1"));
686
687 assert_eq!(buf[buf.len() - 1], 0);
689 }
690
691 #[tokio::test]
692 async fn write_password_message_produces_valid_message() {
693 let mut buf = Vec::new();
694 write_password_message(&mut buf, b"secret").await.unwrap();
695
696 assert_eq!(buf[0], b'p');
697 let len = i32::from_be_bytes([buf[1], buf[2], buf[3], buf[4]]) as usize;
698 assert_eq!(len, buf.len() - 1);
699 assert_eq!(&buf[5..], b"secret");
700 }
701
702 #[tokio::test]
703 async fn write_copy_data_produces_valid_message() {
704 let mut buf = Vec::new();
705 write_copy_data(&mut buf, b"payload").await.unwrap();
706
707 assert_eq!(buf[0], b'd');
708 let len = i32::from_be_bytes([buf[1], buf[2], buf[3], buf[4]]) as usize;
709 assert_eq!(len, buf.len() - 1);
710 assert_eq!(&buf[5..], b"payload");
711 }
712
713 #[tokio::test]
714 async fn write_copy_done_produces_valid_message() {
715 let mut buf = Vec::new();
716 write_copy_done(&mut buf).await.unwrap();
717
718 assert_eq!(buf.len(), 5);
719 assert_eq!(buf[0], b'c');
720 assert_eq!(&buf[1..5], &4i32.to_be_bytes());
722 }
723
724 #[test]
725 fn backend_message_helper_methods() {
726 let error = BackendMessage {
727 tag: b'E',
728 payload: Bytes::new(),
729 };
730 assert!(error.is_error());
731 assert!(!error.is_ready_for_query());
732
733 let ready = BackendMessage {
734 tag: b'Z',
735 payload: Bytes::from_static(b"I"),
736 };
737 assert!(ready.is_ready_for_query());
738 assert!(!ready.is_error());
739
740 let copy_both = BackendMessage {
741 tag: b'W',
742 payload: Bytes::new(),
743 };
744 assert!(copy_both.is_copy_both_response());
745
746 let copy_data = BackendMessage {
747 tag: b'd',
748 payload: Bytes::new(),
749 };
750 assert!(copy_data.is_copy_data());
751
752 let auth = BackendMessage {
753 tag: b'R',
754 payload: Bytes::new(),
755 };
756 assert!(auth.is_auth_request());
757 }
758}