io_http/rfc9112/
request.rs1use alloc::{format, vec::Vec};
6
7use crate::{
8 rfc9110::{
9 chars::{CRLF, CRLF_CRLF, SP},
10 headers::{HTTP_CONTENT_LENGTH, HTTP_HOST},
11 request::HttpRequest,
12 },
13 rfc9112::version::HTTP_11,
14};
15
16impl HttpRequest {
17 pub fn to_http_11_vec(&self) -> Vec<u8> {
22 let mut bytes = Vec::new();
23
24 bytes.extend(self.method.as_bytes());
25 bytes.push(SP);
26 bytes.extend(self.url.path().as_bytes());
27
28 if let Some(q) = self.url.query() {
29 bytes.extend(b"?");
30 bytes.extend(q.as_bytes());
31 }
32
33 bytes.push(SP);
34 bytes.extend(HTTP_11.as_bytes());
35 bytes.extend(CRLF);
36
37 let has_host = self
38 .headers
39 .iter()
40 .any(|(k, _)| k.eq_ignore_ascii_case(HTTP_HOST));
41 if !has_host {
42 if let Some(host) = self.url.host_str() {
43 bytes.extend(HTTP_HOST.as_bytes());
44 bytes.extend(b": ");
45 bytes.extend(host.as_bytes());
46 if let Some(port) = self.url.port() {
49 bytes.extend(format!(":{port}").as_bytes());
50 }
51 bytes.extend(CRLF);
52 }
53 }
54
55 for (key, val) in &self.headers {
56 if key.eq_ignore_ascii_case(HTTP_CONTENT_LENGTH) {
57 continue;
58 }
59
60 bytes.extend(key.as_bytes());
61 bytes.extend(b": ");
62 bytes.extend(val.as_bytes());
63 bytes.extend(CRLF);
64 }
65
66 let body_len = format!("{}", self.body.len());
67 bytes.extend(HTTP_CONTENT_LENGTH.as_bytes());
68 bytes.extend(b": ");
69 bytes.extend(body_len.as_bytes());
70 bytes.extend(CRLF_CRLF);
71 bytes.extend(&self.body);
72
73 bytes
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use alloc::string::String;
80
81 use url::Url;
82
83 use crate::rfc9110::request::HttpRequest;
84
85 fn serialize(req: &HttpRequest) -> String {
86 String::from_utf8(req.to_http_11_vec()).unwrap()
87 }
88
89 #[test]
90 fn host_generated_from_url() {
91 let req = HttpRequest::get(Url::parse("https://example.com/x").unwrap());
92 assert!(serialize(&req).contains("host: example.com\r\n"));
93 }
94
95 #[test]
96 fn host_keeps_non_default_port() {
97 let req = HttpRequest::get(Url::parse("https://example.com:8843/").unwrap());
98 assert!(serialize(&req).contains("host: example.com:8843\r\n"));
99 }
100
101 #[test]
102 fn host_omits_default_port() {
103 let req = HttpRequest::get(Url::parse("https://example.com:443/").unwrap());
104 assert!(serialize(&req).contains("host: example.com\r\n"));
105 }
106
107 #[test]
108 fn host_not_duplicated_when_set_by_caller() {
109 let req = HttpRequest::get(Url::parse("https://example.com/").unwrap())
110 .header("Host", "override.example");
111 let message = serialize(&req);
112 assert!(message.contains("Host: override.example\r\n"));
113 assert!(!message.contains("host: example.com\r\n"));
114 }
115}