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)]
34pub struct Response {
35 pub http_version: String,
37 pub status_code: i16,
39 pub reason_phrase: String,
41 pub headers: Vec<Header>,
43 pub content_range_list: Vec<ContentRange>,
45 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 }
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 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 }
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}