1use std::io::{copy, Read, Write};
20use std::net::TcpStream;
21use std::str;
22use std::str::from_utf8;
23use crate::codex::Codex;
24
25use crate::headers::{DISALLOWED_TRAILERS, Headers};
26use crate::http_message::Body::{BodyStream, BodyString};
27use crate::http_message::CompressionAlgorithm::{BROTLI, DEFLATE, GZIP, NONE};
28use crate::http_message::Method::{CONNECT, DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT, TRACE};
29use crate::http_message::Status::{BadRequest, Forbidden, InternalServerError, LengthRequired, MovedPermanently, NotFound, OK, Unknown};
30use crate::uri::Uri;
31
32pub enum HttpMessage<'a> {
33 Request(Request<'a>),
34 Response(Response<'a>),
35}
36
37impl<'a> HttpMessage<'a> {
38 pub fn is_req(&self) -> bool {
39 match self {
40 HttpMessage::Request(_) => true,
41 HttpMessage::Response(_) => false
42 }
43 }
44
45 pub fn is_res(&self) -> bool {
46 match self {
47 HttpMessage::Request(_) => false,
48 HttpMessage::Response(_) => true
49 }
50 }
51
52 pub fn to_req(self) -> Request<'a> {
53 match self {
54 HttpMessage::Request(req) => req,
55 _ => panic!("Not a request!")
56 }
57 }
58 pub fn to_res(self) -> Response<'a> {
59 match self {
60 HttpMessage::Response(res) => res,
61 _ => panic!("Not a request!")
62 }
63 }
64}
65
66#[allow(unused_assignments)]
67pub fn read_message_from_wire<'a>(
68 mut stream: TcpStream,
69 mut reader: &'a mut [u8],
70 mut start_line_writer: &'a mut Vec<u8>,
71 mut headers_writer: &'a mut Vec<u8>,
72 chunks_writer: &'a mut Vec<u8>,
73 compress_writer: &'a mut Vec<u8>,
74 trailers_writer: &'a mut Vec<u8>,
75) -> Result<HttpMessage<'a>, MessageError> {
76 let (mut read_bytes_from_stream, mut up_to_in_reader, mut result) =
77 read(&mut stream, &mut reader, &mut start_line_writer, 0, 0, None,
78 |reader, writer, _| { start_line_(reader, writer) },
79 );
80 let start_line = str::from_utf8(start_line_writer).unwrap().split(" ").collect::<Vec<&str>>();
81 let (part1, part2, part3) = (start_line[0], start_line[1], start_line[2]);
82 let is_response = part1.starts_with("HTTP");
83 let is_request = !is_response;
84 let method_can_have_body = vec!("POST", "PUT", "PATCH", "DELETE").contains(&part1);
85
86 (read_bytes_from_stream, up_to_in_reader, result) =
87 read(&mut stream, &mut reader, &mut headers_writer, read_bytes_from_stream, up_to_in_reader, None,
88 |reader, writer, _| { headers_(reader, writer) },
89 );
90
91 if result.is_err() {
92 return Err(result.err());
93 }
94 let header_string = from_utf8(headers_writer.as_slice()).unwrap();
95 let mut headers = Headers::parse_from(header_string);
96
97 if let Err(e) = check_valid_content_length_or_transfer_encoding(&headers, is_response, method_can_have_body) {
98 return Err(e);
99 }
100 let transfer_encoding = headers.get("Transfer-Encoding");
101 if headers.has("Content-Length") && transfer_encoding.is_some() {
102 headers = headers.remove("Content-Length");
103 }
104 let is_version_1_0 = part3 == "HTTP/1.0";
105
106 let request_options = RequestOptions::from(&headers);
107 let compression = request_options.read_compression();
108 let content_length = headers.content_length_header();
109
110 let result = if let Some(_encoding) = transfer_encoding {
111 chunked_body_and_trailers(reader, stream, up_to_in_reader, read_bytes_from_stream, chunks_writer, compress_writer, trailers_writer, &compression)
112 } else {
113 simple_body(reader, stream, up_to_in_reader, read_bytes_from_stream, is_request, method_can_have_body, content_length, compression, compress_writer)
114 };
115 if result.is_err() {
116 return Err(result.err().unwrap());
117 }
118 let (body, trailers, content_length) = result.unwrap();
119
120 if headers.get("Transfer-Encoding").is_none() {
121 headers = headers.replace(("Content-Length", content_length.to_string().as_str()));
122 }
123 if is_request && is_version_1_0 {
126 headers = headers.add(("Content-Length", content_length.to_string().as_str()))
127 .remove("Transfer-Encoding");
128 }
129
130 message(part1.to_string(), part2, part3.clone().to_string(), is_response, body, headers, trailers)
131}
132
133#[derive(Clone)]
134enum ReadResult {
135 Ok((bool, usize, Option<ReadMetadata>)),
136 Err(MessageError),
137}
138
139impl ReadResult {
140 pub fn err(self) -> MessageError {
141 return match self {
142 ReadResult::Ok(_) => panic!("Not an error"),
143 ReadResult::Err(e) => e,
144 };
145 }
146
147 pub fn is_err(&self) -> bool {
148 return match self {
149 ReadResult::Ok(_) => false,
150 ReadResult::Err(_) => true
151 };
152 }
153
154 pub fn unwrap(&self) -> (bool, usize, Option<ReadMetadata>) {
155 *match &self {
156 ReadResult::Ok(triple) => triple,
157 ReadResult::Err(e) => panic!("Called unwrap on error: {}", e.to_string())
158 }
159 }
160}
161
162#[derive(Copy, Clone)]
163struct ChunkedMetadata {
164 mode: ReadMode,
165 chunk_size: usize,
166 bytes_of_this_chunk_read: usize,
167}
168
169#[derive(Copy, Clone)]
170struct MultipartMetadata {}
171
172#[derive(Copy, Clone)]
173enum ReadMetadata {
174 Chunked(ChunkedMetadata),
175 Multipart(MultipartMetadata),
176}
177
178#[derive(Copy, Clone, PartialEq, Eq)]
179enum ReadMode {
180 Metadata,
181 Data,
182}
183
184impl ReadMetadata {
185 pub fn chunked(mode: ReadMode, chunk_size: usize, bytes_of_this_chunk_read: usize) -> ReadMetadata {
186 ReadMetadata::Chunked(ChunkedMetadata { mode, chunk_size, bytes_of_this_chunk_read })
187 }
188
189 pub fn to_chunked_metadata(self) -> ChunkedMetadata {
190 match self {
191 ReadMetadata::Chunked(m) => m,
192 ReadMetadata::Multipart(_) => panic!("Have multipart metadata but expected chunked metadata")
193 }
194 }
195}
196
197fn read(
198 stream: &mut TcpStream,
199 mut reader: &mut [u8],
200 writer: &mut Vec<u8>,
201 mut read_bytes_from_stream: usize,
202 mut up_to_in_reader: usize,
203 mut metadata: Option<ReadMetadata>,
204 fun: fn(&mut [u8], &mut Vec<u8>, Option<ReadMetadata>) -> ReadResult,
205) -> (usize, usize, ReadResult) {
206 let mut finished = false;
207 let mut result = ReadResult::Err(MessageError::HeadersTooBig("".to_string()));
208 while !finished {
209 if up_to_in_reader > 0 && read_bytes_from_stream > up_to_in_reader {
210 result = fun(&mut reader[up_to_in_reader..read_bytes_from_stream], writer, metadata);
211 if result.is_err() {
212 return (0, 0, ReadResult::Err(result.err()));
213 }
214 let (now_finished, new_up_to_in_reader, new_metadata) = result.unwrap();
218 metadata = new_metadata;
219 finished = now_finished;
220 if new_up_to_in_reader == 0 {
222 up_to_in_reader = 0
223 } else {
224 up_to_in_reader += new_up_to_in_reader
225 };
226 if finished { break; }
227 } else {
228 read_bytes_from_stream = stream.read(&mut reader).unwrap();
229 result = fun(&mut reader[..read_bytes_from_stream], writer, metadata);
230 if result.is_err() {
231 return (0, 0, ReadResult::Err(result.err()));
232 }
233 (finished, up_to_in_reader, metadata) = result.unwrap();
234 }
235 }
236 (read_bytes_from_stream, up_to_in_reader, result)
237}
238
239fn message<'a>(part1: String, part2: &'a str, part3: String, is_response: bool, body: Body<'a>, headers: Headers, trailers: Headers) -> Result<HttpMessage<'a>, MessageError> {
240 if is_response {
241 let (major, minor) = http_version_from(part1.as_str());
242 Ok(HttpMessage::Response(Response {
243 status: Status::from(part2),
244 headers,
245 body,
246 version: HttpVersion { major, minor },
247 trailers,
248 }))
249 } else {
250 let (major, minor) = http_version_from(part3.as_str());
251 Ok(HttpMessage::Request(Request {
252 method: Method::from(part1.as_str()),
253 uri: Uri::parse(part2),
254 headers,
255 body,
256 version: HttpVersion { major, minor },
257 trailers,
258 }))
259 }
260}
261
262fn simple_body<'a>(
263 reader: &'a mut [u8],
264 stream: TcpStream,
265 up_to_in_reader: usize,
266 read_bytes_from_stream: usize,
267 is_request: bool,
268 method_can_have_body: bool,
269 content_length: Option<Result<usize, String>>,
270 compression: CompressionAlgorithm,
271 mut compress_writer: &'a mut Vec<u8>,
272) -> Result<(Body<'a>, Headers, usize), MessageError> {
273 let bytes_left_in_reader = read_bytes_from_stream - up_to_in_reader;
274 let (body, content_length) = match content_length {
275 Some(_) if is_request && !method_can_have_body => {
276 (Body::empty(), 0)
277 }
278 Some(Ok(content_length)) if bytes_left_in_reader == content_length => {
280 if compression.is_some() {
281 decompress(&compression, &mut compress_writer, &mut reader[up_to_in_reader..read_bytes_from_stream].to_vec());
282 let result = str::from_utf8(compress_writer.as_slice()).unwrap();
283 (Body::BodyString(result), compress_writer.len())
284 } else {
285 let result = str::from_utf8(&reader[up_to_in_reader..read_bytes_from_stream]).unwrap();
286 (Body::BodyString(result), content_length)
287 }
288 }
289 Some(Ok(content_length)) => {
290 if compression.is_some() {
292 let mut rest = Vec::new();
293 let _read = stream.take((content_length - bytes_left_in_reader) as u64).read_to_end(&mut rest).unwrap();
294 let mut whole = reader[up_to_in_reader..read_bytes_from_stream].to_vec();
295 whole.append(&mut rest);
296 decompress(&compression, &mut compress_writer, &mut whole);
297 let result = str::from_utf8(compress_writer.as_slice()).unwrap();
298 (Body::BodyString(result), compress_writer.len())
299 } else {
300 let rest = stream.take((content_length - bytes_left_in_reader) as u64);
301 (Body::BodyStream(Box::new(reader[up_to_in_reader..read_bytes_from_stream].chain(rest))), content_length)
302 }
303 }
304 Some(Err(error)) => {
305 return Err(MessageError::InvalidContentLength(format!("Content Length header couldn't be parsed, got {}", error).to_string()));
306 }
307 _ => (Body::empty(), 0)
308 };
309 Ok((body, Headers::empty(), content_length))
310}
311
312fn chunked_body_and_trailers<'a>(
313 reader: &'a mut [u8],
314 mut stream: TcpStream,
315 up_to_in_reader: usize,
316 read_bytes_from_stream: usize,
317 chunks_writer: &'a mut Vec<u8>,
318 compress_writer: &'a mut Vec<u8>,
319 trailers_writer: &'a mut Vec<u8>,
320 compression: &CompressionAlgorithm,
321) -> Result<(Body<'a>, Headers, usize), MessageError> {
322 let result = read_body_and_trailers(reader, &mut stream, up_to_in_reader, read_bytes_from_stream, chunks_writer, trailers_writer);
323 if result.is_err() {
324 return Err(result.err().unwrap());
325 }
326 let chunked_body_bytes_read = result.unwrap();
327 let trailer_string = from_utf8(trailers_writer.as_slice()).unwrap();
328 let trailers = Headers::parse_from(trailer_string);
329
330 let body = if compression.is_some() {
331 decompress(&compression, compress_writer, chunks_writer);
332 BodyStream(Box::new(compress_writer.take(compress_writer.len() as u64)))
333 } else {
334 BodyStream(Box::new(chunks_writer.take(chunks_writer.len() as u64)))
335 };
336 Ok((body, trailers, chunked_body_bytes_read))
337}
338
339#[allow(unused_assignments)]
340fn read_body_and_trailers(reader: &mut [u8], mut stream: &mut TcpStream, up_to_in_reader: usize, read_bytes_from_stream: usize, chunks_writer: &mut Vec<u8>, trailers_writer: &mut Vec<u8>) -> Result<usize, MessageError> {
341 let metadata = Some(ReadMetadata::chunked(ReadMode::Metadata, 0, 0));
342 let (mut read_bytes_from_stream, mut up_to_in_reader, mut result) =
343 read(&mut stream, reader, chunks_writer, read_bytes_from_stream, up_to_in_reader, metadata, |reader, writer, metadata| {
344 let meta = metadata.unwrap().to_chunked_metadata();
345 body_chunks_(reader, writer, meta.mode, meta.bytes_of_this_chunk_read, meta.chunk_size)
346 });
347 if result.is_err() {
348 return Err(result.err());
349 }
350 let (_finished, chunked_body_bytes_read, _metadata) = result.unwrap();
351
352 let more_bytes_to_read_after_body = up_to_in_reader < read_bytes_from_stream;
353 if more_bytes_to_read_after_body {
354 (read_bytes_from_stream, up_to_in_reader, result) =
355 read(&mut stream, reader, trailers_writer, read_bytes_from_stream, up_to_in_reader, metadata, |reader, writer, _metadata| {
356 trailers_(reader, writer)
357 });
358 }
359 if result.is_err() {
360 return Err(result.err());
361 }
362 Ok(chunked_body_bytes_read)
363}
364
365fn body_chunks_(reader: &[u8], writer: &mut Vec<u8>, mut mode: ReadMode, read_up_to: usize, this_chunk_size: usize) -> ReadResult {
366 let mut prev = vec!('1', '2', '3', '4', '5');
367 let mut chunk_size: usize = this_chunk_size;
368 let mut chunk_size_hex: String = "".to_string();
369 let mut bytes_of_this_chunk_read_previously = read_up_to;
370 let mut finished = false;
371 let mut bytes_of_chunk_read_this_pass: usize = 0;
372 let mut up_to_in_reader: usize = 0;
373
374 for (index, octet) in reader.iter().enumerate() {
375 prev.remove(0);
376 prev.push(*octet as char);
377
378 let on_boundary = *octet == b'\n' || *octet == b'\r';
379 if mode == ReadMode::Metadata && !on_boundary {
380 chunk_size_hex.push(*octet as char);
381 } else if mode == ReadMode::Metadata && on_boundary {
382 if *octet == b'\n' {
384 let result = usize::from_str_radix(&chunk_size_hex, 16);
385 if result.is_err() {
386 return ReadResult::Err(MessageError::InvalidBoundaryDigit(format!("Could not parse boundary character {} in chunked encoding", &chunk_size_hex)));
387 }
388 chunk_size_hex = "".to_string();
390 chunk_size = result.unwrap();
391 if chunk_size == 0 {
392 finished = true;
393 if reader.len() > index + 3 {
395 up_to_in_reader = index + 1
396 } else {
397 up_to_in_reader = index + 3; }
399 break;
400 }
401 mode = ReadMode::Data;
402 }
403 continue;
404 }
405 if mode == ReadMode::Data && bytes_of_chunk_read_this_pass < (chunk_size - bytes_of_this_chunk_read_previously) {
406 writer.push(*octet);
407 bytes_of_chunk_read_this_pass += 1;
408 let last_iteration = index == reader.len() - 1;
409 if last_iteration {
410 bytes_of_this_chunk_read_previously += bytes_of_chunk_read_this_pass;
412 up_to_in_reader = 0;
413 break;
414 }
415 } else if mode == ReadMode::Data && on_boundary {
416 if *octet == b'\n' {
419 bytes_of_this_chunk_read_previously = 0;
420 chunk_size = 0;
421 bytes_of_chunk_read_this_pass = 0;
422 mode = ReadMode::Metadata;
423 }
424 continue;
425 }
426 }
427
428 let metadata = ReadMetadata::chunked(mode, chunk_size, bytes_of_this_chunk_read_previously);
429 ReadResult::Ok((finished, up_to_in_reader, Some(metadata)))
430}
431
432fn check_valid_content_length_or_transfer_encoding(headers: &Headers, is_response: bool, method_can_have_body: bool) -> Result<(), MessageError> {
433 let is_req_and_method_can_have_body = !is_response && method_can_have_body;
434 let no_content_length_or_transfer_encoding = !headers.has("Content-Length") &&
435 headers.get("Transfer-Encoding").is_none();
436
437 if (is_req_and_method_can_have_body && no_content_length_or_transfer_encoding)
438 || is_response && no_content_length_or_transfer_encoding {
439 return Err(MessageError::NoContentLengthOrTransferEncoding("Content-Length or Transfer-Encoding must be provided".to_string()));
440 }
441 Ok(())
442}
443
444fn start_line_(reader: &[u8], writer: &mut Vec<u8>) -> ReadResult {
445 let mut prev: Vec<char> = vec!('1', '2', '3', '4');
446 let mut up_to_in_reader = if reader.len() > 0 { reader.len() - 1 } else { 0 };
447 let mut finished = false;
448
449 for (index, octet) in reader.iter().enumerate() {
450 if *octet != b'\r' && *octet != b'\n' {
451 writer.push(*octet);
452 }
453 if prev[3] == '\r' && *octet == b'\n' {
454 finished = true;
455 up_to_in_reader = index + 1;
456 break;
457 }
458 if writer.len() == writer.capacity() {
459 return ReadResult::Err(MessageError::StartLineTooBig(format!("Start line must be less than {}", reader.len())));
460 }
461 prev.remove(0);
462 prev.push(*octet as char);
463 }
464
465 ReadResult::Ok((finished, up_to_in_reader, None))
466}
467
468fn headers_(reader: &[u8], writer: &mut Vec<u8>) -> ReadResult {
469 let mut prev: Vec<char> = vec!('1', '2', '3', '4');
470 let mut up_to_in_reader = reader.len() - 1;
471 let mut finished = false;
472
473 for (index, octet) in reader.iter().enumerate() {
474 writer.push(*octet);
475 up_to_in_reader = index + 1;
476 if prev[1] == '\r' && prev[2] == '\n' && prev[3] == '\r' && *octet == b'\n' {
477 finished = true;
478 writer.pop();
479 writer.pop();
480 writer.pop();
481 writer.pop(); break;
483 }
484 if writer.len() == writer.capacity() {
485 return ReadResult::Err(MessageError::HeadersTooBig(format!("Headers must be less than {}", writer.capacity())));
486 }
487 prev.remove(0);
488 prev.push(*octet as char);
489 }
490
491 ReadResult::Ok((finished, up_to_in_reader, None))
492}
493
494fn trailers_(buffer: &[u8], writer: &mut Vec<u8>) -> ReadResult {
495 let mut prev: Vec<char> = vec!('1', '2', '3', '4');
496 let mut finished = false;
497
498 for (_index, octet) in buffer.iter().enumerate() {
499 if prev[1] == '\r' && prev[2] == '\n' && prev[3] == '\r' && *octet == b'\n' {
500 finished = true;
501 break;
502 }
503 if writer.len() == writer.capacity() {
504 return ReadResult::Err(MessageError::TrailersTooBig(format!("Trailers must be less than {}", writer.capacity())));
505 }
506 prev.remove(0);
507 prev.push(*octet as char);
508 writer.push(*octet);
509 }
510
511 if finished {
512 writer.pop();
513 writer.pop();
514 writer.pop(); }
516
517 ReadResult::Ok((finished, 0, None))
518}
519
520#[derive(Copy, Clone)]
521pub enum CompressionAlgorithm {
522 GZIP,
523 BROTLI,
524 DEFLATE,
525 NONE,
526}
527
528impl CompressionAlgorithm {
529 pub fn is_none(&self) -> bool {
530 match self {
531 CompressionAlgorithm::NONE => true,
532 _ => false
533 }
534 }
535
536 pub fn or(self, next: CompressionAlgorithm) -> CompressionAlgorithm {
537 match self {
538 GZIP => self,
539 BROTLI => self,
540 DEFLATE => self,
541 NONE => next
542 }
543 }
544
545 pub fn is_some(&self) -> bool {
546 !self.is_none()
547 }
548
549 pub fn from(str: String) -> CompressionAlgorithm {
550 match str {
551 str if str.contains("gzip") => GZIP,
552 str if str.contains("deflate") => DEFLATE,
553 str if str.contains("brotli") => BROTLI,
554 _ => NONE
555 }
556 }
557
558 pub fn supported_algorithms() -> Vec<String> {
559 vec!("gzip".to_string(), "brotli".to_string(), "deflate".to_string())
560 }
561
562 pub fn to_string_for_content_encoding(&self) -> String {
563 match self {
564 GZIP => "gzip".to_string(),
565 BROTLI => "br".to_string(),
566 DEFLATE => "deflate".to_string(),
567 CompressionAlgorithm::NONE => "none".to_string()
568 }
569 }
570
571 pub fn to_string_for_transfer_encoding(&self) -> String {
572 match self {
573 GZIP => "gzip".to_string(),
574 BROTLI => "brotli".to_string(),
575 DEFLATE => "deflate".to_string(),
576 CompressionAlgorithm::NONE => "".to_string()
577 }
578 }
579}
580
581#[allow(non_snake_case)]
582pub fn write_message_to_wire(mut stream: &mut TcpStream, message: HttpMessage, request_options: RequestOptions) {
583 match message {
584 HttpMessage::Request(mut req) => {
585 let chunked_encoding_desired = req.headers.has("Transfer-Encoding");
586 let has_content_length = req.headers.has("Content-Length");
587 let headers = ensure_content_length_or_transfer_encoding(req.headers, &req.body, &req.version, chunked_encoding_desired, has_content_length);
588 let chunked_encoding_desired = headers.has("Transfer-Encoding");
589
590 let compression = compression_from(headers.get("Content-Encoding").or(headers.get("Transfer-Encoding")));
591
592 let headers = set_connection_header_if_needed_and_not_present(headers, chunked_encoding_desired);
593
594 let start_line = format!("{} {} HTTP/{}.{}\r\n",
595 req.method.value(),
596 req.uri.to_string(),
597 req.version.major,
598 req.version.minor);
599
600 let start_line_and_headers = format!("{}{}\r\n\r\n", start_line, headers.to_wire_string());
601
602 match req.body {
603 BodyString(str) => {
604 let is_version_1_1 = req.version == one_pt_one();
605 if chunked_encoding_desired && is_version_1_1 {
606 write_chunked_string(stream, start_line_and_headers, str.as_bytes(), req.trailers, compression);
607 } else {
608 write_string(stream, &compression, start_line_and_headers, str, headers, start_line)
609 }
610 }
611 BodyStream(ref mut reader) => {
612 if chunked_encoding_desired && req.version == one_pt_one() {
613 write_chunked_stream(stream, reader, start_line_and_headers, req.trailers, compression);
614 } else {
615 if compression.is_none() {
616 let mut chain = start_line_and_headers.as_bytes().chain(reader);
617 let _copy = copy(&mut chain, &mut stream).unwrap();
618 } else {
619 let mut writer = Vec::new();
620 let mut read = [0; 4096];
621 loop {
622 let bytes_read = reader.read(&mut read).unwrap();
623 if bytes_read == 0 {
624 break;
625 }
626 }
627 compress(&compression, &mut writer, &read);
628 let headers = headers.replace(("Content-Length", writer.len().to_string().as_str()));
629 let start_line_and_headers = format!("{}{}\r\n\r\n", start_line, headers.to_wire_string());
630 let mut whole = start_line_and_headers.as_bytes().to_vec();
631 whole.append(&mut writer);
632 stream.write(&whole).unwrap();
633 }
634 }
635 }
636 }
637 }
638 HttpMessage::Response(mut res) => {
639 let has_transfer_encoding = res.headers.has("Transfer-Encoding");
640 let has_content_length = res.headers.has("Content-Length");
641 let mut headers = ensure_content_length_or_transfer_encoding(res.headers, &res.body, &res.version, has_transfer_encoding, has_content_length);
642
643 let compression = if headers.get("Content-Encoding").map(|ce| ce.to_lowercase() == "none").unwrap_or(false) {
644 headers = headers.remove("Content-Encoding");
645 CompressionAlgorithm::NONE
646 } else {
647 let compression_algorithm = request_options.write_response_compression()
648 .or(compression_from(headers.get("Transfer-Encoding")))
649 .or(compression_from(headers.get("Content-Encoding")));
650
651 if compression_algorithm.is_some() && !headers.has("Transfer-Encoding") {
652 headers = headers.replace(("Content-Encoding", compression_algorithm.to_string_for_content_encoding().as_str()));
653 } else if compression_algorithm.is_some() && headers.has("Transfer-Encoding") {
654 headers = headers.replace(("Transfer-Encoding", format!("{}, chunked", compression_algorithm.to_string_for_transfer_encoding()).as_str()))
655 }
656 compression_algorithm
657 };
658
659 if headers.has("TE") {
660 headers = headers.remove("TE")
661 };
662
663 headers = headers.remove("Connection");
664
665 let mut trailers = res.trailers;
666 if !request_options.wants_trailers && !trailers.is_empty() {
667 let as_str = request_options.expected_trailers.iter()
668 .map(|x| x.as_str()).collect::<Vec<&str>>();
669 headers = headers.add_all(trailers.filter(as_str));
670 trailers = Headers::empty();
671 }
672
673 let start_line = format!("HTTP/1.1 {} {}\r\n", &res.status.value(), &res.status.to_string());
674 let status_and_headers = format!("{}{}\r\n\r\n", start_line, headers.to_wire_string());
675
676 let chunked_encoding_desired = headers.has("Transfer-Encoding");
677
678 match res.body {
679 BodyString(str) => {
680 if chunked_encoding_desired && (res.version == one_pt_one()) {
681 write_chunked_string(stream, status_and_headers, str.as_bytes(), trailers, compression);
682 } else {
683 write_string(stream, &compression, status_and_headers, str, headers, start_line)
684 }
685 }
686 BodyStream(ref mut reader) => {
687 if chunked_encoding_desired && res.version == one_pt_one() {
688 write_chunked_stream(&mut stream, reader, status_and_headers, trailers, compression);
689 } else {
690 if compression.is_none() {
691 let mut chain = status_and_headers.as_bytes().chain(reader);
692 let _copy = copy(&mut chain, &mut stream).unwrap();
693 } else {
694 let mut writer = Vec::new();
695 let mut whole = Vec::new();
696 let _bytes_read = reader.read_to_end(&mut whole).unwrap();
697 compress(&compression, &mut writer, whole.as_slice());
698
699 let headers = headers.replace(("Content-length", writer.len().to_string().as_str()));
700 let headers = headers.replace(("Content-Encoding", compression.to_string_for_content_encoding().as_str()));
701 let status_and_headers = Response::status_line_and_headers_wire_string(&headers, &res.status);
702 let mut chain = status_and_headers.as_bytes().chain(writer.as_slice());
703 let _copy = copy(&mut chain, &mut stream).unwrap();
704 }
705 }
706 }
707 }
708 }
709 }
710}
711
712fn set_connection_header_if_needed_and_not_present(headers: Headers, chunked_encoding_desired: bool) -> Headers {
713 if chunked_encoding_desired && headers.get("Connection").map(|h| !h.contains("TE")).unwrap_or(false) {
714 headers.replace(("Connection", headers.get("Connection").map(|mut h| {
715 h.push_str(", TE");
716 h
717 }).unwrap_or("TE".to_string()).as_str()))
718 } else {
719 headers
720 }
721}
722
723fn write_string(stream: &mut TcpStream, compression: &CompressionAlgorithm, start_line_and_headers: String, body: &str, headers: Headers, start_line: String) {
724 if compression.is_none() {
725 let status_headers_and_body = [start_line_and_headers.as_bytes(), body.as_bytes()].concat();
726 stream.write(status_headers_and_body.as_slice()).unwrap();
727 } else {
728 let mut writer = Vec::new();
729 compress(&compression, &mut writer, body.as_bytes());
730 let headers = headers.replace(("Content-Length", writer.len().to_string().as_str()));
731 let mut start_line = start_line;
732 start_line.push_str(headers.to_wire_string().as_str());
733 start_line.push_str("\r\n\r\n");
734 let mut whole = start_line.as_bytes().to_vec();
735 whole.append(&mut writer);
736 stream.write(&whole).unwrap();
737 }
738}
739
740fn compression_from(option: Option<String>) -> CompressionAlgorithm {
741 match option {
742 Some(value) if value.contains("br") => CompressionAlgorithm::BROTLI,
743 Some(value) if value.contains("gzip") => CompressionAlgorithm::GZIP,
744 Some(value) if value.contains("deflate") => CompressionAlgorithm::DEFLATE,
745 _ => CompressionAlgorithm::NONE,
746 }
747}
748
749fn compress<'a>(compression: &'a CompressionAlgorithm, mut writer: &'a mut Vec<u8>, chunk: &'a [u8]) {
750 match compression {
751 CompressionAlgorithm::GZIP => { Codex::encode(chunk, &mut writer, GZIP); }
752 CompressionAlgorithm::BROTLI => { Codex::encode(chunk, &mut writer, BROTLI); }
753 CompressionAlgorithm::DEFLATE => { Codex::encode(chunk, &mut writer, DEFLATE); }
754 CompressionAlgorithm::NONE => { writer.write_all(chunk).unwrap(); }
755 }
756}
757
758fn decompress<'a>(compression: &'a CompressionAlgorithm, writer: &'a mut Vec<u8>, reader: &'a mut Vec<u8>) {
759 match compression {
760 GZIP | DEFLATE | BROTLI => { Codex::decode(reader, writer, compression); }
761 NONE => { writer.write_all(reader).unwrap(); }
762 }
763}
764
765#[allow(unused_assignments)]
766pub fn write_chunked_string(stream: &mut TcpStream, mut first_line: String, chunk: &[u8], trailers: Headers, compression: CompressionAlgorithm) {
767 let mut writer = Vec::new();
768 let mut request = Vec::new();
769 if compression.is_some() {
770 compress(&compression, &mut writer, chunk);
771 write_chunk_metadata(&mut first_line, writer.len());
772 request = [first_line.as_bytes(), writer.as_slice(), "\r\n".as_bytes()].concat();
773 } else {
774 write_chunk_metadata(&mut first_line, chunk.len());
775 request = [first_line.as_bytes(), chunk, "\r\n".as_bytes()].concat();
776 }
777 if !trailers.is_empty() {
778 request.extend_from_slice(format!("0\r\n{}\r\n\r\n", trailers.to_wire_string()).as_bytes());
779 } else {
780 request.extend_from_slice("0\r\n\r\n".as_bytes());
781 }
782 stream.write(request.as_slice()).unwrap();
783}
784
785fn write_chunk_metadata(first_line: &mut String, length: usize) {
786 let length_in_hex = format!("{:X}", length);
787 first_line.push_str(length_in_hex.as_str());
788 first_line.push_str("\r\n");
789}
790
791pub fn write_chunked_stream<'a>(mut stream: &mut TcpStream, reader: &mut Box<dyn Read + 'a>, first_line_and_headers: String, trailers: Headers, compression: CompressionAlgorithm) {
797 if compression.is_some() {
798 write_compressed_chunks(&mut stream, reader, &first_line_and_headers, &trailers, &compression);
799 } else {
800 write_simple_chunks(&mut stream, reader, first_line_and_headers, trailers);
801 }
802}
803
804#[allow(unused_assignments)]
805fn write_simple_chunks<'a>(mut stream: &mut TcpStream, reader: &mut Box<dyn Read + 'a>, first_line_and_headers: String, trailers: Headers) {
806 let buffer = &mut [0 as u8; 16384];
807 let mut bytes_read = reader.read(buffer).unwrap_or(0);
808 let mut first_write = true;
809 let mut temp = Vec::new();
810
811 while bytes_read > 0 {
812 temp = Vec::new();
813 let length_in_hex = format!("{:X}", bytes_read);
814 temp.extend_from_slice(length_in_hex.as_bytes());
815 temp.push(b'\r');
816 temp.push(b'\n');
817 let chunk = &buffer[..bytes_read];
818 temp.extend_from_slice(chunk);
819 temp.push(b'\r');
820 temp.push(b'\n');
821 if first_write {
823 let first_line_and_headers_and_first_chunk = [first_line_and_headers.as_bytes(), temp.as_slice()].concat();
824 let _copy = copy(&mut first_line_and_headers_and_first_chunk.as_slice(), &mut stream).unwrap();
825 first_write = false;
826 } else {
827 let _copy = copy(&mut temp.as_slice(), &mut stream).unwrap();
828 }
829 bytes_read = reader.read(buffer).unwrap();
830 }
831
832 let mut end = vec!(b'0', b'\r', b'\n');
833 if !trailers.is_empty() {
834 end.extend_from_slice(format!("{}\r\n\r\n", trailers.to_wire_string()).as_bytes());
835 } else {
836 end.push(b'\r');
837 end.push(b'\n');
838 }
839 stream.write(end.as_slice()).unwrap();
840}
841
842fn write_compressed_chunks<'a>(mut stream: &mut TcpStream, reader: &mut Box<dyn Read + 'a>, first_line_and_headers: &String, trailers: &Headers, compression: &CompressionAlgorithm) {
843 let buffer = &mut [0 as u8; 16384];
844 let mut bytes_read = reader.read(buffer).unwrap_or(0);
845 let mut temp = Vec::new();
846
847 while bytes_read > 0 {
848 let chunk = &buffer[..bytes_read];
849 temp.extend_from_slice(chunk);
850 bytes_read = reader.read(buffer).unwrap();
851 }
852
853 let mut writer = Vec::new();
854 compress(&compression, &mut writer, temp.as_slice());
855 let compressed_length_in_hex = format!("{:X}", writer.len());
856 let reversed = compressed_length_in_hex.chars().rev().collect::<String>();
857 writer.insert(0, b'\n');
858 writer.insert(0, b'\r');
859 for byte in reversed.as_bytes() {
860 writer.insert(0, *byte)
861 }
862 writer.push(b'\r');
863 writer.push(b'\n');
864
865 let mut end = vec!(b'0', b'\r', b'\n');
866 if !trailers.is_empty() {
867 end.extend_from_slice(format!("{}\r\n\r\n", trailers.to_wire_string()).as_bytes());
868 } else {
869 end.push(b'\r');
870 end.push(b'\n');
871 }
872 let message = [first_line_and_headers.as_bytes(), writer.as_slice(), end.as_slice()].concat();
873 let _copy = copy(&mut message.as_slice(), &mut stream).unwrap();
874}
875
876
877pub fn ensure_content_length_or_transfer_encoding(headers: Headers, body: &Body, version: &HttpVersion, chunked_encoding_desired: bool, has_content_length: bool) -> Headers {
878 if chunked_encoding_desired && has_content_length {
879 headers.remove("Content-Length")
880 } else if !chunked_encoding_desired && !has_content_length {
881 if body.is_body_string() {
882 headers.add(("Content-Length", body.length().to_string().as_str()))
883 } else if body.is_body_stream() && version == &one_pt_one() {
884 headers.add(("Transfer-Encoding", "chunked"))
885 } else {
886 headers
887 }
888 } else {
889 headers
890 }
891}
892
893pub fn most_desired_encoding(str: Option<String>) -> Option<String> {
895 str.map(|v| {
896 let mut ranked = v.split(", ")
897 .map(|p| {
898 let pair = p.split(";").map(|it| it.to_string()).collect::<Vec<String>>();
899 if pair.len() > 1 {
900 let rank = pair[1].split("=").map(|it| it.to_string()).collect::<Vec<String>>();
901 if rank.len() > 1 {
902 Some((pair[0].clone(), rank[1].clone()))
903 } else { None }
904 } else { None }
905 })
906 .filter(|p| p.is_some())
907 .map(|x| x.unwrap())
908 .filter(|y| CompressionAlgorithm::supported_algorithms().contains(&y.0))
909 .collect::<Vec<(String, String)>>();
910
911 ranked.sort_by(|x, y| x.1.parse::<f32>().unwrap().partial_cmp(&y.1.parse::<f32>().unwrap()).unwrap());
912 ranked.reverse();
913 ranked.first().map(|x| x.0.clone())
914 }).unwrap_or(Some("none".to_string()))
915}
916
917
918fn http_version_from(str: &str) -> (u8, u8) {
919 let mut version_chars = str.chars();
920 let major = version_chars.nth(0);
921 let minor = version_chars.nth(2);
922 (major.unwrap() as u8, minor.unwrap() as u8)
923}
924
925#[derive(Clone, Debug)]
926pub enum MessageError {
927 InvalidContentLength(String),
928 NoContentLengthOrTransferEncoding(String),
929 StartLineTooBig(String),
930 HeadersTooBig(String),
931 TrailersTooBig(String),
932 InvalidBoundaryDigit(String),
933}
934
935impl MessageError {
936 pub fn to_string(&self) -> String {
937 match &self {
938 MessageError::InvalidContentLength(_) => "Invalid content length".to_string(),
939 MessageError::NoContentLengthOrTransferEncoding(_) => "No content length or transfer encoding".to_string(),
940 MessageError::StartLineTooBig(_) => "Start line too big".to_string(),
941 MessageError::HeadersTooBig(_) => "Headers too big".to_string(),
942 MessageError::TrailersTooBig(_) => "Trailers too big".to_string(),
943 MessageError::InvalidBoundaryDigit(_) => "Invalid boundary digit in chunked encoding".to_string(),
944 }
945 }
946}
947
948impl<'a> Response<'a> {
949 pub fn status_line_and_headers_wire_string(headers: &Headers, status: &Status) -> String {
950 let mut response = String::new();
951 let http = format!("HTTP/1.1 {} {}", &status.value(), &status.to_string());
952 response.push_str(&http);
953 response.push_str("\r\n");
954
955 response.push_str(&headers.to_wire_string().as_str());
956
957 response.push_str("\r\n\r\n");
958 response
959 }
960}
961
962pub enum Body<'a> {
963 BodyString(&'a str),
964 BodyStream(Box<dyn Read + 'a>),
965}
966
967impl<'a> Body<'a> {
968 pub fn empty() -> Body<'a> {
969 BodyString("")
970 }
971
972 pub fn is_body_string(&self) -> bool {
973 match self {
974 BodyString(_) => true,
975 BodyStream(_) => false
976 }
977 }
978
979 pub fn is_body_stream(&self) -> bool {
980 match self {
981 BodyString(_) => false,
982 BodyStream(_) => true
983 }
984 }
985
986 pub fn length(&self) -> usize {
987 match self {
988 BodyString(str) => str.len(),
989 BodyStream(_) => panic!("Do not know the length of a body stream!")
990 }
991 }
992}
993
994pub fn body_length(body: &Body) -> u32 {
995 match body {
996 BodyString(str) => str.len() as u32,
997 BodyStream(_) => panic!("Cannot find length of BodyStream, please provide Content-Length header")
998 }
999}
1000
1001pub fn with_content_length(message: HttpMessage) -> HttpMessage {
1002 match message {
1003 HttpMessage::Request(request) => {
1004 if !request.headers.has("Content-Length") && !request.headers.has("Transfer-Encoding") {
1005 return HttpMessage::Request(Request {
1006 headers: request.headers.add(("Content-Length", body_length(&request.body).to_string().as_str())),
1007 ..request
1008 });
1009 } else {
1010 HttpMessage::Request(request)
1011 }
1012 }
1013 HttpMessage::Response(response) => {
1014 if !response.headers.has("Content-Length") && !response.headers.has("Transfer-Encoding") {
1015 return HttpMessage::Response(Response {
1016 headers: response.headers.add(("Content-Length", body_length(&response.body).to_string().as_str())),
1017 ..response
1018 });
1019 } else {
1020 HttpMessage::Response(response)
1021 }
1022 }
1023 }
1024}
1025
1026#[derive(PartialEq)]
1027pub struct HttpVersion {
1028 pub major: u8,
1029 pub minor: u8,
1030}
1031
1032pub fn one_pt_one() -> HttpVersion {
1033 HttpVersion { major: 1, minor: 1 }
1034}
1035
1036pub fn two_pt_oh() -> HttpVersion {
1037 HttpVersion { major: 2, minor: 0 }
1038}
1039
1040pub fn one_pt_oh() -> HttpVersion {
1041 HttpVersion { major: 1, minor: 0 }
1042}
1043
1044pub struct Request<'a> {
1045 pub headers: Headers,
1046 pub body: Body<'a>,
1047 pub uri: Uri<'a>,
1048 pub method: Method,
1049 pub version: HttpVersion,
1050 pub trailers: Headers,
1051}
1052
1053pub struct Response<'a> {
1054 pub headers: Headers,
1055 pub body: Body<'a>,
1056 pub status: Status,
1057 pub version: HttpVersion,
1058 pub trailers: Headers,
1059}
1060
1061
1062impl<'a> Request<'a> {
1063 pub fn with_body(self, body: Body<'a>) -> Request<'a> {
1064 Request {
1065 body,
1066 ..self
1067 }
1068 }
1069
1070 pub fn with_header(self, pair: (&str, &str)) -> Request<'a> {
1071 Request {
1072 headers: self.headers.add(pair),
1073 ..self
1074 }
1075 }
1076
1077 pub fn with_trailers(self, trailers: Headers) -> Request<'a> {
1078 Request {
1079 trailers,
1080 ..self
1081 }
1082 }
1083
1084 pub fn with_uri(self, uri: Uri<'a>) -> Request<'a> {
1085 Request {
1086 uri,
1087 ..self
1088 }
1089 }
1090}
1091
1092pub fn body_string(mut body: Body) -> String {
1093 match body {
1094 BodyString(str) => str.to_string(),
1095 BodyStream(ref mut reader) => {
1096 let big = &mut Vec::new();
1097 let _read_bytes = reader.read_to_end(big).unwrap(); str::from_utf8(&big).unwrap()
1099 .trim_end_matches(char::from(0))
1100 .to_string()
1101 }
1102 }
1103}
1104
1105#[allow(non_snake_case)]
1106pub struct RequestOptions {
1107 pub desired_content_encoding: CompressionAlgorithm,
1108 pub transfer_encoding: CompressionAlgorithm,
1109 pub compression_from_TE_header: CompressionAlgorithm,
1110 pub content_encoding: CompressionAlgorithm,
1111 pub wants_trailers: bool,
1112 pub expected_trailers: Vec<String>,
1113}
1114
1115#[allow(non_snake_case)]
1116impl RequestOptions {
1117 pub fn from(headers: &Headers) -> RequestOptions {
1118 RequestOptions {
1119 desired_content_encoding: compression_from(headers.get("Accept-Encoding")),
1120 transfer_encoding: compression_from(headers.get("Transfer-Encoding")),
1121 content_encoding: compression_from(headers.get("Content-Encoding")),
1122 compression_from_TE_header: compression_from(most_desired_encoding(headers.get("TE"))),
1123 wants_trailers: headers.get("TE").map(|t| t.contains("trailers")).unwrap_or(false),
1124 expected_trailers: headers.get("Trailer").map(|ts| ts.split(", ")
1125 .filter(|t| !DISALLOWED_TRAILERS.contains(&&*t.to_lowercase()))
1126 .map(|t| t.to_string())
1127 .collect::<Vec<String>>())
1128 .unwrap_or(vec!()),
1129 }
1130 }
1131
1132 pub fn read_compression(&self) -> CompressionAlgorithm {
1133 self.content_encoding
1134 .or(self.transfer_encoding)
1135 }
1136
1137 pub fn write_response_compression(&self) -> CompressionAlgorithm {
1138 self.desired_content_encoding
1139 .or(self.transfer_encoding)
1140 .or(self.compression_from_TE_header)
1141 }
1142
1143 pub fn default() -> RequestOptions {
1144 RequestOptions {
1145 desired_content_encoding: NONE,
1146 transfer_encoding: NONE,
1147 content_encoding: NONE,
1148 compression_from_TE_header: NONE,
1149 wants_trailers: false,
1150 expected_trailers: vec!(),
1151 }
1152 }
1153}
1154
1155
1156#[derive(PartialEq, Debug)]
1157pub enum Method {
1158 GET,
1159 CONNECT,
1160 HEAD,
1161 POST,
1162 OPTIONS,
1163 DELETE,
1164 PATCH,
1165 PUT,
1166 TRACE,
1167}
1168
1169impl Method {
1170 pub fn value(&self) -> String {
1171 match self {
1172 GET => String::from("GET"),
1173 POST => String::from("POST"),
1174 PATCH => String::from("PATCH"),
1175 OPTIONS => String::from("OPTIONS"),
1176 CONNECT => String::from("CONNECT"),
1177 HEAD => String::from("HEAD"),
1178 DELETE => String::from("DELETE"),
1179 PUT => String::from("PUT"),
1180 TRACE => String::from("TRACE")
1181 }
1182 }
1183
1184 pub fn from(str: &str) -> Method {
1185 match str {
1186 "GET" => GET,
1187 "POST" => POST,
1188 "PATCH" => PATCH,
1189 "OPTIONS" => OPTIONS,
1190 "DELETE" => DELETE,
1191 "CONNECT" => CONNECT,
1192 "TRACE" => TRACE,
1193 "HEAD" => HEAD,
1194 _ => panic!("Unknown method")
1195 }
1196 }
1197}
1198
1199impl<'a> Response<'a> {
1200 pub fn ok(headers: Headers, body: Body) -> Response {
1201 Response { headers, body, status: OK, version: HttpVersion { major: 1, minor: 1 }, trailers: Headers::empty() }
1202 }
1203
1204 pub fn bad_request(headers: Headers, body: Body) -> Response {
1205 Response { headers, body, status: BadRequest, version: HttpVersion { major: 1, minor: 1 }, trailers: Headers::empty() }
1206 }
1207
1208 pub fn internal_server_error(headers: Headers, body: Body) -> Response {
1209 Response { headers, body, status: InternalServerError, version: HttpVersion { major: 1, minor: 1 }, trailers: Headers::empty() }
1210 }
1211
1212 pub fn length_required(headers: Headers, body: Body) -> Response {
1213 Response { headers, body, status: LengthRequired, version: HttpVersion { major: 1, minor: 1 }, trailers: Headers::empty() }
1214 }
1215
1216 pub fn not_found(headers: Headers, body: Body) -> Response {
1217 Response { headers, body, status: NotFound, version: HttpVersion { major: 1, minor: 1 }, trailers: Headers::empty() }
1218 }
1219
1220 pub fn forbidden(headers: Headers, body: Body) -> Response {
1221 Response { headers, body, status: Forbidden, version: HttpVersion { major: 1, minor: 1 }, trailers: Headers::empty() }
1222 }
1223
1224 pub fn moved_permanently(headers: Headers, body: Body) -> Response {
1225 Response { headers, body, status: MovedPermanently, version: HttpVersion { major: 1, minor: 1 }, trailers: Headers::empty() }
1226 }
1227
1228 pub fn with_trailers(self, trailers: Headers) -> Response<'a> {
1229 Response {
1230 trailers,
1231 ..self
1232 }
1233 }
1234
1235 pub fn with_headers(self, headers: Headers) -> Response<'a> {
1236 Response {
1237 headers: self.headers.add_all(headers),
1238 ..self
1239 }
1240 }
1241}
1242
1243impl<'a> Request<'a> {
1244 pub fn request(method: Method, uri: Uri, headers: Headers) -> Request {
1245 Request { method, headers, body: Body::empty(), uri, version: HttpVersion { major: 1, minor: 1 }, trailers: Headers::empty() }
1246 }
1247
1248 pub fn get(uri: Uri, headers: Headers) -> Request {
1249 Request { method: GET, headers, body: Body::empty(), uri, version: HttpVersion { major: 1, minor: 1 }, trailers: Headers::empty() }
1250 }
1251
1252 pub fn post(uri: Uri<'a>, headers: Headers, body: Body<'a>) -> Request<'a> {
1253 Request { method: POST, headers, body, uri, version: HttpVersion { major: 1, minor: 1 }, trailers: Headers::empty() }
1254 }
1255}
1256
1257
1258#[derive(PartialEq, Debug)]
1259#[repr(u32)]
1260pub enum Status {
1261 OK = 200,
1262 MovedPermanently = 301,
1263 BadRequest = 400,
1264 LengthRequired = 411,
1265 NotFound = 404,
1266 Forbidden = 403,
1267 InternalServerError = 500,
1268 Unknown = 0,
1269}
1270
1271impl Status {
1272 pub fn to_string(&self) -> String {
1273 match self {
1274 OK => "OK".to_string(),
1275 MovedPermanently => "Moved Permanently".to_string(),
1276 NotFound => "Not Found".to_string(),
1277 Forbidden => "Forbidden".to_string(),
1278 BadRequest => "Bad Request".to_string(),
1279 InternalServerError => "Internal Server Error".to_string(),
1280 _ => "Unknown".to_string()
1281 }
1282 }
1283 pub fn value(&self) -> u32 {
1284 match self {
1285 OK => 200,
1286 MovedPermanently => 301,
1287 BadRequest => 400,
1288 Forbidden => 403,
1289 NotFound => 404,
1290 InternalServerError => 500,
1291 _ => 500
1292 }
1293 }
1294 pub fn from(str: &str) -> Self {
1295 match str.to_lowercase().as_str() {
1296 "200" => OK,
1297 "301" => MovedPermanently,
1298 "400" => BadRequest,
1299 "403" => Forbidden,
1300 "404" => NotFound,
1301 "500" => InternalServerError,
1302 _ => Unknown
1303 }
1304 }
1305}
1306