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