1use std::net::{TcpStream, Shutdown, SocketAddr};
2use std::io::BufReader;
3use std::io::prelude::*;
4
5pub fn write_bytes_to_tcp_stream_no_error(tcp_stream: &mut TcpStream, bytes: &[u8]) -> bool {
6 let bytes_total = bytes.len();
7 let mut bytes_left = bytes_total;
8 while bytes_left > 0 {
9 let buf = &bytes[(bytes_total - bytes_left)..bytes_total];
10 if let Ok(bytes_written) = tcp_stream.write(buf) {
11 if bytes_written == 0 {
12 return true
13 }
14 bytes_left -= bytes_written;
15 }
16 else {
17 return true
18 }
19 }
20 false
21}
22
23pub fn http_error_out(mut tcp_stream: TcpStream, code: usize) {
24 write_bytes_to_tcp_stream_no_error(&mut tcp_stream, format!("HTTP/1.1 {}\r\n\r\n", code).as_bytes());
25 let _ = tcp_stream.shutdown(Shutdown::Both);
26}
27
28
29pub fn split_header_line<'a>(inp: &'a str, what: &str) -> Option<&'a str> {
30 let mut what_lc = what.to_string();
31 what_lc.make_ascii_lowercase();
32 let mut inp_lc = inp.to_string();
33 inp_lc.make_ascii_lowercase();
34 if inp_lc.starts_with(&what_lc) {
35 return Some(&inp[what.len()..(inp.len() - 2)])
36 }
37 None
38}
39
40pub fn parse_url_path(url: &str) -> Option<(String, Option<String>)> {
41
42 let end_of_name = url.find(' ');
44 end_of_name ?;
45 let end_of_name = end_of_name.unwrap();
46 let mut search = None;
47 let end_of_name = if let Some(q) = url.find('?') {
48 search = Some(url[q..].to_string());
49 end_of_name.min(q)
50 }else {end_of_name};
51
52 let mut url = url[0..end_of_name].to_string();
53
54 if url.ends_with('/') {
55 url.push_str("index.html");
56 }
57
58 Some((url, search))
59}
60
61#[derive(Debug)]
62pub struct HttpServerHeaders {
63 pub addr: SocketAddr,
64 pub lines: Vec<String>,
65 pub verb: String,
66 pub path: String,
67 pub path_no_slash: String,
68 pub search: Option<String>,
69 pub content_length: Option<u64>,
70 pub accept_encoding: Option<String>,
71 pub sec_websocket_key: Option<String>
72}
73
74impl HttpServerHeaders {
75 pub fn from_tcp_stream(tcp_stream: &mut TcpStream) -> Option<HttpServerHeaders> {
76 let addr = tcp_stream.peer_addr().unwrap();
77 let mut reader = BufReader::new(tcp_stream);
78
79 let mut lines = Vec::new();
80 let mut content_length = None;
81 let mut accept_encoding = None;
82 let mut sec_websocket_key = None;
83 let mut line = String::new();
84
85 while reader.read_line(&mut line).is_ok() { if line == "\r\n" { break;
88 }
89 if let Some(v) = split_header_line(&line, "Content-Length: ") {
90 content_length = Some(if let Ok(v) = v.parse() {v} else {
91 return None
92 });
93 }
94 if let Some(v) = split_header_line(&line, "Accept-Encoding: ") {
95 accept_encoding = Some(v.to_string());
96 }
97 if let Some(v) = split_header_line(&line, "sec-websocket-key: ") {
98 sec_websocket_key = Some(v.to_string());
99 }
100 if line.len() > 4096 || lines.len() > 4096 { return None
102 }
103 lines.push(line.clone());
104 line.clear();
105 }
106 if lines.len() <2 {
107 return None;
108 }
109 let verb;
110 let path;
111 if let Some(v) = split_header_line(&lines[0], "GET ") {
112 verb = "GET";
113 path = parse_url_path(v)
114 }
115 else if let Some(v) = split_header_line(&lines[0], "POST ") {
116 verb = "POST";
117 path = parse_url_path(v)
118 }
119 else if let Some(v) = split_header_line(&lines[0], "PUT ") {
120 verb = "PUT";
121 path = parse_url_path(v)
122 }
123 else if let Some(v) = split_header_line(&lines[0], "DELETE ") {
124 verb = "DELETE";
125 path = parse_url_path(v)
126 }
127 else {
128 return None
129 }
130 path.as_ref() ?;
131 let path = path.unwrap();
132
133 Some(HttpServerHeaders {
134 addr,
135 verb: verb.to_string(),
136 path_no_slash: path.0[1..].to_string(),
137 path: path.0,
138 search: path.1,
139 lines,
140 content_length,
141 accept_encoding,
142 sec_websocket_key
143 })
144 }
145}