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)]
30pub struct Response {
31 pub http_version: String,
33 pub status_code: i16,
35 pub reason_phrase: String,
37 pub headers: Vec<Header>,
39 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 }
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 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 }
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}