Skip to main content

fkm_proxy/utils/
http.rs

1use anyhow::Result;
2use http::StatusCode;
3use tokio::io::{AsyncReadExt, AsyncWriteExt};
4
5pub async fn write_http_resp<T>(
6    stream: &mut T,
7    status: u16,
8    content: &str,
9    content_type: &str,
10) -> Result<()>
11where
12    T: AsyncReadExt + AsyncWriteExt + Unpin,
13{
14    let resp = construct_http_resp(status, content, content_type);
15    stream.write_all(resp.as_bytes()).await?;
16    Ok(())
17}
18
19pub fn construct_http_resp(status: u16, content: &str, content_type: &str) -> String {
20    let status_str = StatusCode::from_u16(status)
21        .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)
22        .canonical_reason()
23        .unwrap_or("Internal Server Error");
24
25    format!(
26        "HTTP/1.1 {status} {status_str}\r\n\
27        Content-Length: {content_len}\r\n\
28        Content-Type: {content_type}\r\n\
29        Connection: close\r\n\
30        \r\n\
31        {content}",
32        content_len = content.len(),
33    )
34}
35
36pub fn construct_raw_http_resp(status: u16, content: &[u8], content_type: &str) -> Vec<u8> {
37    let status_str = StatusCode::from_u16(status)
38        .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)
39        .canonical_reason()
40        .unwrap_or("Internal Server Error");
41
42    let response = format!(
43        "HTTP/1.1 {status} {status_str}\r\n\
44        Content-Length: {content_len}\r\n\
45        Content-Type: {content_type}\r\n\
46        Connection: close\r\n\
47        \r\n",
48        content_len = content.len(),
49    );
50
51    let mut result = response.into_bytes();
52    result.extend_from_slice(content);
53    result
54}
55
56pub fn construct_http_redirect(url: &str) -> String {
57    format!("HTTP/1.1 301 Moved Permanently\r\nLocation: {url}\r\nContent-Length: 0\r\n\r\n",)
58}