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