1use crate::body::Body;
2use crate::record::CommandRecord;
3use crate::response::parser_headers;
4use crate::{Client, Error, Response, COLON_SPACE, CR_LF, SPACE};
5use bytes::Bytes;
6use http::Request as HttpRequest;
7use http::{HeaderMap, HeaderName, HeaderValue, Method, Version};
8use std::fmt::{Debug, Formatter};
9use tokio::io::{AsyncBufReadExt, AsyncRead, AsyncReadExt, BufReader};
10
11#[derive(Debug, Default, Clone)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
15pub struct RawRequest {
16 unsafe_raw: bool,
17 #[cfg_attr(feature = "serde", serde(with = "crate::serde_schema::bytes_serde"))]
18 #[cfg_attr(feature = "schema", schemars(with = "Bytes"))]
19 raw: Bytes,
20}
21
22#[derive(Default, Clone)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
26pub struct Request {
27 #[cfg_attr(feature = "serde", serde(with = "http_serde::uri"))]
29 #[cfg_attr(
30 feature = "schema",
31 schemars(
32 with = "String",
33 title = "request URI",
34 description = "The target URI of the HTTP request including path and query parameters",
35 example = "https://example.com/api/v1/resource?id=123"
36 )
37 )]
38 pub uri: http::Uri,
39 #[cfg_attr(feature = "serde", serde(with = "http_serde::version"))]
41 #[cfg_attr(
42 feature = "schema",
43 schemars(
44 with = "String",
45 title = "HTTP version",
46 description = "The protocol version of HTTP used for this request",
47 example = "HTTP/1.1"
48 )
49 )]
50 pub version: Version,
51 #[cfg_attr(feature = "serde", serde(with = "http_serde::method"))]
53 #[cfg_attr(
54 feature = "schema",
55 schemars(
56 schema_with = "crate::serde_schema::http_method_schema",
57 title = "HTTP method",
58 description = "The HTTP method indicating the desired action for the resource",
59 example = &"GET",
60 )
61 )]
62 pub method: Method,
63 #[cfg_attr(feature = "serde", serde(with = "http_serde::header_map"))]
65 #[cfg_attr(
66 feature = "schema",
67 schemars(
68 with = "std::collections::HashMap<String,String>",
69 title = "HTTP headers",
70 description = "Key-value pairs of HTTP headers included in the request",
71 example = r#"&[("Content-Type", "application/json"), ("Authorization", "Bearer token")]"#
72 )
73 )]
74 pub headers: HeaderMap<HeaderValue>,
75 #[cfg_attr(
77 feature = "schema",
78 schemars(
79 title = "request body",
80 description = "Optional body content sent with the HTTP request",
81 example = r#"&"{\"key\":\"value\"}""#
82 )
83 )]
84 pub body: Option<Body>,
85 #[cfg_attr(
87 feature = "schema",
88 schemars(
89 title = "raw request",
90 description = "Optional raw representation of the HTTP request for special handling cases",
91 )
92 )]
93 pub raw_request: Option<RawRequest>,
94}
95
96impl Debug for Request {
97 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
98 if let Some(raw) = &self.raw_request {
99 f.debug_struct("RawRequest")
100 .field("uri", &self.uri)
101 .field("raw", &format_args!("{}", &raw.raw.escape_ascii()))
102 .field("unsafe_raw", &raw.unsafe_raw)
103 .finish()
104 } else {
105 f.debug_struct("Request")
106 .field("uri", &self.uri)
107 .field("version", &self.version)
108 .field("method", &self.method)
109 .field("headers", &self.headers)
110 .field("body", &self.body)
111 .finish()
112 }
113 }
114}
115impl<T> From<HttpRequest<T>> for Request
116where
117 T: Into<Body>,
118{
119 fn from(value: HttpRequest<T>) -> Self {
120 let (parts, body) = value.into_parts();
121 let body = body.into();
122 Self {
123 uri: parts.uri,
124 version: parts.version,
125 method: parts.method,
126 headers: parts.headers,
127 body: if body.is_empty() { None } else { Some(body) },
128 raw_request: None,
129 }
130 }
131}
132
133impl From<&Request> for Bytes {
134 fn from(value: &Request) -> Self {
135 if let Some(raw) = &value.raw_request {
136 return raw.raw.clone();
137 }
138 let mut http_requests = Vec::new();
139 http_requests.extend(value.method.as_str().as_bytes());
141 http_requests.extend(SPACE);
142 http_requests.extend(value.uri.path().as_bytes());
144 if let Some(q) = value.uri.query() {
145 http_requests.extend([63]);
146 http_requests.extend(q.as_bytes());
147 }
148 http_requests.extend(SPACE);
149 http_requests.extend(format!("{:?}", value.version).as_bytes());
151 http_requests.extend(CR_LF);
152 if value.headers.get(http::header::HOST).is_none() {
154 http_requests.extend(http::header::HOST.as_str().as_bytes());
155 http_requests.extend(COLON_SPACE);
156 http_requests.extend(if let Some(s) = value.uri.authority() {
157 s.as_str().as_bytes()
158 } else {
159 &[]
160 });
161 http_requests.extend(CR_LF);
162 }
163 let mut headers = value.headers.clone();
165 if let Some(b) = value.body() {
167 if !b.is_empty() {
168 headers
169 .entry(http::header::CONTENT_LENGTH)
170 .or_insert(HeaderValue::from(b.len()));
171 }
172 }
173 for (k, v) in headers.iter() {
174 http_requests.extend(k.as_str().as_bytes());
175 http_requests.extend(COLON_SPACE);
176 http_requests.extend(v.as_bytes());
177 http_requests.extend(CR_LF);
178 }
179 http_requests.extend(CR_LF);
180 if let Some(b) = value.body() {
182 if !b.is_empty() {
183 http_requests.extend(b.as_ref());
184 }
185 }
186 Bytes::from(http_requests)
187 }
188}
189
190impl From<Request> for Bytes {
191 fn from(value: Request) -> Self {
192 Bytes::from(&value)
193 }
194}
195
196impl Request {
197 pub async fn from_http_reader<R>(reader: &mut BufReader<R>) -> crate::Result<Self>
199 where
200 R: AsyncRead + Unpin,
201 {
202 let mut request_line = String::new();
203 let n = reader.read_line(&mut request_line).await?;
204 if n == 0 {
205 return Err(Error::invalid_request("Empty request".to_string()));
206 }
207 let parts: Vec<&str> = request_line.split_whitespace().collect();
208 if parts.len() < 3 {
209 return Err(Error::invalid_request("Invalid request line".to_string()));
210 }
211 let method = parts[0];
212 let uri = parts[1];
213 let version = Self::parse_http_version(parts[2])?;
214
215 let mut headers_buf = Vec::new();
217 loop {
218 let mut line = String::new();
219 reader.read_line(&mut line).await?;
220 if line == "\r\n" || line == "\n" {
221 break;
222 }
223 headers_buf.extend_from_slice(line.as_bytes());
224 }
225
226 let mut content_length: usize = 0;
227 let mut parsed_headers: Vec<(String, String)> = Vec::new();
228 for line in String::from_utf8_lossy(&headers_buf).lines() {
229 if let Some(idx) = line.find(':') {
230 let (name, value) = line.split_at(idx);
231 let value = value[1..].trim();
232 parsed_headers.push((name.trim().to_string(), value.to_string()));
233 if name.trim().eq_ignore_ascii_case("content-length") {
234 content_length = value.parse().unwrap_or(0);
235 }
236 }
237 }
238
239 let body = if content_length > 0 {
240 let mut body_buf = vec![0u8; content_length];
241 reader.read_exact(&mut body_buf).await?;
242 Bytes::from(body_buf)
243 } else {
244 Bytes::new()
245 };
246
247 Self::from_http_parts(method, uri, version, parsed_headers, body)
248 }
249
250 fn parse_http_version(version: &str) -> crate::Result<Version> {
251 match version {
252 "HTTP/0.9" => Ok(Version::HTTP_09),
253 "HTTP/1.0" => Ok(Version::HTTP_10),
254 "HTTP/1.1" => Ok(Version::HTTP_11),
255 "HTTP/2.0" | "HTTP/2" => Ok(Version::HTTP_2),
256 "HTTP/3.0" | "HTTP/3" => Ok(Version::HTTP_3),
257 _ => Err(Error::invalid_request(format!(
258 "Unsupported HTTP version: {}",
259 version
260 ))),
261 }
262 }
263
264 pub fn from_http_parts<I, K, V, B>(
266 method: &str,
267 uri: &str,
268 version: Version,
269 headers: I,
270 body: B,
271 ) -> crate::Result<Self>
272 where
273 I: IntoIterator<Item = (K, V)>,
274 K: AsRef<str>,
275 V: AsRef<str>,
276 B: Into<Body>,
277 {
278 let mut request_builder = http::Request::builder()
279 .method(method)
280 .uri(uri)
281 .version(version);
282
283 for (name, value) in headers {
284 request_builder = request_builder.header(name.as_ref(), value.as_ref());
285 }
286
287 let http_request = request_builder.body(body.into())?;
288 Ok(http_request.into())
289 }
290
291 pub fn builder() -> http::request::Builder {
308 http::request::Builder::new()
309 }
310
311 pub fn raw<U, R>(uri: U, raw: R, unsafe_raw: bool) -> Request
320 where
321 Bytes: From<R>,
322 http::Uri: From<U>,
323 {
324 let raw = RawRequest {
325 unsafe_raw,
326 raw: raw.into(),
327 };
328 Request {
329 uri: uri.into(),
330 raw_request: Some(raw),
331 ..Request::default()
332 }
333 }
334}
335
336impl Request {
337 #[inline]
352 pub fn method(&self) -> &Method {
353 &self.method
354 }
355 #[inline]
371 pub fn method_mut(&mut self) -> &mut Method {
372 &mut self.method
373 }
374 #[inline]
389 pub fn uri(&self) -> &http::Uri {
390 &self.uri
391 }
392 #[inline]
408 pub fn uri_mut(&mut self) -> &mut http::Uri {
409 &mut self.uri
410 }
411 #[inline]
430 pub fn headers(&self) -> &HeaderMap {
431 &self.headers
432 }
433 #[inline]
448 pub fn headers_mut(&mut self) -> &mut HeaderMap {
449 &mut self.headers
450 }
451 #[inline]
472 pub fn body(&self) -> Option<&Body> {
473 self.body.as_ref()
474 }
475 #[inline]
485 pub fn version(&self) -> Version {
486 self.version
487 }
488 #[inline]
499 pub fn version_mut(&mut self) -> &mut Version {
500 &mut self.version
501 }
502 #[inline]
512 pub fn raw_request(&self) -> &Option<RawRequest> {
513 &self.raw_request
514 }
515
516 #[inline]
517 pub(crate) fn raw_request_mut(&mut self) -> &mut Option<RawRequest> {
518 &mut self.raw_request
519 }
520 #[inline]
521 pub(crate) fn is_unsafe(&self) -> bool {
522 match &self.raw_request {
523 None => false,
524 Some(raw) => raw.unsafe_raw,
525 }
526 }
527 #[inline]
540 pub fn get_command(&self) -> String {
541 CommandRecord::from(self).command
542 }
543}
544
545#[must_use = "RequestBuilder does nothing until you 'send' it"]
550pub struct RequestBuilder {
551 client: Client,
552 builder: http::request::Builder,
553 body: Body,
554 raw: Option<RawRequest>,
555}
556
557impl Default for RequestBuilder {
558 fn default() -> Self {
559 RequestBuilder {
560 client: Default::default(),
561 builder: http::request::Builder::new(),
562 body: Default::default(),
563 raw: None,
564 }
565 }
566}
567
568impl RequestBuilder {
569 pub fn new(client: Client, builder: http::request::Builder) -> RequestBuilder {
571 RequestBuilder {
572 client,
573 builder,
574 body: Default::default(),
575 raw: None,
576 }
577 }
578 pub fn uri<U: Into<http::Uri>>(mut self, uri: U) -> RequestBuilder {
580 self.builder = self.builder.uri(uri);
581 self
582 }
583 pub fn header<K, V>(mut self, key: K, value: V) -> RequestBuilder
585 where
586 HeaderName: TryFrom<K>,
587 HeaderValue: TryFrom<V>,
588 <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
589 <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
590 {
591 self.builder = self.builder.header(key, value);
592 self
593 }
594 pub fn header_line<L: Into<String>>(mut self, lines: L) -> RequestBuilder {
596 for line in lines.into().lines() {
597 if let Ok((Some(key), Some(value))) = parser_headers(line.as_bytes()) {
598 self.builder = self.builder.header(key, value);
599 };
600 }
601 self
602 }
603 pub fn headers(mut self, headers: HeaderMap) -> RequestBuilder {
607 if let Some(header) = self.builder.headers_mut() {
608 for (key, value) in headers {
609 if let Some(key) = key {
610 header.insert(key, value);
611 }
612 }
613 }
614 self
615 }
616 pub fn body<T: Into<Body>>(mut self, body: T) -> RequestBuilder {
618 self.body = body.into();
619 self
620 }
621 pub fn raw<R: Into<Bytes>>(mut self, raw: R, unsafe_raw: bool) -> RequestBuilder {
623 self.raw = Some(RawRequest {
624 unsafe_raw,
625 raw: raw.into(),
626 });
627 self
628 }
629 pub fn build(self) -> crate::Result<Request> {
632 let mut r: Request = self.builder.body(self.body)?.into();
633 r.raw_request = self.raw;
634 Ok(r)
635 }
636 pub async fn send(self) -> crate::Result<Response> {
657 let mut req: Request = self.builder.body(self.body)?.into();
658 *req.raw_request_mut() = self.raw;
659 self.client.execute(req).await
660 }
661}