Skip to main content

sark_core/http/codec/encode/
wire.rs

1use o3::buffer::{Owned, Shared};
2
3use crate::http::Request;
4
5pub struct Wire;
6
7impl Wire {
8    pub fn dec_len(mut n: usize) -> usize {
9        if n == 0 {
10            return 1;
11        }
12        let mut digits = 0;
13        while n > 0 {
14            digits += 1;
15            n /= 10;
16        }
17        digits
18    }
19
20    pub fn write_dec(mut n: usize, buf: &mut [u8; 20]) -> usize {
21        if n == 0 {
22            buf[0] = b'0';
23            return 1;
24        }
25        let mut i = 20;
26        while n > 0 {
27            i -= 1;
28            buf[i] = b'0' + (n % 10) as u8;
29            n /= 10;
30        }
31        let len = 20 - i;
32        buf.copy_within(i..20, 0);
33        len
34    }
35
36    pub fn write_hex(n: usize, buf: &mut [u8; 16]) -> usize {
37        if n == 0 {
38            buf[0] = b'0';
39            return 1;
40        }
41        let mut i = 16;
42        let mut val = n;
43        while val > 0 {
44            i -= 1;
45            buf[i] = b"0123456789abcdef"[val & 0xf];
46            val >>= 4;
47        }
48        buf.copy_within(i..16, 0);
49        16 - i
50    }
51
52    pub fn chunk_prefix(size: usize) -> ([u8; 18], usize) {
53        let mut hex = [0u8; 16];
54        let hex_len = Self::write_hex(size, &mut hex);
55        let mut out = [0u8; 18];
56        out[..hex_len].copy_from_slice(&hex[..hex_len]);
57        out[hex_len] = b'\r';
58        out[hex_len + 1] = b'\n';
59        (out, hex_len + 2)
60    }
61
62    pub fn chunk_frame(body: Shared) -> Shared {
63        let (prefix, prefix_len) = Self::chunk_prefix(body.len());
64        let mut framed = Owned::with_capacity(prefix_len + body.len() + 2);
65        framed.extend_from_slice(&prefix[..prefix_len]);
66        framed.extend_from_slice(&body);
67        framed.extend_from_slice(b"\r\n");
68        framed.freeze()
69    }
70
71    pub fn request(req: &Request) -> Vec<u8> {
72        let mut buf = Vec::with_capacity(Self::estimate_request_capacity(req));
73        Self::write_request_head(&mut buf, req);
74
75        let body = req.body();
76        if !body.is_empty() && !req.headers().contains_key("content-length") {
77            let mut dec = [0u8; 20];
78            let dec_len = Self::write_dec(body.len(), &mut dec);
79            buf.extend_from_slice(b"Content-Length: ");
80            buf.extend_from_slice(&dec[..dec_len]);
81            buf.extend_from_slice(b"\r\n");
82        }
83
84        buf.extend_from_slice(b"\r\n");
85
86        if !body.is_empty() {
87            buf.extend_from_slice(body.as_ref());
88        }
89
90        buf
91    }
92
93    pub fn request_head(req: &Request) -> Vec<u8> {
94        let mut buf = Vec::with_capacity(
95            Self::estimate_request_capacity(req).saturating_sub(req.body().len()),
96        );
97        Self::write_request_head(&mut buf, req);
98        buf.extend_from_slice(b"\r\n");
99        buf
100    }
101
102    fn header_map_len(headers: &http::HeaderMap) -> usize {
103        headers
104            .iter()
105            .map(|(name, value)| name.as_str().len() + 2 + value.as_bytes().len() + 2)
106            .sum()
107    }
108
109    fn request_path(req: &Request) -> &str {
110        req.uri()
111            .path_and_query()
112            .map(|pq| pq.as_str())
113            .unwrap_or("/")
114    }
115
116    fn host_value(req: &Request) -> Option<&str> {
117        if req.headers().contains_key("host") {
118            return None;
119        }
120        let authority = req.uri().authority()?;
121        let scheme = req.uri().scheme_str().unwrap_or("http");
122        let default_port = if scheme == "https" { 443 } else { 80 };
123        if req.uri().port_u16() == Some(default_port) {
124            Some(authority.host())
125        } else {
126            Some(authority.as_str())
127        }
128    }
129
130    fn estimate_request_capacity(req: &Request) -> usize {
131        let mut cap = req.method().as_str().len()
132            + 1
133            + Self::request_path(req).len()
134            + b" HTTP/1.1\r\n".len();
135        cap += Self::header_map_len(req.headers());
136
137        if let Some(host) = Self::host_value(req) {
138            cap += b"Host: ".len() + host.len() + 2;
139        }
140
141        if !req.headers().contains_key("user-agent") {
142            cap += b"User-Agent: sark/0.1\r\n".len();
143        }
144        if !req.headers().contains_key("accept-encoding") {
145            cap += b"Accept-Encoding: gzip\r\n".len();
146        }
147
148        let body = req.body();
149        if !body.is_empty() && !req.headers().contains_key("content-length") {
150            cap += b"Content-Length: ".len() + Self::dec_len(body.len()) + 2;
151        }
152
153        cap + 2 + body.len()
154    }
155
156    fn write_request_head(buf: &mut Vec<u8>, req: &Request) {
157        buf.extend_from_slice(req.method().as_str().as_bytes());
158        buf.push(b' ');
159        buf.extend_from_slice(Self::request_path(req).as_bytes());
160        buf.extend_from_slice(b" HTTP/1.1\r\n");
161
162        if let Some(host) = Self::host_value(req) {
163            buf.extend_from_slice(b"Host: ");
164            buf.extend_from_slice(host.as_bytes());
165            buf.extend_from_slice(b"\r\n");
166        }
167
168        if !req.headers().contains_key("user-agent") {
169            buf.extend_from_slice(b"User-Agent: sark/0.1\r\n");
170        }
171
172        if !req.headers().contains_key("accept-encoding") {
173            buf.extend_from_slice(b"Accept-Encoding: gzip\r\n");
174        }
175
176        for (name, value) in req.headers().iter() {
177            buf.extend_from_slice(name.as_str().as_bytes());
178            buf.extend_from_slice(b": ");
179            buf.extend_from_slice(value.as_bytes());
180            buf.extend_from_slice(b"\r\n");
181        }
182    }
183}