Skip to main content

rust_web_server/range/
mod.rs

1#[cfg(test)]
2mod tests;
3
4#[cfg(test)]
5mod example;
6
7use std::io::prelude::*;
8use std::fs::{metadata};
9use std::io::{Cursor};
10use file_ext::FileExt;
11use crate::core::New;
12
13use crate::response::{Error, Response, STATUS_CODE_REASON_PHRASE};
14use crate::header::Header;
15use crate::mime_type::MimeType;
16use crate::symbol::SYMBOL;
17use crate::url::URL;
18
19/// A byte range within a resource (`start..end`).
20#[derive(PartialEq, Eq, Clone, Debug)]
21pub struct Range {
22    pub start: u64,
23    pub end: u64,
24}
25
26/// A single body part. `Response.content_range_list` holds one or more of these.
27///
28/// Build one with [`Range::get_content_range`] (in-memory bytes) or
29/// [`Range::get_content_range_of_a_file`] (file on disk).
30#[derive(PartialEq, Eq, Clone, Debug)]
31pub struct ContentRange {
32    /// Range unit — always `"bytes"`.
33    pub unit: String,
34    pub range: Range,
35    /// Total resource size as a string.
36    pub size: String,
37    /// Raw body bytes.
38    pub body: Vec<u8>,
39    /// MIME type for this part. Use [`MimeType`] constants or [`MimeType::detect_mime_type`].
40    pub content_type: String,
41}
42
43impl New for ContentRange {
44    fn new() -> Self {
45        ContentRange {
46            unit: Range::BYTES.to_string(),
47            range: Range { start: 0, end: 0 },
48            size: "".to_string(),
49            body: vec![],
50            content_type: "".to_string()
51        }
52    }
53}
54
55impl Range {
56    pub const STRING_SEPARATOR: &'static str = "String_separator";
57    pub const BOUNDARY: &'static str = "boundary";
58    pub const BYTERANGES: &'static str = "byteranges";
59    pub const MULTIPART: &'static str = "multipart";
60    pub const BYTES: &'static str = "bytes";
61    pub const MULTIPART_BYTERANGES_CONTENT_TYPE: &'static str = "multipart/byteranges; boundary=String_separator";
62
63
64    pub const _ERROR_NO_EMPTY_LINE_BETWEEN_CONTENT_RANGE_HEADER_AND_BODY: &'static str = "no empty line between content range headers and body";
65    pub const _ERROR_UNABLE_TO_PARSE_CONTENT_RANGE: &'static str = "unable to parse content-range";
66
67    pub const ERROR_START_IS_AFTER_END_CONTENT_RANGE: &'static str = "start is after end in content range";
68    pub const ERROR_START_IS_BIGGER_THAN_FILESIZE_CONTENT_RANGE: &'static str = "start is bigger than filesize in content range";
69    pub const ERROR_END_IS_BIGGER_THAN_FILESIZE_CONTENT_RANGE: &'static str = "end is bigger than filesize in content range";
70    pub const ERROR_MALFORMED_RANGE_HEADER_WRONG_UNIT: &'static str = "range header malformed, most likely you have an error in unit statement";
71
72    pub const ERROR_UNABLE_TO_PARSE_RANGE_START: &'static str = "unable to parse range start";
73    pub const ERROR_UNABLE_TO_PARSE_RANGE_END: &'static str = "unable to parse range end";
74
75
76    /// Parse one `first-last` / `first-` / `-suffix` byte range against a
77    /// resource of `filelength` bytes (RFC 9110 §14.1.2). The returned `end`
78    /// is **inclusive** (`bytes=0-0` is one byte). A `last` past the end is
79    /// clamped to the last byte and a suffix longer than the resource selects
80    /// all of it; a range starting at or past the end, `first > last`, or any
81    /// range on an empty resource is `416 Range Not Satisfiable`.
82    pub fn parse_range_in_content_range(filelength: u64, range_str: &str) -> Result<Range, Error> {
83        let unsatisfiable = |message: &str| Error {
84            status_code_reason_phrase: STATUS_CODE_REASON_PHRASE.n416_range_not_satisfiable,
85            message: message.to_string(),
86        };
87
88        let (raw_start, raw_end) = match range_str.split_once(SYMBOL.hyphen) {
89            Some((start, end)) => (start.trim(), end.trim()),
90            None => return Err(unsatisfiable(Range::ERROR_UNABLE_TO_PARSE_RANGE_START)),
91        };
92        if filelength == 0 {
93            return Err(unsatisfiable(Range::ERROR_START_IS_BIGGER_THAN_FILESIZE_CONTENT_RANGE));
94        }
95        let last_byte = filelength - 1;
96
97        if raw_start.is_empty() {
98            // Suffix range: the final `raw_end` bytes.
99            let suffix: u64 = raw_end
100                .parse()
101                .map_err(|_| unsatisfiable(Range::ERROR_UNABLE_TO_PARSE_RANGE_END))?;
102            if suffix == 0 {
103                return Err(unsatisfiable(Range::ERROR_UNABLE_TO_PARSE_RANGE_END));
104            }
105            return Ok(Range { start: filelength.saturating_sub(suffix), end: last_byte });
106        }
107
108        let start: u64 = raw_start
109            .parse()
110            .map_err(|_| unsatisfiable(Range::ERROR_UNABLE_TO_PARSE_RANGE_START))?;
111        let requested_end: Option<u64> = if raw_end.is_empty() {
112            None
113        } else {
114            Some(raw_end.parse().map_err(|_| unsatisfiable(Range::ERROR_UNABLE_TO_PARSE_RANGE_END))?)
115        };
116        if requested_end.map_or(false, |end| start > end) {
117            return Err(unsatisfiable(Range::ERROR_START_IS_AFTER_END_CONTENT_RANGE));
118        }
119        if start > last_byte {
120            return Err(unsatisfiable(Range::ERROR_START_IS_BIGGER_THAN_FILESIZE_CONTENT_RANGE));
121        }
122        let end = requested_end.map_or(last_byte, |end| end.min(last_byte));
123        Ok(Range { start, end })
124    }
125
126    pub fn parse_content_range(filepath: &str, filelength: u64, raw_range_value: &str) -> Result<Vec<ContentRange>, Error> {
127        const INDEX_AFTER_UNIT_DECLARATION : usize = 1;
128        let mut content_range_list: Vec<ContentRange> = vec![];
129
130        let prefix = [Range::BYTES, SYMBOL.equals].join("");
131        if !raw_range_value.starts_with(prefix.as_str()) {
132            let message = Range::ERROR_MALFORMED_RANGE_HEADER_WRONG_UNIT.to_string();
133            let error = Error {
134                status_code_reason_phrase: STATUS_CODE_REASON_PHRASE.n416_range_not_satisfiable,
135                message,
136            };
137            return Err(error);
138        }
139
140        let split_raw_range_value: Vec<&str> = raw_range_value.split(SYMBOL.equals).collect();
141        let boxed_raw_bytes = split_raw_range_value.get(INDEX_AFTER_UNIT_DECLARATION);
142        if boxed_raw_bytes.is_none() {
143            let message = Range::ERROR_UNABLE_TO_PARSE_RANGE_START.to_string();
144            let error = Error {
145                status_code_reason_phrase: STATUS_CODE_REASON_PHRASE.n416_range_not_satisfiable,
146                message: message.to_string()
147            };
148            return Err(error)
149        }
150
151        let raw_bytes = boxed_raw_bytes.unwrap();
152
153        // Every range is parsed before any byte is read, then overlapping or
154        // adjacent ones are merged and too many become the whole file (#46):
155        // `bytes=0-,0-,0-,…` read the file into memory once per range.
156        let mut ranges: Vec<Range> = Vec::new();
157        for byte in raw_bytes.split(SYMBOL.comma) {
158            ranges.push(Range::parse_range_in_content_range(filelength, byte)?);
159        }
160        let ranges = Range::coalesce(ranges, filelength);
161        for range in ranges {
162            {
163                let boxed_read = FileExt::read_file_partially(filepath, range.start, range.end);
164                if boxed_read.is_ok() {
165
166                    let content_type = MimeType::detect_mime_type(filepath);
167                    let body = boxed_read.unwrap();
168                    let content_range = ContentRange {
169                        unit: Range::BYTES.to_string(),
170                        range,
171                        size: filelength.to_string(),
172                        body,
173                        content_type,
174                    };
175                    content_range_list.push(content_range);
176                } else {
177                    let error : Error = Error {
178                        status_code_reason_phrase:  STATUS_CODE_REASON_PHRASE.n416_range_not_satisfiable,
179                        message: boxed_read.err().unwrap().to_string()
180                    };
181                    return Err(error)
182                }
183            }
184        }
185        Ok(content_range_list)
186    }
187
188    /// The most ranges served as parts; more become one range of the whole
189    /// file (RFC 9110 §14.2 lets a server coalesce or ignore ranges).
190    pub const MAX_RANGES: usize = 16;
191
192    /// `ranges` (inclusive ends) as served: kept as requested when none
193    /// overlap; otherwise sorted with the overlapping ones merged — so a
194    /// response never holds more bytes than the file has; and more than
195    /// [`MAX_RANGES`](Self::MAX_RANGES) parts become the whole file.
196    pub fn coalesce(ranges: Vec<Range>, filelength: u64) -> Vec<Range> {
197        if ranges.len() <= 1 {
198            return ranges;
199        }
200        let mut sorted = ranges.clone();
201        sorted.sort_by_key(|r| r.start);
202        let overlapping = sorted.windows(2).any(|w| w[1].start <= w[0].end);
203        let merged = if overlapping {
204            let mut merged: Vec<Range> = Vec::with_capacity(sorted.len());
205            for r in sorted {
206                match merged.last_mut() {
207                    Some(last) if r.start <= last.end => last.end = last.end.max(r.end),
208                    _ => merged.push(r),
209                }
210            }
211            merged
212        } else {
213            ranges
214        };
215        if merged.len() > Range::MAX_RANGES {
216            return vec![Range { start: 0, end: filelength.saturating_sub(1) }];
217        }
218        merged
219    }
220
221    pub fn get_content_range_list(request_uri: &str, range: &Header) -> Result<Vec<ContentRange>, Error> {
222        let mut content_range_list : Vec<ContentRange> = vec![];
223
224        let url = request_uri.replace(&FileExt::get_path_separator(), SYMBOL.slash).to_string();
225
226        let boxed_url_components = URL::parse_request_target(&url);
227        if boxed_url_components.is_err() {
228            let message = boxed_url_components.as_ref().err().unwrap().to_string();
229            // unfallable
230            println!("unexpected error, {}", message);
231        }
232
233        let components = boxed_url_components.unwrap();
234
235        let file_path_part = components.path.replace(SYMBOL.slash, &FileExt::get_path_separator());
236
237        let boxed_static_filepath = crate::app::controller::static_resource::static_fs_path(&file_path_part);
238        if boxed_static_filepath.is_err() {
239            let error = Error {
240                status_code_reason_phrase: STATUS_CODE_REASON_PHRASE.n500_internal_server_error,
241                message: boxed_static_filepath.err().unwrap()
242            };
243            eprintln!("{}", &error.message);
244            return Err(error);
245        }
246        let static_filepath = boxed_static_filepath.unwrap();
247
248        let boxed_metadata = metadata(&static_filepath);
249        if boxed_metadata.is_err() {
250            let error = Error {
251                status_code_reason_phrase: STATUS_CODE_REASON_PHRASE.n500_internal_server_error,
252                message: boxed_metadata.err().unwrap().to_string()
253            };
254            eprintln!("{}", &error.message);
255            return Err(error);
256        }
257
258        let md = boxed_metadata.unwrap();
259        if md.is_file() {
260            let mut path = static_filepath.as_str().to_string();
261
262            let boxed_is_link = FileExt::is_symlink(&static_filepath);
263            if boxed_is_link.is_err() {
264                let error = Error {
265                    status_code_reason_phrase: STATUS_CODE_REASON_PHRASE.n500_internal_server_error,
266                    message: boxed_is_link.err().unwrap()
267                };
268                eprintln!("{}", &error.message);
269                return Err(error);
270            }
271
272
273            let is_link = boxed_is_link.unwrap();
274            if is_link {
275                let boxed_points_to = FileExt::symlink_points_to(&static_filepath);
276                if boxed_points_to.is_err() {
277                    let error = Error {
278                        status_code_reason_phrase: STATUS_CODE_REASON_PHRASE.n500_internal_server_error,
279                        message: boxed_points_to.err().unwrap()
280                    };
281                    eprintln!("{}", &error.message);
282                    return Err(error);
283                }
284
285                let points_to = boxed_points_to.unwrap();
286                let reversed_link = &static_filepath.chars().rev().collect::<String>();
287
288                let mut symlink_directory = SYMBOL.empty_string.to_string();
289                let boxed_split = reversed_link.split_once(&FileExt::get_path_separator());
290                if boxed_split.is_some() {
291                    let (_filename, path) = boxed_split.unwrap();
292                    symlink_directory = path.chars().rev().collect::<String>();
293                }
294
295                let resolved_link = FileExt::resolve_symlink_path(&symlink_directory, &points_to).unwrap();
296                path = resolved_link;
297            }
298
299            let boxed_content_range_list = Range::parse_content_range(&path, md.len(), &range.value);
300            if boxed_content_range_list.is_ok() {
301                content_range_list = boxed_content_range_list.unwrap();
302            } else {
303                let error = boxed_content_range_list.err().unwrap();
304                return Err(error)
305            }
306        }
307
308        Ok(content_range_list)
309    }
310
311    pub fn _parse_multipart_body(cursor: &mut Cursor<&[u8]>, mut content_range_list: Vec<ContentRange>) -> Result<Vec<ContentRange>, String> {
312        // A loop, not recursion: one stack frame per line let a backend's
313        // multipart/byteranges body with thousands of lines overflow the
314        // stack and abort the process.
315        loop {
316
317            let mut buffer = Range::_parse_line_as_bytes(cursor);
318            let new_line_char_found = buffer.len() != 0;
319            let mut string = Range::_convert_bytes_array_to_string(buffer);
320
321            if !new_line_char_found {
322                return Ok(content_range_list)
323            };
324
325            let mut content_range: ContentRange = ContentRange {
326                unit: Range::BYTES.to_string(),
327                range: Range { start: 0, end: 0 },
328                size: "".to_string(),
329                body: vec![],
330                content_type: "".to_string()
331            };
332
333            let content_range_is_not_parsed = content_range.body.len() == 0;
334            let separator = [SYMBOL.hyphen, SYMBOL.hyphen, Range::STRING_SEPARATOR].join("");
335            if string.starts_with(separator.as_str()) && content_range_is_not_parsed {
336                //read next line - Content-Type
337                buffer = Range::_parse_line_as_bytes(cursor);
338                string = Range::_convert_bytes_array_to_string(buffer);
339            }
340
341            let content_type_is_not_parsed = content_range.content_type.len() == 0;
342            if string.starts_with(Header::_CONTENT_TYPE) && content_type_is_not_parsed {
343                let content_type = Response::_parse_http_response_header_string(string.as_str());
344                content_range.content_type = content_type.value.trim().to_string();
345
346                //read next line - Content-Range
347                buffer = Range::_parse_line_as_bytes(cursor);
348                string = Range::_convert_bytes_array_to_string(buffer);
349            }
350
351            let content_range_is_not_parsed = content_range.size.len() == 0;
352            if string.starts_with(Header::_CONTENT_RANGE) && content_range_is_not_parsed {
353                let content_range_header = Response::_parse_http_response_header_string(string.as_str());
354
355                let boxed_result = Range::_parse_content_range_header_value(content_range_header.value);
356                if boxed_result.is_ok() {
357                    let (start, end, size) = boxed_result.unwrap();
358
359                    content_range.size = size.to_string();
360                    content_range.range.start = start as u64;
361                    content_range.range.end = end as u64;
362                } else {
363                    return Err(boxed_result.err().unwrap())
364                }
365
366
367
368                // read next line - empty line
369                buffer = Range::_parse_line_as_bytes(cursor);
370                string = Range::_convert_bytes_array_to_string(buffer);
371
372                if string.trim().len() > 0 {
373                    return Err(Range::_ERROR_NO_EMPTY_LINE_BETWEEN_CONTENT_RANGE_HEADER_AND_BODY.to_string());
374                }
375
376                // read next line - separator between content ranges
377                buffer = Range::_parse_line_as_bytes(cursor);
378                string = Range::_convert_bytes_array_to_string(buffer);
379            }
380
381            let content_range_is_parsed = content_range.size.len() != 0;
382            let content_type_is_parsed = content_range.content_type.len() != 0;
383            if content_range_is_parsed && content_type_is_parsed {
384                let mut body : Vec<u8> = vec![];
385                body = [body, string.as_bytes().to_vec()].concat();
386
387                let mut buf = Vec::from(string.as_bytes());
388                let separator = [SYMBOL.hyphen, SYMBOL.hyphen, Range::STRING_SEPARATOR].join("");
389                while !buf.starts_with(separator.as_bytes()) {
390                    buf = vec![];
391                    cursor.read_until(b'\n', &mut buf).unwrap();
392                    let separator = [SYMBOL.hyphen, SYMBOL.hyphen, Range::STRING_SEPARATOR].join("");
393                    if !buf.starts_with(separator.as_bytes()) {
394                        body = [body, buf.to_vec()].concat();
395                    }
396                }
397
398                let mut mutable_body : Vec<u8>  = body;
399                mutable_body.pop(); // remove /r
400                mutable_body.pop(); // remove /n
401
402
403                content_range.body = mutable_body;
404
405                content_range_list.push(content_range);
406            }
407
408        }
409    }
410
411    pub fn _parse_raw_content_range_header_value(unparsed_header_value: &str)-> Result<(i64, i64, i64), String> {
412        let lowercase_unparsed_header_value = unparsed_header_value.trim().to_lowercase();
413
414        let start : i64;
415        let end : i64;
416        let size : i64;
417
418
419        let boxed_split_without_bytes = lowercase_unparsed_header_value.split_once(SYMBOL.whitespace);
420        if boxed_split_without_bytes.is_none() {
421            return Err(Range::_ERROR_UNABLE_TO_PARSE_CONTENT_RANGE.to_string())
422        }
423
424        let (bytes, without_bytes) = boxed_split_without_bytes.unwrap();
425        if !bytes.eq("bytes") {
426            return Err(Range::_ERROR_UNABLE_TO_PARSE_CONTENT_RANGE.to_string())
427        }
428
429        let boxed_without_bytes = without_bytes.split_once(SYMBOL.hyphen);
430        if boxed_without_bytes.is_none() {
431            return Err(Range::_ERROR_UNABLE_TO_PARSE_CONTENT_RANGE.to_string())
432        }
433
434        let (_start, _without_start) = boxed_without_bytes.unwrap();
435
436        let boxed_start = _start.parse::<i64>();
437        if boxed_start.is_err() {
438            return Err(Range::_ERROR_UNABLE_TO_PARSE_CONTENT_RANGE.to_string())
439        }
440
441        start = boxed_start.unwrap();
442
443
444
445        let boxed_without_start = _without_start.split_once(SYMBOL.slash);
446        if boxed_without_start.is_none() {
447            return Err(Range::_ERROR_UNABLE_TO_PARSE_CONTENT_RANGE.to_string())
448        }
449        let (_end, _size) = boxed_without_start.unwrap();
450
451        let boxed_end = _end.parse::<i64>();
452        if boxed_end.is_err() {
453            return Err(Range::_ERROR_UNABLE_TO_PARSE_CONTENT_RANGE.to_string())
454        }
455
456        end = boxed_end.unwrap();
457
458        let boxed_size = _size.parse::<i64>();
459        if boxed_size.is_err() {
460            return Err(Range::_ERROR_UNABLE_TO_PARSE_CONTENT_RANGE.to_string())
461        }
462
463        size = boxed_size.unwrap();
464
465        Ok((start, end, size))
466    }
467
468    pub fn _parse_content_range_header_value(header_value: String) -> Result<(i64, i64, i64), String> {
469        let boxed_parse_result = Range::_parse_raw_content_range_header_value(&header_value);
470        if boxed_parse_result.is_err() {
471            return Err(boxed_parse_result.err().unwrap())
472        }
473        let (start, end, size) = boxed_parse_result.unwrap();
474
475        if start > end {
476            return Err(Range::ERROR_START_IS_AFTER_END_CONTENT_RANGE.to_string())
477        }
478
479        if start > size {
480            return Err(Range::ERROR_START_IS_BIGGER_THAN_FILESIZE_CONTENT_RANGE.to_string());
481        }
482        if end > size {
483            return  Err(Range::ERROR_END_IS_BIGGER_THAN_FILESIZE_CONTENT_RANGE.to_string());
484        }
485
486        Ok((start, end, size))
487    }
488
489    pub fn _parse_line_as_bytes(cursor: &mut Cursor<&[u8]>) -> Vec<u8> {
490        let mut buffer = vec![];
491        cursor.read_until(b'\n', &mut buffer).unwrap();
492        buffer
493    }
494
495    pub fn _convert_bytes_array_to_string(buffer: Vec<u8>) -> String {
496        let buffer_as_u8_array: &[u8] = &buffer;
497        String::from_utf8(Vec::from(buffer_as_u8_array)).unwrap()
498    }
499
500    /// Creates a `ContentRange` from raw bytes and a MIME type. The most common way to build a response body.
501    pub fn get_content_range(body: Vec<u8>, mime_type: String) -> ContentRange {
502        let length = body.len() as u64;
503        let content_range = ContentRange {
504            unit: Range::BYTES.to_string(),
505            range: Range { start: 0, end: length },
506            size: length.to_string(),
507            body,
508            content_type: mime_type
509        };
510
511        content_range
512    }
513
514    /// Creates a `ContentRange` by reading a file from disk. MIME type is detected from the extension.
515    pub fn get_content_range_of_a_file(filepath: &str) -> Result<ContentRange, String> {
516        let body: Vec<u8>;
517        let boxed_file = FileExt::read_file(filepath);
518        if boxed_file.is_err() {
519            let error = boxed_file.err().unwrap();
520            return Err(error);
521        }
522
523        body = boxed_file.unwrap();
524        let mime_type = MimeType::detect_mime_type(filepath);
525        let content_range = Range::get_content_range(body, mime_type);
526        Ok(content_range)
527    }
528
529
530    pub fn parse_multipart_body(cursor: &mut Cursor<&[u8]>,
531                                mut content_range_list: Vec<ContentRange>)
532        -> Result<Vec<ContentRange>, String> {
533
534        let boxed_line = Range::parse_line_as_bytes(cursor);
535        if boxed_line.is_err() {
536            let message = boxed_line.err().unwrap();
537            return Err(message);
538        }
539        let mut buffer = boxed_line.unwrap();
540
541
542        let new_line_char_found = buffer.len() != 0;
543
544
545        let boxed_line = Range::convert_bytes_array_to_string(buffer);
546        if boxed_line.is_err() {
547            let message = boxed_line.err().unwrap();
548            return Err(message);
549        }
550        let mut string = boxed_line.unwrap();
551
552        if !new_line_char_found {
553            return Ok(content_range_list)
554        };
555
556        let mut content_range: ContentRange = ContentRange {
557            unit: Range::BYTES.to_string(),
558            range: Range { start: 0, end: 0 },
559            size: "".to_string(),
560            body: vec![],
561            content_type: "".to_string()
562        };
563
564        let content_range_is_not_parsed = content_range.body.len() == 0;
565        let separator = [SYMBOL.hyphen, SYMBOL.hyphen, Range::STRING_SEPARATOR].join("");
566        if string.starts_with(separator.as_str()) && content_range_is_not_parsed {
567            //read next line - Content-Type
568            let boxed_line = Range::parse_line_as_bytes(cursor);
569            if boxed_line.is_err() {
570                let message = boxed_line.err().unwrap();
571                return Err(message);
572            }
573            buffer = boxed_line.unwrap();
574
575            let boxed_line = Range::convert_bytes_array_to_string(buffer);
576            if boxed_line.is_err() {
577                let message = boxed_line.err().unwrap();
578                return Err(message);
579            }
580            string = boxed_line.unwrap();
581        }
582
583        let content_type_is_not_parsed = content_range.content_type.len() == 0;
584        if string.starts_with(Header::_CONTENT_TYPE) && content_type_is_not_parsed {
585            let boxed_content_type = Response::parse_http_response_header_string(string.as_str());
586            if boxed_content_type.is_err() {
587                let message = boxed_content_type.err().unwrap();
588                return Err(message);
589            }
590            let content_type = boxed_content_type.unwrap();
591
592            content_range.content_type = content_type.value.trim().to_string();
593
594            //read next line - Content-Range
595            let boxed_line = Range::parse_line_as_bytes(cursor);
596            if boxed_line.is_err() {
597                let message = boxed_line.err().unwrap();
598                return Err(message);
599            }
600            buffer = boxed_line.unwrap();
601
602            let boxed_line = Range::convert_bytes_array_to_string(buffer);
603            if boxed_line.is_err() {
604                let message = boxed_line.err().unwrap();
605                return Err(message);
606            }
607            string = boxed_line.unwrap();
608        }
609
610        let content_range_is_not_parsed = content_range.size.len() == 0;
611        if string.starts_with(Header::_CONTENT_RANGE) && content_range_is_not_parsed {
612            let content_range_header = Response::_parse_http_response_header_string(string.as_str());
613
614            let boxed_result = Range::_parse_content_range_header_value(content_range_header.value);
615            if boxed_result.is_ok() {
616                let (start, end, size) = boxed_result.unwrap();
617
618                content_range.size = size.to_string();
619                content_range.range.start = start as u64;
620                content_range.range.end = end as u64;
621            } else {
622                return Err(boxed_result.err().unwrap())
623            }
624
625
626
627            // read next line - empty line
628            let boxed_line = Range::parse_line_as_bytes(cursor);
629            if boxed_line.is_err() {
630                let message = boxed_line.err().unwrap();
631                return Err(message);
632            }
633            buffer = boxed_line.unwrap();
634
635            let boxed_line = Range::convert_bytes_array_to_string(buffer);
636            if boxed_line.is_err() {
637                let message = boxed_line.err().unwrap();
638                return Err(message);
639            }
640            string = boxed_line.unwrap();
641
642            if string.trim().len() > 0 {
643                return Err(Range::_ERROR_NO_EMPTY_LINE_BETWEEN_CONTENT_RANGE_HEADER_AND_BODY.to_string());
644            }
645
646            // read next line - separator between content ranges
647            let boxed_line = Range::parse_line_as_bytes(cursor);
648            if boxed_line.is_err() {
649                let message = boxed_line.err().unwrap();
650                return Err(message);
651            }
652            buffer = boxed_line.unwrap();
653
654            let boxed_line = Range::convert_bytes_array_to_string(buffer);
655            if boxed_line.is_err() {
656                let message = boxed_line.err().unwrap();
657                return Err(message);
658            }
659            string = boxed_line.unwrap();
660        }
661
662        let content_range_is_parsed = content_range.size.len() != 0;
663        let content_type_is_parsed = content_range.content_type.len() != 0;
664        if content_range_is_parsed && content_type_is_parsed {
665            let mut body : Vec<u8> = vec![];
666            body = [body, string.as_bytes().to_vec()].concat();
667
668            let mut buf = Vec::from(string.as_bytes());
669            let separator = [SYMBOL.hyphen, SYMBOL.hyphen, Range::STRING_SEPARATOR].join("");
670            while !buf.starts_with(separator.as_bytes()) {
671                buf = vec![];
672                cursor.read_until(b'\n', &mut buf).unwrap();
673                let separator = [SYMBOL.hyphen, SYMBOL.hyphen, Range::STRING_SEPARATOR].join("");
674                if !buf.starts_with(separator.as_bytes()) {
675                    body = [body, buf.to_vec()].concat();
676                }
677            }
678
679            let mut mutable_body : Vec<u8>  = body;
680            mutable_body.pop(); // remove /r
681            mutable_body.pop(); // remove /n
682
683
684            content_range.body = mutable_body;
685
686            content_range_list.push(content_range);
687        }
688
689        let boxed_result = Range::_parse_multipart_body(cursor, content_range_list);
690        return if boxed_result.is_ok() {
691            Ok(boxed_result.unwrap())
692        } else {
693            let error = boxed_result.err().unwrap();
694            Err(error)
695        }
696
697    }
698
699    pub fn parse_multipart_body_with_boundary(cursor: &mut Cursor<&[u8]>,
700                                              mut content_range_list: Vec<ContentRange>,
701                                              boundary: String,
702                                              total_bytes: i32,
703                                              mut bytes_read: i32,
704                                              mut is_opening_boundary_read: bool)
705                                              -> Result<Vec<ContentRange>, String> {
706        // A loop, not recursion: one stack frame per line let a backend's
707        // multipart/byteranges body with thousands of lines overflow the
708        // stack and abort the process.
709        loop {
710
711            let mut buffer = vec![];
712            let boxed_read = cursor.read_until(b'\n', &mut buffer);
713            if boxed_read.is_err() {
714                let message = boxed_read.err().unwrap().to_string();
715                return Err(message);
716            }
717
718            let bytes_offset = boxed_read.unwrap();
719            bytes_read = bytes_read + bytes_offset as i32;
720            if bytes_read == total_bytes {
721                // end of stream
722            }
723
724
725            let new_line_char_found = buffer.len() != 0;
726
727
728            let boxed_line = Range::convert_bytes_array_to_string(buffer);
729            if boxed_line.is_err() {
730                let message = boxed_line.err().unwrap();
731                return Err(message);
732            }
733            let mut string = boxed_line.unwrap();
734
735            if !new_line_char_found {
736                return Ok(content_range_list)
737            };
738
739            let mut content_range: ContentRange = ContentRange::new();
740
741            let content_range_is_not_parsed = content_range.body.len() == 0;
742
743            if string.trim().len() != 0 && !is_opening_boundary_read && !string.contains(boundary.as_str()) {
744                return Err("Response body doesn't start with a boundary".to_string())
745            }
746
747            if string.contains(boundary.as_str()) && content_range_is_not_parsed {
748                if !is_opening_boundary_read {
749                    is_opening_boundary_read = true;
750                }
751                //read next line - Content-Type
752                let boxed_line = Range::parse_line_as_bytes(cursor);
753                if boxed_line.is_err() {
754                    let message = boxed_line.err().unwrap();
755                    return Err(message);
756                }
757                buffer = boxed_line.unwrap();
758
759                let boxed_line = Range::convert_bytes_array_to_string(buffer);
760                if boxed_line.is_err() {
761                    let message = boxed_line.err().unwrap();
762                    return Err(message);
763                }
764                string = boxed_line.unwrap();
765            }
766
767            let content_type_is_not_parsed = content_range.content_type.len() == 0;
768            if string.starts_with(Header::_CONTENT_TYPE) && content_type_is_not_parsed {
769                let boxed_content_type = Response::parse_http_response_header_string(string.as_str());
770                if boxed_content_type.is_err() {
771                    let message = boxed_content_type.err().unwrap();
772                    return Err(message);
773                }
774                let content_type = boxed_content_type.unwrap();
775
776                content_range.content_type = content_type.value.trim().to_string();
777
778                //read next line - Content-Range
779                let boxed_line = Range::parse_line_as_bytes(cursor);
780                if boxed_line.is_err() {
781                    let message = boxed_line.err().unwrap();
782                    return Err(message);
783                }
784                buffer = boxed_line.unwrap();
785
786                let boxed_line = Range::convert_bytes_array_to_string(buffer);
787                if boxed_line.is_err() {
788                    let message = boxed_line.err().unwrap();
789                    return Err(message);
790                }
791                string = boxed_line.unwrap();
792            }
793
794            let content_range_is_not_parsed = content_range.size.len() == 0;
795            if string.starts_with(Header::_CONTENT_RANGE) && content_range_is_not_parsed {
796                let content_range_header = Response::_parse_http_response_header_string(string.as_str());
797
798                let boxed_result = Range::_parse_content_range_header_value(content_range_header.value);
799                if boxed_result.is_ok() {
800                    let (start, end, size) = boxed_result.unwrap();
801
802                    content_range.size = size.to_string();
803                    content_range.range.start = start as u64;
804                    content_range.range.end = end as u64;
805                } else {
806                    return Err(boxed_result.err().unwrap())
807                }
808
809
810
811                // read next line - empty line
812                let boxed_line = Range::parse_line_as_bytes(cursor);
813                if boxed_line.is_err() {
814                    let message = boxed_line.err().unwrap();
815                    return Err(message);
816                }
817                buffer = boxed_line.unwrap();
818
819                let boxed_line = Range::convert_bytes_array_to_string(buffer);
820                if boxed_line.is_err() {
821                    let message = boxed_line.err().unwrap();
822                    return Err(message);
823                }
824                string = boxed_line.unwrap();
825
826                if string.trim().len() > 0 {
827                    return Err(Range::_ERROR_NO_EMPTY_LINE_BETWEEN_CONTENT_RANGE_HEADER_AND_BODY.to_string());
828                }
829
830            }
831
832            let content_range_is_parsed = content_range.size.len() != 0;
833            let content_type_is_parsed = content_range.content_type.len() != 0;
834            if content_range_is_parsed && content_type_is_parsed {
835                let mut body : Vec<u8> = vec![];
836
837                let mut is_not_boundary = true;
838
839                while is_not_boundary {
840                    let mut _bytes_offset = 0;
841                    let mut buf: Vec<u8> = vec![];
842                    let boxed_read = cursor.read_until(b'\n', &mut buf);
843                    if boxed_read.is_err() {
844                        return Err("Unable to read from stream".to_string());
845                    }
846                    _bytes_offset = boxed_read.unwrap();
847                    bytes_read = bytes_read + _bytes_offset as i32;
848
849
850                    let boxed_line = Range::convert_bytes_array_to_string(buf.clone());
851                    if boxed_line.is_err() {
852                        // non utf-8 body, continue
853                        body = [body, buf.to_vec()].concat();
854                        continue;
855                    }
856
857                    string = boxed_line.unwrap();
858
859                    is_not_boundary = !string.contains(boundary.as_str());
860
861                    if is_not_boundary {
862                        body = [body, buf.to_vec()].concat();
863                        if (bytes_read == total_bytes) || _bytes_offset == 0 {
864                            return Err("Unable to parse multipart form body, reached the end of stream and it does not contain boundary".to_string());
865                        }
866                    }
867
868                }
869
870                let mut mutable_body : Vec<u8>  = body;
871                mutable_body.pop(); // remove /r
872                mutable_body.pop(); // remove /n
873
874
875                content_range.body = mutable_body;
876
877                content_range_list.push(content_range);
878            }
879
880        }
881    }
882
883    pub fn parse_line_as_bytes(cursor: &mut Cursor<&[u8]>) -> Result<Vec<u8>, String> {
884        let mut buffer = vec![];
885        let boxed_read = cursor.read_until(b'\n', &mut buffer);
886        if boxed_read.is_err() {
887            let message = boxed_read.err().unwrap().to_string();
888            return Err(message);
889        }
890        boxed_read.unwrap();
891        Ok(buffer)
892    }
893
894    pub fn convert_bytes_array_to_string(buffer: Vec<u8>) -> Result<String, String> {
895        let buffer_as_u8_array: &[u8] = &buffer;
896        let boxed_string = String::from_utf8(Vec::from(buffer_as_u8_array));
897        if boxed_string.is_err() {
898            let message = boxed_string.err().unwrap().to_string();
899            return Err(message);
900        }
901        let string = boxed_string.unwrap();
902        Ok(string)
903    }
904}
905
906