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 }
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 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 }
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}