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}