1use std::fmt;
2
3use http::{HeaderMap, Method};
4use http_body_util::BodyExt;
5use serde::de::DeserializeOwned;
6use url::Url;
7
8pub const BODY_PRINT_LIMIT: usize = 10_000;
9
10#[derive(Debug, Copy, Clone)]
13pub enum BodyPrintLimit {
14 Limited(usize),
16 Unlimited,
18}
19
20#[derive(Debug, Clone)]
39pub struct Request {
40 pub url: Url,
41 pub method: Method,
42 pub headers: HeaderMap,
43 pub body: Vec<u8>,
44}
45
46impl Request {
47 pub fn body_json<T: DeserializeOwned>(&self) -> Result<T, serde_json::Error> {
48 serde_json::from_slice(&self.body)
49 }
50
51 pub(crate) async fn from_hyper(request: hyper::Request<hyper::body::Incoming>) -> Request {
52 let (parts, body) = request.into_parts();
53 let url = match parts.uri.authority() {
54 Some(_) => parts.uri.to_string(),
55 None => format!("http://localhost{}", parts.uri),
56 }
57 .parse()
58 .unwrap();
59
60 let body = body
61 .collect()
62 .await
63 .expect("Failed to read request body.")
64 .to_bytes();
65
66 Self {
67 url,
68 method: parts.method,
69 headers: parts.headers,
70 body: body.to_vec(),
71 }
72 }
73
74 pub(crate) fn print_with_limit(
75 &self,
76 mut buffer: impl fmt::Write,
77 body_print_limit: BodyPrintLimit,
78 ) -> fmt::Result {
79 writeln!(buffer, "{} {}", self.method, self.url)?;
80 for name in self.headers.keys() {
81 let values = self
82 .headers
83 .get_all(name)
84 .iter()
85 .map(|value| String::from_utf8_lossy(value.as_bytes()))
86 .collect::<Vec<_>>();
87 let values = values.join(",");
88 writeln!(buffer, "{}: {}", name, values)?;
89 }
90
91 match body_print_limit {
92 BodyPrintLimit::Limited(limit) if self.body.len() > limit => {
93 let mut written = false;
94 for end_byte in limit..(limit + 4).max(self.body.len()) {
95 if let Ok(truncated) = std::str::from_utf8(&self.body[..end_byte]) {
96 written = true;
97 writeln!(buffer, "{}", truncated)?;
98 if end_byte < self.body.len() {
99 writeln!(
100 buffer,
101 "We truncated the body because it was too large: {} bytes (limit: {} bytes)",
102 self.body.len(),
103 limit
104 )?;
105 writeln!(
106 buffer,
107 "Increase this limit by setting `WIREMOCK_BODY_PRINT_LIMIT`, or calling `MockServerBuilder::body_print_limit` when building your MockServer instance"
108 )?;
109 }
110 break;
111 }
112 }
113 if !written {
114 writeln!(
115 buffer,
116 "Body is likely binary (invalid utf-8) size is {} bytes",
117 self.body.len()
118 )
119 } else {
120 Ok(())
121 }
122 }
123 _ => {
124 if let Ok(body) = std::str::from_utf8(&self.body) {
125 writeln!(buffer, "{}", body)
126 } else {
127 writeln!(
128 buffer,
129 "Body is likely binary (invalid utf-8) size is {} bytes",
130 self.body.len()
131 )
132 }
133 }
134 }
135 }
136}