Skip to main content

rust_web_server/range/
mod.rs

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