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 && let Some(host) = self.url.host_str() {
42 bytes.extend(HTTP_HOST.as_bytes());
43 bytes.extend(b": ");
44 bytes.extend(host.as_bytes());
45 if let Some(port) = self.url.port() {
48 bytes.extend(format!(":{port}").as_bytes());
49 }
50 bytes.extend(CRLF);
51 }
52
53 for (key, val) in &self.headers {
54 if key.eq_ignore_ascii_case(HTTP_CONTENT_LENGTH) {
55 continue;
56 }
57
58 bytes.extend(key.as_bytes());
59 bytes.extend(b": ");
60 bytes.extend(val.as_bytes());
61 bytes.extend(CRLF);
62 }
63
64 let body_len = format!("{}", self.body.len());
65 bytes.extend(HTTP_CONTENT_LENGTH.as_bytes());
66 bytes.extend(b": ");
67 bytes.extend(body_len.as_bytes());
68 bytes.extend(CRLF_CRLF);
69 bytes.extend(&self.body);
70
71 bytes
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use alloc::string::String;
78
79 use url::Url;
80
81 use crate::rfc9110::request::HttpRequest;
82
83 fn serialize(req: &HttpRequest) -> String {
84 String::from_utf8(req.to_http_11_vec()).unwrap()
85 }
86
87 #[test]
88 fn host_generated_from_url() {
89 let req = HttpRequest::get(Url::parse("https://example.com/x").unwrap());
90 assert!(serialize(&req).contains("host: example.com\r\n"));
91 }
92
93 #[test]
94 fn host_keeps_non_default_port() {
95 let req = HttpRequest::get(Url::parse("https://example.com:8843/").unwrap());
96 assert!(serialize(&req).contains("host: example.com:8843\r\n"));
97 }
98
99 #[test]
100 fn host_omits_default_port() {
101 let req = HttpRequest::get(Url::parse("https://example.com:443/").unwrap());
102 assert!(serialize(&req).contains("host: example.com\r\n"));
103 }
104
105 #[test]
106 fn host_not_duplicated_when_set_by_caller() {
107 let req = HttpRequest::get(Url::parse("https://example.com/").unwrap())
108 .header("Host", "override.example");
109 let message = serialize(&req);
110 assert!(message.contains("Host: override.example\r\n"));
111 assert!(!message.contains("host: example.com\r\n"));
112 }
113}