http4r_core/
http_message.rs

1/*
2    http4r is a web toolkit
3    Copyright (C) 2021 Tom Shacham
4
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation, either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18
19use 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    // should only be doing this if we are talking to a user agent that does not accept chunked encoding
124    // otherwise keep chunked encoding header
125    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            // if up_to_in_reader > 0 then we are continuing on in the same reader from previous call to stream.read()
215            // ie we didn't need to call stream.read to finish parsing in fun()
216            // so we need to increment the up_to_in_reader as we are not starting from the start of the reader
217            let (now_finished, new_up_to_in_reader, new_metadata) = result.unwrap();
218            metadata = new_metadata;
219            finished = now_finished;
220            // if we reached the end of the reader then set to zero, otherwise add on how far through we got
221            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        // we have read the whole body in the first read
279        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            // we need to read more to get the body
291            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 we're on the boundary, continue, or compute chunk length and change mode to read once we've seen \n
383            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                // reset chunk_size_hex
389                chunk_size_hex = "".to_string();
390                chunk_size = result.unwrap();
391                if chunk_size == 0 {
392                    finished = true;
393                    // if more bytes left then assume there are trailers (which means end is 0\r\n otherwise its 0\r\n\r\n)
394                    if reader.len() > index + 3 {
395                        up_to_in_reader = index + 1
396                    } else {
397                        up_to_in_reader = index + 3; // add 3 to go past the next \n (weve hit the first one in 0\r\n\r\n)
398                    }
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                // if last index, add on the bytes read from current chunk
411                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 we're on the boundary, continue, or change mode to metadata once we've seen \n
417            // and reset counters
418            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(); // get rid of previous \r\n\r\n
482            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(); // get rid of previous \r\n\r\n
515    }
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
791/*
792https://doc.rust-lang.org/std/io/trait.Read.html#tymethod.read
793It is not an error if the returned value n is smaller than the buffer size, even when the reader is not at the end of the stream yet.
794This may happen for example because fewer bytes are actually available right now (e. g. being close to end-of-file) or because read() was interrupted by a signal.
795 */
796pub 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        // write to wire
822        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
893// something like gzip;q=0.9, deflate;q=0.8
894pub 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(); //todo() this blows up sometimes! unwrap_or()?
1098            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