Skip to main content

rust_web_server/response/
mod.rs

1#[cfg(test)]
2mod tests;
3#[cfg(test)]
4mod example;
5
6use std::io;
7use std::io::{BufRead, Cursor, Read};
8use crate::body::multipart_form_data::FormMultipartData;
9use crate::core::New;
10use crate::header::Header;
11use crate::ext::string_ext::StringExt;
12use crate::http::{HTTP, VERSION};
13use crate::mime_type::MimeType;
14use crate::range::{ContentRange, Range};
15use crate::request::{METHOD, Request};
16use crate::symbol::SYMBOL;
17
18#[derive(PartialEq, Eq, Clone, Debug)]
19pub struct Error {
20    pub status_code_reason_phrase: &'static StatusCodeReasonPhrase,
21    pub message: String,
22}
23
24/// An HTTP response. Build one inside [`Controller::process`] and return it.
25///
26/// Set `status_code` and `reason_phrase` from [`STATUS_CODE_REASON_PHRASE`],
27/// push body content via [`Range::get_content_range`] into `content_range_list`,
28/// and add any extra headers to `headers`.
29///
30/// For large files, set `stream_file` to the absolute file path instead of loading
31/// the body into `content_range_list`. The server will stream it with
32/// `Transfer-Encoding: chunked` so memory usage stays constant regardless of file size.
33#[derive(PartialEq, Eq, Clone, Debug)]
34pub struct Response {
35    /// HTTP version string, e.g. `"HTTP/1.1"`.
36    pub http_version: String,
37    /// Numeric status code, e.g. `200`. Set from [`STATUS_CODE_REASON_PHRASE`].
38    pub status_code: i16,
39    /// Reason phrase, e.g. `"OK"`. Set from [`STATUS_CODE_REASON_PHRASE`].
40    pub reason_phrase: String,
41    /// Response headers. Pre-populated with standard headers by [`Header::get_header_list`].
42    pub headers: Vec<Header>,
43    /// Response body as a list of content ranges (supports multipart and range responses).
44    pub content_range_list: Vec<ContentRange>,
45    /// If set, the server streams this file with `Transfer-Encoding: chunked`
46    /// instead of using `content_range_list`. Use for files larger than ~8 MB.
47    pub stream_file: Option<String>,
48}
49
50#[derive(PartialEq, Eq, Clone, Debug)]
51pub struct StatusCodeReasonPhrase {
52    pub status_code: &'static i16,
53    pub reason_phrase: &'static str,
54}
55
56#[derive(PartialEq, Eq, Clone, Debug)]
57pub struct ResponseStatusCodeReasonPhrase {
58    pub n100_continue: &'static StatusCodeReasonPhrase,
59    pub n101_switching_protocols: &'static StatusCodeReasonPhrase,
60    pub n102_processing: &'static StatusCodeReasonPhrase,
61    pub n103_early_hints: &'static StatusCodeReasonPhrase,
62    pub n200_ok: &'static StatusCodeReasonPhrase,
63    pub n201_created: &'static StatusCodeReasonPhrase,
64    pub n202_accepted: &'static StatusCodeReasonPhrase,
65    pub n203_non_authoritative_information: &'static StatusCodeReasonPhrase,
66    pub n204_no_content: &'static StatusCodeReasonPhrase,
67    pub n205_reset_content: &'static StatusCodeReasonPhrase,
68    pub n206_partial_content: &'static StatusCodeReasonPhrase,
69    pub n207_multi_status: &'static StatusCodeReasonPhrase,
70    pub n208_already_reported: &'static StatusCodeReasonPhrase,
71    pub n226_im_used: &'static StatusCodeReasonPhrase,
72    pub n300_multiple_choices: &'static StatusCodeReasonPhrase,
73    pub n301_moved_permanently: &'static StatusCodeReasonPhrase,
74    pub n302_found: &'static StatusCodeReasonPhrase,
75    pub n303_see_other: &'static StatusCodeReasonPhrase,
76    pub n304_not_modified: &'static StatusCodeReasonPhrase,
77    pub n307_temporary_redirect: &'static StatusCodeReasonPhrase,
78    pub n308_permanent_redirect: &'static StatusCodeReasonPhrase,
79    pub n400_bad_request: &'static StatusCodeReasonPhrase,
80    pub n401_unauthorized: &'static StatusCodeReasonPhrase,
81    pub n402_payment_required: &'static StatusCodeReasonPhrase,
82    pub n403_forbidden: &'static StatusCodeReasonPhrase,
83    pub n404_not_found: &'static StatusCodeReasonPhrase,
84    pub n405_method_not_allowed: &'static StatusCodeReasonPhrase,
85    pub n406_not_acceptable: &'static StatusCodeReasonPhrase,
86    pub n407_proxy_authentication_required: &'static StatusCodeReasonPhrase,
87    pub n408_request_timeout: &'static StatusCodeReasonPhrase,
88    pub n409_conflict: &'static StatusCodeReasonPhrase,
89    pub n410_gone: &'static StatusCodeReasonPhrase,
90    pub n411_length_required: &'static StatusCodeReasonPhrase,
91    pub n412_precondition_failed: &'static StatusCodeReasonPhrase,
92    pub n413_payload_too_large: &'static StatusCodeReasonPhrase,
93    pub n414_uri_too_long: &'static StatusCodeReasonPhrase,
94    pub n415_unsupported_media_type: &'static StatusCodeReasonPhrase,
95    pub n416_range_not_satisfiable: &'static StatusCodeReasonPhrase,
96    pub n417_expectation_failed: &'static StatusCodeReasonPhrase,
97    pub n418_im_a_teapot: &'static StatusCodeReasonPhrase,
98    pub n421_misdirected_request: &'static StatusCodeReasonPhrase,
99    pub n422_unprocessable_entity: &'static StatusCodeReasonPhrase,
100    pub n423_locked: &'static StatusCodeReasonPhrase,
101    pub n424_failed_dependency: &'static StatusCodeReasonPhrase,
102    pub n425_too_early: &'static StatusCodeReasonPhrase,
103    pub n426_upgrade_required: &'static StatusCodeReasonPhrase,
104    pub n428_precondition_required: &'static StatusCodeReasonPhrase,
105    pub n429_too_many_requests: &'static StatusCodeReasonPhrase,
106    pub n431_request_header_fields_too_large: &'static StatusCodeReasonPhrase,
107    pub n451_unavailable_for_legal_reasons: &'static StatusCodeReasonPhrase,
108    pub n500_internal_server_error: &'static StatusCodeReasonPhrase,
109    pub n501_not_implemented: &'static StatusCodeReasonPhrase,
110    pub n502_bad_gateway: &'static StatusCodeReasonPhrase,
111    pub n503_service_unavailable: &'static StatusCodeReasonPhrase,
112    pub n504_gateway_timeout: &'static StatusCodeReasonPhrase,
113    pub n505_http_version_not_supported: &'static StatusCodeReasonPhrase,
114    pub n506_variant_also_negotiates: &'static StatusCodeReasonPhrase,
115    pub n507_insufficient_storage: &'static StatusCodeReasonPhrase,
116    pub n508_loop_detected: &'static StatusCodeReasonPhrase,
117    pub n510_not_extended: &'static StatusCodeReasonPhrase,
118    pub n511_network_authentication_required: &'static StatusCodeReasonPhrase,
119}
120
121pub const STATUS_CODE_REASON_PHRASE: ResponseStatusCodeReasonPhrase = ResponseStatusCodeReasonPhrase {
122    n100_continue: &StatusCodeReasonPhrase { status_code: &100, reason_phrase: "Continue" },
123    n101_switching_protocols: &StatusCodeReasonPhrase { status_code: &101, reason_phrase: "Switching Protocols" },
124    n102_processing: &StatusCodeReasonPhrase { status_code: &102, reason_phrase: "Processing" },
125    n103_early_hints: &StatusCodeReasonPhrase { status_code: &103, reason_phrase: "Early Hints" },
126    n200_ok: &StatusCodeReasonPhrase {
127        status_code: &200,
128        reason_phrase: "OK"
129    },
130
131    n201_created: &StatusCodeReasonPhrase { status_code: &201, reason_phrase: "Created" },
132    n202_accepted: &StatusCodeReasonPhrase { status_code: &202, reason_phrase: "Accepted" },
133    n203_non_authoritative_information: &StatusCodeReasonPhrase { status_code: &203, reason_phrase: "Non Authoritative Information" },
134    n204_no_content: &StatusCodeReasonPhrase {
135        status_code: &204,
136        reason_phrase: "No Content"
137    },
138
139    n205_reset_content: &StatusCodeReasonPhrase { status_code: &205, reason_phrase: "Reset Content" },
140    n206_partial_content: &StatusCodeReasonPhrase {
141        status_code: &206,
142        reason_phrase: "Partial Content"
143    },
144
145    n207_multi_status: &StatusCodeReasonPhrase { status_code: &207, reason_phrase: "Multi-Status" },
146    n208_already_reported: &StatusCodeReasonPhrase { status_code: &208, reason_phrase: "Already Reported" },
147    n226_im_used: &StatusCodeReasonPhrase { status_code: &226, reason_phrase: "IM Used" },
148    n300_multiple_choices: &StatusCodeReasonPhrase { status_code: &300, reason_phrase: "Multiple Choices" },
149    n301_moved_permanently: &StatusCodeReasonPhrase { status_code: &301, reason_phrase: "Moved Permanently" },
150    n302_found: &StatusCodeReasonPhrase { status_code: &302, reason_phrase: "Found" },
151    n303_see_other: &StatusCodeReasonPhrase { status_code: &303, reason_phrase: "See Other" },
152    n304_not_modified: &StatusCodeReasonPhrase { status_code: &304, reason_phrase: "Not Modified" },
153    n307_temporary_redirect: &StatusCodeReasonPhrase { status_code: &307, reason_phrase: "Temporary Redirect" },
154    n308_permanent_redirect: &StatusCodeReasonPhrase { status_code: &308, reason_phrase: "Permanent Redirect" },
155    n400_bad_request: &StatusCodeReasonPhrase {
156        status_code: &400,
157        reason_phrase: "Bad Request"
158    },
159
160    n401_unauthorized: &StatusCodeReasonPhrase { status_code: &401, reason_phrase: "Unauthorized" },
161    n402_payment_required: &StatusCodeReasonPhrase { status_code: &402, reason_phrase: "Payment Required" },
162    n403_forbidden: &StatusCodeReasonPhrase { status_code: &403, reason_phrase: "Forbidden" },
163    n404_not_found: &StatusCodeReasonPhrase {
164        status_code: &404,
165        reason_phrase: "Not Found"
166    },
167
168    n405_method_not_allowed: &StatusCodeReasonPhrase { status_code: &405, reason_phrase: "Method Not Allowed" },
169    n406_not_acceptable: &StatusCodeReasonPhrase { status_code: &406, reason_phrase: "Not Acceptable" },
170    n407_proxy_authentication_required: &StatusCodeReasonPhrase { status_code: &407, reason_phrase: "Proxy Authentication Required" },
171    n408_request_timeout: &StatusCodeReasonPhrase { status_code: &408, reason_phrase: "Request Timeout" },
172    n409_conflict: &StatusCodeReasonPhrase { status_code: &409, reason_phrase: "Conflict" },
173    n410_gone: &StatusCodeReasonPhrase { status_code: &410, reason_phrase: "Gone" },
174    n411_length_required: &StatusCodeReasonPhrase { status_code: &411, reason_phrase: "Length Required" },
175    n412_precondition_failed: &StatusCodeReasonPhrase { status_code: &412, reason_phrase: "Precondition Failed" },
176    n413_payload_too_large: &StatusCodeReasonPhrase { status_code: &413, reason_phrase: "Payload Too Large" },
177    n414_uri_too_long: &StatusCodeReasonPhrase { status_code: &414, reason_phrase: "URI Too Long" },
178    n415_unsupported_media_type: &StatusCodeReasonPhrase { status_code: &415, reason_phrase: "Unsupported Media Type" },
179    n416_range_not_satisfiable: &StatusCodeReasonPhrase {
180        status_code: &416,
181        reason_phrase: "Range Not Satisfiable"
182    },
183
184    n417_expectation_failed: &StatusCodeReasonPhrase { status_code: &417, reason_phrase: "Expectation Failed" },
185    n418_im_a_teapot: &StatusCodeReasonPhrase { status_code: &418, reason_phrase: "I'm A Teapot" },
186    n421_misdirected_request: &StatusCodeReasonPhrase { status_code: &421, reason_phrase: "Misdirected Request" },
187    n422_unprocessable_entity: &StatusCodeReasonPhrase { status_code: &422, reason_phrase: "Unprocessable Entity" },
188    n423_locked: &StatusCodeReasonPhrase { status_code: &423, reason_phrase: "Locked" },
189    n424_failed_dependency: &StatusCodeReasonPhrase { status_code: &424, reason_phrase: "Failed Dependency" },
190    n425_too_early: &StatusCodeReasonPhrase { status_code: &425, reason_phrase: "Too Early" },
191    n426_upgrade_required: &StatusCodeReasonPhrase { status_code: &426, reason_phrase: "Upgrade Required" },
192    n428_precondition_required: &StatusCodeReasonPhrase { status_code: &428, reason_phrase: "Precondition Required" },
193    n429_too_many_requests: &StatusCodeReasonPhrase { status_code: &429, reason_phrase: "Too Many Requests" },
194    n431_request_header_fields_too_large: &StatusCodeReasonPhrase { status_code: &431, reason_phrase: "Request Header Fields Too Large" },
195    n451_unavailable_for_legal_reasons: &StatusCodeReasonPhrase { status_code: &451, reason_phrase: "Unavailable For Legal Reasons" },
196    n500_internal_server_error: &StatusCodeReasonPhrase {
197        status_code: &500,
198        reason_phrase: "Internal Server Error"
199    },
200    n501_not_implemented: &StatusCodeReasonPhrase { status_code: &501, reason_phrase: "Not Implemented" },
201    n502_bad_gateway: &StatusCodeReasonPhrase { status_code: &502, reason_phrase: "Bad Gateway" },
202    n503_service_unavailable: &StatusCodeReasonPhrase { status_code: &503, reason_phrase: "Service Unavailable" },
203    n504_gateway_timeout: &StatusCodeReasonPhrase { status_code: &504, reason_phrase: "Gateway Timeout" },
204    n505_http_version_not_supported: &StatusCodeReasonPhrase { status_code: &505, reason_phrase: "HTTP Version Not Supported" },
205    n506_variant_also_negotiates: &StatusCodeReasonPhrase { status_code: &506, reason_phrase: "Variant Also Negotiates" },
206    n507_insufficient_storage: &StatusCodeReasonPhrase { status_code: &507, reason_phrase: "Insufficient Storage" },
207    n508_loop_detected: &StatusCodeReasonPhrase { status_code: &508, reason_phrase: "Loop Detected" },
208    n510_not_extended: &StatusCodeReasonPhrase { status_code: &510, reason_phrase: "Not Extended" },
209    n511_network_authentication_required: &StatusCodeReasonPhrase { status_code: &511, reason_phrase: "Network Authentication Required" }
210};
211
212impl Response {
213
214    pub fn build(status: StatusCodeReasonPhrase, header_list : Vec<Header>, body: Vec<ContentRange>) -> Response {
215        Response {
216            http_version: VERSION.http_1_1.to_string(),
217            status_code: *status.status_code,
218            reason_phrase: status.reason_phrase.to_string(),
219            headers: header_list,
220            content_range_list: body,
221            stream_file: None,
222        }
223    }
224
225    pub fn status_code_reason_phrase_list() -> Vec<&'static StatusCodeReasonPhrase> {
226        let list = vec![
227            STATUS_CODE_REASON_PHRASE.n100_continue,
228            STATUS_CODE_REASON_PHRASE.n101_switching_protocols,
229            STATUS_CODE_REASON_PHRASE.n102_processing,
230            STATUS_CODE_REASON_PHRASE.n103_early_hints,
231            STATUS_CODE_REASON_PHRASE.n200_ok,
232            STATUS_CODE_REASON_PHRASE.n201_created,
233            STATUS_CODE_REASON_PHRASE.n202_accepted,
234            STATUS_CODE_REASON_PHRASE.n203_non_authoritative_information,
235            STATUS_CODE_REASON_PHRASE.n204_no_content,
236            STATUS_CODE_REASON_PHRASE.n205_reset_content,
237            STATUS_CODE_REASON_PHRASE.n206_partial_content,
238            STATUS_CODE_REASON_PHRASE.n207_multi_status,
239            STATUS_CODE_REASON_PHRASE.n208_already_reported,
240            STATUS_CODE_REASON_PHRASE.n226_im_used,
241            STATUS_CODE_REASON_PHRASE.n300_multiple_choices,
242            STATUS_CODE_REASON_PHRASE.n301_moved_permanently,
243            STATUS_CODE_REASON_PHRASE.n302_found,
244            STATUS_CODE_REASON_PHRASE.n303_see_other,
245            STATUS_CODE_REASON_PHRASE.n304_not_modified,
246            STATUS_CODE_REASON_PHRASE.n307_temporary_redirect,
247            STATUS_CODE_REASON_PHRASE.n308_permanent_redirect,
248            STATUS_CODE_REASON_PHRASE.n400_bad_request,
249            STATUS_CODE_REASON_PHRASE.n401_unauthorized,
250            STATUS_CODE_REASON_PHRASE.n402_payment_required,
251            STATUS_CODE_REASON_PHRASE.n403_forbidden,
252            STATUS_CODE_REASON_PHRASE.n404_not_found,
253            STATUS_CODE_REASON_PHRASE.n405_method_not_allowed,
254            STATUS_CODE_REASON_PHRASE.n406_not_acceptable,
255            STATUS_CODE_REASON_PHRASE.n407_proxy_authentication_required,
256            STATUS_CODE_REASON_PHRASE.n408_request_timeout,
257            STATUS_CODE_REASON_PHRASE.n409_conflict,
258            STATUS_CODE_REASON_PHRASE.n410_gone,
259            STATUS_CODE_REASON_PHRASE.n411_length_required,
260            STATUS_CODE_REASON_PHRASE.n412_precondition_failed,
261            STATUS_CODE_REASON_PHRASE.n413_payload_too_large,
262            STATUS_CODE_REASON_PHRASE.n414_uri_too_long,
263            STATUS_CODE_REASON_PHRASE.n415_unsupported_media_type,
264            STATUS_CODE_REASON_PHRASE.n416_range_not_satisfiable,
265            STATUS_CODE_REASON_PHRASE.n417_expectation_failed,
266            STATUS_CODE_REASON_PHRASE.n418_im_a_teapot,
267            STATUS_CODE_REASON_PHRASE.n421_misdirected_request,
268            STATUS_CODE_REASON_PHRASE.n422_unprocessable_entity,
269            STATUS_CODE_REASON_PHRASE.n423_locked,
270            STATUS_CODE_REASON_PHRASE.n424_failed_dependency,
271            STATUS_CODE_REASON_PHRASE.n425_too_early,
272            STATUS_CODE_REASON_PHRASE.n426_upgrade_required,
273            STATUS_CODE_REASON_PHRASE.n428_precondition_required,
274            STATUS_CODE_REASON_PHRASE.n429_too_many_requests,
275            STATUS_CODE_REASON_PHRASE.n431_request_header_fields_too_large,
276            STATUS_CODE_REASON_PHRASE.n451_unavailable_for_legal_reasons,
277            STATUS_CODE_REASON_PHRASE.n500_internal_server_error,
278            STATUS_CODE_REASON_PHRASE.n501_not_implemented,
279            STATUS_CODE_REASON_PHRASE.n502_bad_gateway,
280            STATUS_CODE_REASON_PHRASE.n503_service_unavailable,
281            STATUS_CODE_REASON_PHRASE.n504_gateway_timeout,
282            STATUS_CODE_REASON_PHRASE.n505_http_version_not_supported,
283            STATUS_CODE_REASON_PHRASE.n506_variant_also_negotiates,
284            STATUS_CODE_REASON_PHRASE.n507_insufficient_storage,
285            STATUS_CODE_REASON_PHRASE.n508_loop_detected,
286            STATUS_CODE_REASON_PHRASE.n510_not_extended,
287            STATUS_CODE_REASON_PHRASE.n511_network_authentication_required,
288        ];
289        list
290    }
291
292    pub const _ERROR_UNABLE_TO_PARSE_HTTP_VERSION_STATUS_CODE: &'static str = "Unable to parse status code";
293
294    pub const _HTTP_VERSION_AND_STATUS_CODE_AND_REASON_PHRASE_REGEX: &'static str = "(?P<http_version>\\w+/\\w+.\\w)\\s(?P<status_code>\\w+)\\s(?P<reason_phrase>.+)";
295
296    pub fn _get_header(&self, name: String) -> Option<&Header> {
297        let header =  self.headers.iter().find(|x| x.name == name);
298        header
299    }
300
301    pub fn generate_body(content_range_list: Vec<ContentRange>) -> Vec<u8> {
302        let mut body = vec![];
303        let one = 1;
304
305        if content_range_list.len() == one {
306            let index = 0;
307            let content_range = content_range_list.get(index).unwrap();
308            body = content_range.body.to_vec();
309        }
310
311        if content_range_list.len() > one {
312            for (i, content_range) in content_range_list.iter().enumerate() {
313                let mut body_str = SYMBOL.empty_string.to_string();
314                if i != 0 {
315                    body_str.push_str(SYMBOL.new_line_carriage_return);
316                }
317                body_str.push_str(SYMBOL.hyphen);
318                body_str.push_str(SYMBOL.hyphen);
319                body_str.push_str(Range::STRING_SEPARATOR);
320                body_str.push_str(SYMBOL.new_line_carriage_return);
321                let content_type = [Header::_CONTENT_TYPE, Header::NAME_VALUE_SEPARATOR, SYMBOL.whitespace, &content_range.content_type.to_string()].join("");
322                body_str.push_str(content_type.as_str());
323                body_str.push_str(SYMBOL.new_line_carriage_return);
324                let content_range_header = [Header::_CONTENT_RANGE, Header::NAME_VALUE_SEPARATOR, SYMBOL.whitespace, Range::BYTES, SYMBOL.whitespace, &content_range.range.start.to_string(), SYMBOL.hyphen, &content_range.range.end.to_string(), SYMBOL.slash, &content_range.size].join("");
325                body_str.push_str(content_range_header.as_str());
326                body_str.push_str(SYMBOL.new_line_carriage_return);
327                body_str.push_str(SYMBOL.new_line_carriage_return);
328
329                let inner_body = [body_str.as_bytes(), &content_range.body].concat();
330                body = [body, inner_body].concat();
331            }
332            let mut trailing_separator = SYMBOL.empty_string.to_string();
333            trailing_separator.push_str(SYMBOL.new_line_carriage_return);
334            trailing_separator.push_str(SYMBOL.hyphen);
335            trailing_separator.push_str(SYMBOL.hyphen);
336            trailing_separator.push_str(Range::STRING_SEPARATOR);
337            body = [&body, trailing_separator.as_bytes()].concat();
338        }
339
340        body
341    }
342
343    pub fn generate_response(mut response: Response, request: Request) -> Vec<u8> {
344
345        if response.content_range_list.len() == 1 {
346            let content_range_index = 0;
347            let content_range = response.content_range_list.get(content_range_index).unwrap();
348            response.headers.push(Header {
349                name: Header::_CONTENT_TYPE.to_string(),
350                value: content_range.content_type.to_string()
351            });
352
353            let content_range_header_value = [
354                Range::BYTES,
355                SYMBOL.whitespace,
356                &content_range.range.start.to_string(),
357                SYMBOL.hyphen,
358                &content_range.range.end.to_string(),
359                SYMBOL.slash,
360                &content_range.size
361            ].join("");
362            response.headers.push(Header {
363                name: Header::_CONTENT_RANGE.to_string(),
364                value: content_range_header_value.to_string()
365            });
366
367            response.headers.push(Header {
368                name: Header::_CONTENT_LENGTH.to_string(),
369                value: content_range.body.len().to_string()
370            });
371        }
372
373        if response.content_range_list.len() > 1 {
374            let content_range_header_value = [
375                Range::MULTIPART,
376                SYMBOL.slash,
377                Range::BYTERANGES,
378                SYMBOL.semicolon,
379                SYMBOL.whitespace,
380                Range::BOUNDARY,
381                SYMBOL.equals,
382                Range::STRING_SEPARATOR
383            ].join("");
384            response.headers.push(Header {
385                name: Header::_CONTENT_TYPE.to_string(),
386                value: content_range_header_value,
387            });
388        }
389
390        let body = Response::generate_body(response.content_range_list);
391
392        let mut headers_str = SYMBOL.new_line_carriage_return.to_string();
393        for header in response.headers {
394            let mut header_string = SYMBOL.empty_string.to_string();
395            header_string.push_str(&header.name);
396            header_string.push_str(Header::NAME_VALUE_SEPARATOR);
397            header_string.push_str(&header.value);
398            header_string.push_str(SYMBOL.new_line_carriage_return);
399            headers_str.push_str(&header_string);
400        }
401        let status = [response.http_version, response.status_code.to_string(), response.reason_phrase].join(SYMBOL.whitespace);
402        let response_without_body = format!(
403            "{}{}{}",
404            status,
405            headers_str,
406            SYMBOL.new_line_carriage_return,
407        );
408
409        let is_head = request.method == METHOD.head;
410        let is_options = request.method == METHOD.options;
411
412        return if is_head || is_options {
413            response_without_body.into_bytes()
414        } else {
415            [response_without_body.into_bytes(), body].concat()
416        }
417
418    }
419
420    pub fn _parse_response(response_vec_u8: &[u8]) -> Response {
421        let mut cursor = io::Cursor::new(response_vec_u8);
422
423        let mut response = Response {
424            http_version: "".to_string(),
425            status_code: 0,
426            reason_phrase: "".to_string(),
427            headers: vec![],
428            content_range_list: vec![],
429            stream_file: None,
430        };
431
432        let content_length: usize = 0;
433        let iteration_number : usize = 0;
434
435        Response::_parse_raw_response_via_cursor(&mut cursor, iteration_number, &mut response, content_length);
436
437        return response;
438    }
439
440    pub fn _parse_http_version_status_code_reason_phrase_string(http_version_status_code_reason_phrase: &str) -> Result<(String, i16, String), String> {
441        let truncated = StringExt::truncate_new_line_carriage_return(http_version_status_code_reason_phrase);
442
443        let boxed_split = truncated.split_once(SYMBOL.whitespace);
444        if boxed_split.is_none() {
445            return Err(Response::_ERROR_UNABLE_TO_PARSE_HTTP_VERSION_STATUS_CODE.to_string())
446        }
447
448        let (http_version, status_code_reason_phrase) = boxed_split.unwrap();
449        let supported_http_versions = HTTP::version_list();
450        if !supported_http_versions.contains(&http_version.to_uppercase().to_string()) {
451            return Err(Response::_ERROR_UNABLE_TO_PARSE_HTTP_VERSION_STATUS_CODE.to_string())
452        }
453
454        let boxed_split = status_code_reason_phrase.split_once(SYMBOL.whitespace);
455        if boxed_split.is_none() {
456            return Err(Response::_ERROR_UNABLE_TO_PARSE_HTTP_VERSION_STATUS_CODE.to_string())
457        }
458        let (status_code, reason_phrase) = boxed_split.unwrap();
459
460        let boxed_status_code_i16 = status_code.parse::<i16>();
461        if boxed_status_code_i16.is_err() {
462            return Err(Response::_ERROR_UNABLE_TO_PARSE_HTTP_VERSION_STATUS_CODE.to_string())
463        }
464
465        let status_code_i16 = boxed_status_code_i16.unwrap();
466
467        let list = Response::status_code_reason_phrase_list();
468        let boxed_search =
469            list
470                .iter()
471                .find(|x| {
472                    return x.status_code == &status_code_i16
473                });
474
475        if boxed_search.is_none() {
476            return Err(Response::_ERROR_UNABLE_TO_PARSE_HTTP_VERSION_STATUS_CODE.to_string())
477        }
478
479        let found_status_code_reason_phrase = boxed_search.unwrap();
480        let uppercase_reason_phrase = reason_phrase.to_uppercase();
481        let is_equal =
482            &found_status_code_reason_phrase.reason_phrase
483            .to_uppercase()
484                .eq(uppercase_reason_phrase.as_str());
485
486        if !is_equal {
487            return Err(Response::_ERROR_UNABLE_TO_PARSE_HTTP_VERSION_STATUS_CODE.to_string())
488        }
489
490        return Ok((http_version.to_string(), status_code_i16, reason_phrase.to_string()))
491    }
492
493    pub fn _parse_http_response_header_string(header_string: &str) -> Header {
494        let header_parts: Vec<&str> = header_string.split(Header::NAME_VALUE_SEPARATOR).collect();
495        let header_name = header_parts[0].to_string();
496        let raw_header_value = header_parts[1].to_string();
497        let header_value = StringExt::truncate_new_line_carriage_return(&raw_header_value);
498
499
500        Header {
501            name: header_name.to_string(),
502            value: header_value.to_string()
503        }
504    }
505
506    pub fn _parse_raw_response_via_cursor(
507        cursor: &mut Cursor<&[u8]>,
508        mut iteration_number: usize,
509        response: &mut Response,
510        mut content_length: usize) {
511
512        let mut buffer = vec![];
513        let boxed_read = cursor.read_until(b'\n', &mut buffer);
514        if boxed_read.is_err() {
515            eprintln!("unable to parse raw response via cursor {}", boxed_read.err().unwrap());
516            return;
517        }
518        let bytes_offset = boxed_read.unwrap();
519        let mut buffer_as_u8_array: &[u8] = &buffer;
520        let string = String::from_utf8(Vec::from(buffer_as_u8_array)).unwrap();
521
522        let is_first_iteration = iteration_number == 0;
523        let new_line_char_found = bytes_offset != 0;
524        let current_string_is_empty = string.trim().len() == 0;
525
526        if is_first_iteration {
527            let boxed_http_version_status_code_reason_phrase = Response::_parse_http_version_status_code_reason_phrase_string(&string);
528            if boxed_http_version_status_code_reason_phrase.is_err() {
529                let error = boxed_http_version_status_code_reason_phrase.err().unwrap();
530                eprintln!("{}", error);
531                return;
532            }
533
534            let (http_version, status_code, reason_phrase) = boxed_http_version_status_code_reason_phrase.unwrap();
535
536            response.http_version = http_version;
537            response.status_code = status_code;
538            response.reason_phrase = reason_phrase;
539        }
540
541        if current_string_is_empty {
542            let content_type = response._get_header(Header::_CONTENT_TYPE.to_string()).unwrap();
543            let is_multipart = Response::_is_multipart_byteranges_content_type(&content_type);
544
545            if is_multipart {
546                let content_range_list : Vec<ContentRange> = vec![];
547
548                let mut buf = vec![];
549                cursor.read_until(b'\n', &mut buf).unwrap();
550                let boxed_value = Range::_parse_multipart_body(cursor, content_range_list);
551                let mut range_list = vec![];
552                if boxed_value.is_ok() {
553                    range_list = boxed_value.unwrap();
554                }
555                response.content_range_list = range_list;
556            } else {
557                buffer = vec![];
558                let boxed_read = cursor.read_to_end(&mut buffer);
559                if boxed_read.is_ok() {
560                    buffer_as_u8_array = &buffer;
561
562                    let content_range = ContentRange {
563                        unit: Range::BYTES.to_string(),
564                        range: Range {
565                            start: 0,
566                            end: buffer_as_u8_array.len() as u64
567                        },
568                        size: buffer_as_u8_array.len().to_string(),
569                        body: Vec::from(buffer_as_u8_array),
570                        content_type: content_type.value.to_string()
571                    };
572                    response.content_range_list = vec![content_range];
573                } else {
574                    let reason = boxed_read.err().unwrap();
575                    eprintln!("error reading file: {}", reason.to_string())
576                }
577
578            }
579
580            return;
581        }
582
583        if new_line_char_found && !current_string_is_empty {
584            let mut header = Header { name: "".to_string(), value: "".to_string() };
585            if !is_first_iteration {
586                header = Response::_parse_http_response_header_string(&string);
587                if header.name == Header::_CONTENT_LENGTH {
588                    content_length = header.value.parse().unwrap();
589                }
590            }
591
592            response.headers.push(header);
593            iteration_number += 1;
594            Response::_parse_raw_response_via_cursor(cursor, iteration_number, response, content_length);
595        }
596    }
597
598    pub fn _is_multipart_byteranges_content_type(content_type: &Header) -> bool {
599        let multipart_byteranges =
600            [
601                Range::MULTIPART,
602                SYMBOL.slash,
603                Range::BYTERANGES
604            ].join("");
605        let is_multipart_byteranges = content_type.value.starts_with(&multipart_byteranges);
606        is_multipart_byteranges
607    }
608
609
610    pub fn get_response(
611        status_code_reason_phrase: &StatusCodeReasonPhrase,
612        boxed_header_list: Option<Vec<Header>>,
613        boxed_content_range_list: Option<Vec<ContentRange>>) -> Response {
614
615        let mut header_list: Vec<Header> = vec![];
616        if boxed_header_list.is_some() {
617            header_list = boxed_header_list.unwrap();
618        }
619
620        let mut content_range_list: Vec<ContentRange> = vec![];
621        if boxed_content_range_list.is_some() {
622            content_range_list = boxed_content_range_list.unwrap();
623        }
624
625        let response = Response {
626            http_version: VERSION.http_1_1.to_string(),
627            status_code: *status_code_reason_phrase.status_code,
628            reason_phrase: status_code_reason_phrase.reason_phrase.to_string(),
629            headers: header_list,
630            content_range_list,
631            stream_file: None,
632        };
633
634        response
635    }
636
637    pub fn generate(&mut self) -> Vec<u8> {
638        let response = &mut self.clone();
639
640        if response.content_range_list.len() == 1 {
641            let content_range_index = 0;
642            let content_range = response.content_range_list.get(content_range_index).unwrap();
643            self.headers.push(Header {
644                name: Header::_CONTENT_TYPE.to_string(),
645                value: content_range.content_type.to_string()
646            });
647
648            let content_range_header_value = [
649                Range::BYTES,
650                SYMBOL.whitespace,
651                &content_range.range.start.to_string(),
652                SYMBOL.hyphen,
653                &content_range.range.end.to_string(),
654                SYMBOL.slash,
655                &content_range.size
656            ].join("");
657            response.headers.push(Header {
658                name: Header::_CONTENT_RANGE.to_string(),
659                value: content_range_header_value.to_string()
660            });
661
662            response.headers.push(Header {
663                name: Header::_CONTENT_LENGTH.to_string(),
664                value: content_range.body.len().to_string()
665            });
666        }
667
668        if response.content_range_list.len() > 1 {
669            let content_range_header_value = [
670                Range::MULTIPART,
671                SYMBOL.slash,
672                Range::BYTERANGES,
673                SYMBOL.semicolon,
674                SYMBOL.whitespace,
675                Range::BOUNDARY,
676                SYMBOL.equals,
677                Range::STRING_SEPARATOR
678            ].join("");
679            response.headers.push(Header {
680                name: Header::_CONTENT_TYPE.to_string(),
681                value: content_range_header_value,
682            });
683        }
684
685        let response_clone = response.clone();
686        let body = Response::generate_body(response_clone.content_range_list);
687
688        let mut headers_str = SYMBOL.new_line_carriage_return.to_string();
689
690        let header_list = response.headers.clone();
691        for header in header_list {
692            let mut header_string = SYMBOL.empty_string.to_string();
693            header_string.push_str(&header.name);
694            header_string.push_str(Header::NAME_VALUE_SEPARATOR);
695            header_string.push_str(&header.value);
696            header_string.push_str(SYMBOL.new_line_carriage_return);
697            headers_str.push_str(&header_string);
698        }
699
700        let response_clone = response.clone();
701        let status = [response_clone.http_version, response.status_code.to_string(), response_clone.reason_phrase].join(SYMBOL.whitespace);
702        let response_without_body = format!(
703            "{}{}{}",
704            status,
705            headers_str,
706            SYMBOL.new_line_carriage_return,
707        );
708
709
710        [response_without_body.into_bytes(), body].concat()
711    }
712
713    pub fn get_header(&self, name: String) -> Option<&Header> {
714        self._get_header(name)
715    }
716
717    pub fn parse(response_vec_u8: &[u8]) -> Result<Response, String> {
718        let total_bytes : i32 = response_vec_u8.len() as i32;
719        let bytes_read = 0;
720        let mut cursor = io::Cursor::new(response_vec_u8);
721
722        let mut response = Response {
723            http_version: "".to_string(),
724            status_code: 0,
725            reason_phrase: "".to_string(),
726            headers: vec![],
727            content_range_list: vec![],
728            stream_file: None,
729        };
730
731        let content_length: usize = 0;
732        let iteration_number : usize = 0;
733
734        let boxed_parse = Response::parse_raw_response_via_cursor(
735            &mut cursor, iteration_number,
736            &mut response,
737            content_length,
738            total_bytes,
739            bytes_read
740        );
741        if boxed_parse.is_err() {
742            let message = boxed_parse.err().unwrap();
743            return Err(message);
744        }
745
746        return Ok(response);
747    }
748
749    pub fn parse_raw_response_via_cursor(
750        cursor: &mut Cursor<&[u8]>,
751        mut iteration_number: usize,
752        response: &mut Response,
753        mut content_length: usize,
754        total_bytes: i32,
755        mut bytes_read: i32) -> Result<(), String> {
756
757        let mut buffer = vec![];
758        let boxed_read = cursor.read_until(b'\n', &mut buffer);
759        if boxed_read.is_err() {
760            let message = format!("unable to parse raw response via cursor {}", boxed_read.err().unwrap());
761            return Err(message);
762        }
763        let bytes_offset = boxed_read.unwrap();
764        bytes_read = bytes_read + bytes_offset as i32;
765        if bytes_read == total_bytes {
766            // end of stream
767        }
768        let mut buffer_as_u8_array: &[u8] = &buffer;
769        let boxed_string = String::from_utf8(Vec::from(buffer_as_u8_array));
770        if boxed_string.is_err() {
771            let message = boxed_string.err().unwrap().to_string();
772            return Err(message);
773        }
774        let string = boxed_string.unwrap();
775
776        let is_first_iteration = iteration_number == 0;
777        let new_line_char_found = bytes_offset != 0;
778        let current_string_is_empty = string.trim().len() == 0;
779
780        if is_first_iteration {
781            let boxed_http_version_status_code_reason_phrase = Response::_parse_http_version_status_code_reason_phrase_string(&string);
782            if boxed_http_version_status_code_reason_phrase.is_err() {
783                let message = boxed_http_version_status_code_reason_phrase.err().unwrap();
784                return Err(message);
785            }
786
787            let (http_version, status_code, reason_phrase) = boxed_http_version_status_code_reason_phrase.unwrap();
788
789            response.http_version = http_version;
790            response.status_code = status_code;
791            response.reason_phrase = reason_phrase;
792        }
793
794        if current_string_is_empty {
795            let mut is_multipart = false;
796            // if response does not contain Content-Type, it will be defaulted to APPLICATION_OCTET_STREAM
797            let mut content_type = MimeType::APPLICATION_OCTET_STREAM;
798
799            let boxed_content_type = response.get_header(Header::_CONTENT_TYPE.to_string());
800            if boxed_content_type.is_some() {
801                let content_type_header = response.get_header(Header::_CONTENT_TYPE.to_string()).unwrap();
802                content_type = content_type_header.value.as_str();
803                is_multipart = Response::_is_multipart_byteranges_content_type(&content_type_header);
804            }
805
806
807            if is_multipart {
808                let content_range_list : Vec<ContentRange> = vec![];
809                let boxed_content_type = response.get_header(Header::_CONTENT_TYPE.to_string());
810                if boxed_content_type.is_none() {
811                    return Err("Content-Type is missing".to_string());
812                }
813                let content_type = boxed_content_type.unwrap();
814                let boxed_boundary = FormMultipartData::extract_boundary(content_type.value.as_str());
815                if boxed_boundary.is_err() {
816                    return Err("unable to extract boundary from Content-Type".to_string());
817                }
818                let boundary = boxed_boundary.unwrap();
819
820                let is_opening_boundary_read = false;
821                let boxed_content_range_list =
822                    Range::parse_multipart_body_with_boundary(
823                        cursor,
824                        content_range_list,
825                        boundary,
826                        total_bytes,
827                        bytes_read,
828                        is_opening_boundary_read);
829                if boxed_content_range_list.is_err() {
830                    let message = boxed_content_range_list.err().unwrap();
831                    return Err(message);
832                }
833
834                response.content_range_list = boxed_content_range_list.unwrap();
835            } else {
836                buffer = vec![];
837                let boxed_read = cursor.read_to_end(&mut buffer);
838                if boxed_read.is_err() {
839                    let message = boxed_read.err().unwrap().to_string();
840                    return Err(message);
841                }
842                let bytes_offset = boxed_read.unwrap();
843                bytes_read = bytes_read + bytes_offset as i32;
844                if bytes_read == total_bytes {
845                    // end of stream
846                }
847
848                buffer_as_u8_array = &buffer;
849
850                let content_range = ContentRange {
851                    unit: Range::BYTES.to_string(),
852                    range: Range {
853                        start: 0,
854                        end: buffer_as_u8_array.len() as u64
855                    },
856                    size: buffer_as_u8_array.len().to_string(),
857                    body: Vec::from(buffer_as_u8_array),
858                    content_type: content_type.to_string()
859                };
860                response.content_range_list = vec![content_range];
861
862
863            }
864
865            return Ok(());
866        }
867
868        if new_line_char_found && !current_string_is_empty {
869            if !is_first_iteration {
870                let boxed_header = Response::parse_http_response_header_string(&string);
871                if boxed_header.is_err() {
872                    let message = boxed_header.err().unwrap();
873                    return Err(message);
874                }
875                let header = boxed_header.unwrap();
876                if header.name == Header::_CONTENT_LENGTH {
877                    content_length = header.value.parse().unwrap();
878                }
879                response.headers.push(header);
880            }
881
882            iteration_number += 1;
883            return Response::parse_raw_response_via_cursor(cursor, iteration_number, response, content_length, total_bytes, bytes_read );
884        } else {
885            return Err("unable to parse".to_string());
886        }
887    }
888
889    pub fn parse_http_response_header_string(header_string: &str) -> Result<Header, String> {
890        let header_parts: Option<(&str, &str)> = header_string.split_once(Header::NAME_VALUE_SEPARATOR);
891        if header_parts.is_none() {
892            let message = format!("unable to parse header: {}", header_string);
893            return Err(message);
894        }
895        let (header_name, raw_header_value) = header_parts.unwrap();
896        let header_value = StringExt::truncate_new_line_carriage_return(&raw_header_value);
897
898        Ok(Header {
899            name: header_name.to_string(),
900            value: header_value.to_string()
901        })
902    }
903}
904
905impl New for Response {
906    fn new() -> Self {
907        Response {
908            http_version: VERSION.http_1_1.to_string(),
909            status_code: *STATUS_CODE_REASON_PHRASE.n501_not_implemented.status_code,
910            reason_phrase: STATUS_CODE_REASON_PHRASE.n501_not_implemented.reason_phrase.to_string(),
911            headers: vec![],
912            content_range_list: vec![],
913            stream_file: None,
914        }
915    }
916}