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