Skip to main content

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