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