#[cfg(test)]
mod tests;
#[cfg(test)]
mod example;
use std::io::prelude::*;
use std::fs::{metadata};
use std::io::{Cursor};
use file_ext::FileExt;
use crate::core::New;
use crate::response::{Error, Response, STATUS_CODE_REASON_PHRASE};
use crate::header::Header;
use crate::mime_type::MimeType;
use crate::symbol::SYMBOL;
use crate::url::URL;
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Range {
pub start: u64,
pub end: u64,
}
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ContentRange {
pub unit: String,
pub range: Range,
pub size: String,
pub body: Vec<u8>,
pub content_type: String,
}
impl New for ContentRange {
fn new() -> Self {
ContentRange {
unit: Range::BYTES.to_string(),
range: Range { start: 0, end: 0 },
size: "".to_string(),
body: Default::default(),
content_type: "".to_string()
}
}
}
impl Range {
pub const STRING_SEPARATOR: &'static str = "String_separator";
pub const BOUNDARY: &'static str = "boundary";
pub const BYTERANGES: &'static str = "byteranges";
pub const MULTIPART: &'static str = "multipart";
pub const BYTES: &'static str = "bytes";
pub const MULTIPART_BYTERANGES_CONTENT_TYPE: &'static str = "multipart/byteranges; boundary=String_separator";
pub fn multipart_boundary(content_range_list: &[ContentRange]) -> String {
let mut seed: u64 = 0xcbf2_9ce4_8422_2325;
for cr in content_range_list {
for n in [cr.range.start, cr.range.end, cr.body.len() as u64] {
for byte in n.to_le_bytes() {
seed = (seed ^ byte as u64).wrapping_mul(0x0100_0000_01b3);
}
}
}
let mut salt: u64 = 0;
loop {
let candidate = format!("rws-{:016x}", seed.wrapping_add(salt));
let collides = content_range_list.iter()
.any(|cr| cr.body.windows(candidate.len()).any(|w| w == candidate.as_bytes()));
if !collides {
return candidate;
}
salt += 1;
}
}
pub fn multipart_content_type(content_range_list: &[ContentRange]) -> String {
format!("{}/{}; {}={}", Range::MULTIPART, Range::BYTERANGES, Range::BOUNDARY, Range::multipart_boundary(content_range_list))
}
pub const _ERROR_NO_EMPTY_LINE_BETWEEN_CONTENT_RANGE_HEADER_AND_BODY: &'static str = "no empty line between content range headers and body";
pub const _ERROR_UNABLE_TO_PARSE_CONTENT_RANGE: &'static str = "unable to parse content-range";
pub const ERROR_START_IS_AFTER_END_CONTENT_RANGE: &'static str = "start is after end in content range";
pub const ERROR_START_IS_BIGGER_THAN_FILESIZE_CONTENT_RANGE: &'static str = "start is bigger than filesize in content range";
pub const ERROR_END_IS_BIGGER_THAN_FILESIZE_CONTENT_RANGE: &'static str = "end is bigger than filesize in content range";
pub const ERROR_MALFORMED_RANGE_HEADER_WRONG_UNIT: &'static str = "range header malformed, most likely you have an error in unit statement";
pub const ERROR_UNABLE_TO_PARSE_RANGE_START: &'static str = "unable to parse range start";
pub const ERROR_UNABLE_TO_PARSE_RANGE_END: &'static str = "unable to parse range end";
pub fn parse_range_in_content_range(filelength: u64, range_str: &str) -> Result<Range, Error> {
let unsatisfiable = |message: &str| Error {
status_code_reason_phrase: STATUS_CODE_REASON_PHRASE.n416_range_not_satisfiable,
message: message.to_string(),
};
let (raw_start, raw_end) = match range_str.split_once(SYMBOL.hyphen) {
Some((start, end)) => (start.trim(), end.trim()),
None => return Err(unsatisfiable(Range::ERROR_UNABLE_TO_PARSE_RANGE_START)),
};
if filelength == 0 {
return Err(unsatisfiable(Range::ERROR_START_IS_BIGGER_THAN_FILESIZE_CONTENT_RANGE));
}
let last_byte = filelength - 1;
if raw_start.is_empty() {
let suffix: u64 = raw_end
.parse()
.map_err(|_| unsatisfiable(Range::ERROR_UNABLE_TO_PARSE_RANGE_END))?;
if suffix == 0 {
return Err(unsatisfiable(Range::ERROR_UNABLE_TO_PARSE_RANGE_END));
}
return Ok(Range { start: filelength.saturating_sub(suffix), end: last_byte });
}
let start: u64 = raw_start
.parse()
.map_err(|_| unsatisfiable(Range::ERROR_UNABLE_TO_PARSE_RANGE_START))?;
let requested_end: Option<u64> = if raw_end.is_empty() {
None
} else {
Some(raw_end.parse().map_err(|_| unsatisfiable(Range::ERROR_UNABLE_TO_PARSE_RANGE_END))?)
};
if requested_end.map_or(false, |end| start > end) {
return Err(unsatisfiable(Range::ERROR_START_IS_AFTER_END_CONTENT_RANGE));
}
if start > last_byte {
return Err(unsatisfiable(Range::ERROR_START_IS_BIGGER_THAN_FILESIZE_CONTENT_RANGE));
}
let end = requested_end.map_or(last_byte, |end| end.min(last_byte));
Ok(Range { start, end })
}
fn read_file_range(filepath: &str, start: u64, end: u64) -> Result<Vec<u8>, String> {
let mut file = std::fs::File::open(filepath).map_err(|e| e.to_string())?;
file.seek(std::io::SeekFrom::Start(start)).map_err(|e| e.to_string())?;
let mut body = Vec::with_capacity((end - start + 1) as usize);
file.take(end - start + 1).read_to_end(&mut body).map_err(|e| e.to_string())?;
Ok(body)
}
pub fn parse_content_range(filepath: &str, filelength: u64, raw_range_value: &str) -> Result<Vec<ContentRange>, Error> {
const INDEX_AFTER_UNIT_DECLARATION : usize = 1;
let mut content_range_list: Vec<ContentRange> = vec![];
let prefix = [Range::BYTES, SYMBOL.equals].join("");
if !raw_range_value.starts_with(prefix.as_str()) {
let message = Range::ERROR_MALFORMED_RANGE_HEADER_WRONG_UNIT.to_string();
let error = Error {
status_code_reason_phrase: STATUS_CODE_REASON_PHRASE.n416_range_not_satisfiable,
message,
};
return Err(error);
}
let split_raw_range_value: Vec<&str> = raw_range_value.split(SYMBOL.equals).collect();
let boxed_raw_bytes = split_raw_range_value.get(INDEX_AFTER_UNIT_DECLARATION);
if boxed_raw_bytes.is_none() {
let message = Range::ERROR_UNABLE_TO_PARSE_RANGE_START.to_string();
let error = Error {
status_code_reason_phrase: STATUS_CODE_REASON_PHRASE.n416_range_not_satisfiable,
message: message.to_string()
};
return Err(error)
}
let raw_bytes = boxed_raw_bytes.unwrap();
let mut ranges: Vec<Range> = Vec::new();
let mut first_error: Option<Error> = None;
for byte in raw_bytes.split(SYMBOL.comma) {
match Range::parse_range_in_content_range(filelength, byte) {
Ok(range) => ranges.push(range),
Err(error) => { first_error.get_or_insert(error); }
}
}
if ranges.is_empty() {
return Err(first_error.unwrap_or(Error {
status_code_reason_phrase: STATUS_CODE_REASON_PHRASE.n416_range_not_satisfiable,
message: Range::ERROR_UNABLE_TO_PARSE_RANGE_START.to_string(),
}));
}
let ranges = Range::coalesce(ranges, filelength);
for range in ranges {
{
let boxed_read = Range::read_file_range(filepath, range.start, range.end);
if boxed_read.is_ok() {
let content_type = MimeType::detect_mime_type(filepath);
let body = boxed_read.unwrap();
let content_range = ContentRange {
unit: Range::BYTES.to_string(),
range,
size: filelength.to_string(),
body,
content_type,
};
content_range_list.push(content_range);
} else {
let error : Error = Error {
status_code_reason_phrase: STATUS_CODE_REASON_PHRASE.n416_range_not_satisfiable,
message: boxed_read.err().unwrap().to_string()
};
return Err(error)
}
}
}
Ok(content_range_list)
}
pub const MAX_RANGES: usize = 16;
pub fn coalesce(ranges: Vec<Range>, filelength: u64) -> Vec<Range> {
if ranges.len() <= 1 {
return ranges;
}
let mut sorted = ranges.clone();
sorted.sort_by_key(|r| r.start);
let overlapping = sorted.windows(2).any(|w| w[1].start <= w[0].end);
let merged = if overlapping {
let mut merged: Vec<Range> = Vec::with_capacity(sorted.len());
for r in sorted {
match merged.last_mut() {
Some(last) if r.start <= last.end => last.end = last.end.max(r.end),
_ => merged.push(r),
}
}
merged
} else {
ranges
};
if merged.len() > Range::MAX_RANGES {
return vec![Range { start: 0, end: filelength.saturating_sub(1) }];
}
merged
}
pub fn get_content_range_list(request_uri: &str, range: &Header) -> Result<Vec<ContentRange>, Error> {
let mut content_range_list : Vec<ContentRange> = vec![];
let url = request_uri.replace(&FileExt::get_path_separator(), SYMBOL.slash).to_string();
let boxed_url_components = URL::parse_request_target(&url);
if boxed_url_components.is_err() {
let message = boxed_url_components.as_ref().err().unwrap().to_string();
println!("unexpected error, {}", message);
}
let components = boxed_url_components.unwrap();
let file_path_part = components.path.replace(SYMBOL.slash, &FileExt::get_path_separator());
let boxed_static_filepath = crate::app::controller::static_resource::static_fs_path(&file_path_part);
if boxed_static_filepath.is_err() {
let error = Error {
status_code_reason_phrase: STATUS_CODE_REASON_PHRASE.n500_internal_server_error,
message: boxed_static_filepath.err().unwrap()
};
eprintln!("{}", &error.message);
return Err(error);
}
let static_filepath = boxed_static_filepath.unwrap();
let boxed_metadata = metadata(&static_filepath);
if boxed_metadata.is_err() {
let error = Error {
status_code_reason_phrase: STATUS_CODE_REASON_PHRASE.n500_internal_server_error,
message: boxed_metadata.err().unwrap().to_string()
};
eprintln!("{}", &error.message);
return Err(error);
}
let md = boxed_metadata.unwrap();
if md.is_file() {
let mut path = static_filepath.as_str().to_string();
let boxed_is_link = FileExt::is_symlink(&static_filepath);
if boxed_is_link.is_err() {
let error = Error {
status_code_reason_phrase: STATUS_CODE_REASON_PHRASE.n500_internal_server_error,
message: boxed_is_link.err().unwrap()
};
eprintln!("{}", &error.message);
return Err(error);
}
let is_link = boxed_is_link.unwrap();
if is_link {
let boxed_points_to = FileExt::symlink_points_to(&static_filepath);
if boxed_points_to.is_err() {
let error = Error {
status_code_reason_phrase: STATUS_CODE_REASON_PHRASE.n500_internal_server_error,
message: boxed_points_to.err().unwrap()
};
eprintln!("{}", &error.message);
return Err(error);
}
let points_to = boxed_points_to.unwrap();
let reversed_link = &static_filepath.chars().rev().collect::<String>();
let mut symlink_directory = SYMBOL.empty_string.to_string();
let boxed_split = reversed_link.split_once(&FileExt::get_path_separator());
if boxed_split.is_some() {
let (_filename, path) = boxed_split.unwrap();
symlink_directory = path.chars().rev().collect::<String>();
}
let resolved_link = FileExt::resolve_symlink_path(&symlink_directory, &points_to).unwrap();
path = resolved_link;
}
let boxed_content_range_list = Range::parse_content_range(&path, md.len(), &range.value);
if boxed_content_range_list.is_ok() {
content_range_list = boxed_content_range_list.unwrap();
} else {
let error = boxed_content_range_list.err().unwrap();
return Err(error)
}
}
Ok(content_range_list)
}
pub fn _parse_multipart_body(cursor: &mut Cursor<&[u8]>, content_range_list: Vec<ContentRange>) -> Result<Vec<ContentRange>, String> {
Range::_parse_multipart_body_with_boundary(cursor, content_range_list, Range::STRING_SEPARATOR)
}
pub(crate) fn _parse_multipart_body_with_boundary(cursor: &mut Cursor<&[u8]>, mut content_range_list: Vec<ContentRange>, boundary: &str) -> Result<Vec<ContentRange>, String> {
let separator = [SYMBOL.hyphen, SYMBOL.hyphen, boundary].join("");
loop {
let mut buffer = Range::_parse_line_as_bytes(cursor);
let new_line_char_found = buffer.len() != 0;
let mut string = Range::_convert_bytes_array_to_string(buffer);
if !new_line_char_found {
return Ok(content_range_list)
};
let mut content_range: ContentRange = ContentRange {
unit: Range::BYTES.to_string(),
range: Range { start: 0, end: 0 },
size: "".to_string(),
body: Default::default(),
content_type: "".to_string()
};
let content_range_is_not_parsed = content_range.body.len() == 0;
if string.starts_with(separator.as_str()) && content_range_is_not_parsed {
buffer = Range::_parse_line_as_bytes(cursor);
string = Range::_convert_bytes_array_to_string(buffer);
}
let content_type_is_not_parsed = content_range.content_type.len() == 0;
if string.starts_with(Header::_CONTENT_TYPE) && content_type_is_not_parsed {
let content_type = Response::_parse_http_response_header_string(string.as_str());
content_range.content_type = content_type.value.trim().to_string();
buffer = Range::_parse_line_as_bytes(cursor);
string = Range::_convert_bytes_array_to_string(buffer);
}
let content_range_is_not_parsed = content_range.size.len() == 0;
if string.starts_with(Header::_CONTENT_RANGE) && content_range_is_not_parsed {
let content_range_header = Response::_parse_http_response_header_string(string.as_str());
let boxed_result = Range::_parse_content_range_header_value(content_range_header.value.into_owned());
if boxed_result.is_ok() {
let (start, end, size) = boxed_result.unwrap();
content_range.size = size.to_string();
content_range.range.start = start as u64;
content_range.range.end = end as u64;
} else {
return Err(boxed_result.err().unwrap())
}
buffer = Range::_parse_line_as_bytes(cursor);
string = Range::_convert_bytes_array_to_string(buffer);
if string.trim().len() > 0 {
return Err(Range::_ERROR_NO_EMPTY_LINE_BETWEEN_CONTENT_RANGE_HEADER_AND_BODY.to_string());
}
buffer = Range::_parse_line_as_bytes(cursor);
string = Range::_convert_bytes_array_to_string(buffer);
}
let content_range_is_parsed = content_range.size.len() != 0;
let content_type_is_parsed = content_range.content_type.len() != 0;
if content_range_is_parsed && content_type_is_parsed {
let mut body : Vec<u8> = vec![];
body = [body, string.as_bytes().to_vec()].concat();
let mut buf = Vec::from(string.as_bytes());
while !buf.starts_with(separator.as_bytes()) {
buf = vec![];
if cursor.read_until(b'\n', &mut buf).unwrap_or(0) == 0 {
return Err("multipart body ends without a closing boundary".to_string());
}
if !buf.starts_with(separator.as_bytes()) {
body = [body, buf.to_vec()].concat();
}
}
let mut mutable_body : Vec<u8> = body;
mutable_body.pop(); mutable_body.pop();
content_range.body = mutable_body;
content_range_list.push(content_range);
}
}
}
pub fn _parse_raw_content_range_header_value(unparsed_header_value: &str)-> Result<(i64, i64, i64), String> {
let lowercase_unparsed_header_value = unparsed_header_value.trim().to_lowercase();
let start : i64;
let end : i64;
let size : i64;
let boxed_split_without_bytes = lowercase_unparsed_header_value.split_once(SYMBOL.whitespace);
if boxed_split_without_bytes.is_none() {
return Err(Range::_ERROR_UNABLE_TO_PARSE_CONTENT_RANGE.to_string())
}
let (bytes, without_bytes) = boxed_split_without_bytes.unwrap();
if !bytes.eq("bytes") {
return Err(Range::_ERROR_UNABLE_TO_PARSE_CONTENT_RANGE.to_string())
}
let boxed_without_bytes = without_bytes.split_once(SYMBOL.hyphen);
if boxed_without_bytes.is_none() {
return Err(Range::_ERROR_UNABLE_TO_PARSE_CONTENT_RANGE.to_string())
}
let (_start, _without_start) = boxed_without_bytes.unwrap();
let boxed_start = _start.parse::<i64>();
if boxed_start.is_err() {
return Err(Range::_ERROR_UNABLE_TO_PARSE_CONTENT_RANGE.to_string())
}
start = boxed_start.unwrap();
let boxed_without_start = _without_start.split_once(SYMBOL.slash);
if boxed_without_start.is_none() {
return Err(Range::_ERROR_UNABLE_TO_PARSE_CONTENT_RANGE.to_string())
}
let (_end, _size) = boxed_without_start.unwrap();
let boxed_end = _end.parse::<i64>();
if boxed_end.is_err() {
return Err(Range::_ERROR_UNABLE_TO_PARSE_CONTENT_RANGE.to_string())
}
end = boxed_end.unwrap();
let boxed_size = _size.parse::<i64>();
if boxed_size.is_err() {
return Err(Range::_ERROR_UNABLE_TO_PARSE_CONTENT_RANGE.to_string())
}
size = boxed_size.unwrap();
Ok((start, end, size))
}
pub fn _parse_content_range_header_value(header_value: String) -> Result<(i64, i64, i64), String> {
let boxed_parse_result = Range::_parse_raw_content_range_header_value(&header_value);
if boxed_parse_result.is_err() {
return Err(boxed_parse_result.err().unwrap())
}
let (start, end, size) = boxed_parse_result.unwrap();
if start > end {
return Err(Range::ERROR_START_IS_AFTER_END_CONTENT_RANGE.to_string())
}
if start > size {
return Err(Range::ERROR_START_IS_BIGGER_THAN_FILESIZE_CONTENT_RANGE.to_string());
}
if end > size {
return Err(Range::ERROR_END_IS_BIGGER_THAN_FILESIZE_CONTENT_RANGE.to_string());
}
Ok((start, end, size))
}
pub fn _parse_line_as_bytes(cursor: &mut Cursor<&[u8]>) -> Vec<u8> {
let mut buffer = vec![];
cursor.read_until(b'\n', &mut buffer).unwrap();
buffer
}
pub fn _convert_bytes_array_to_string(buffer: Vec<u8>) -> String {
let buffer_as_u8_array: &[u8] = &buffer;
String::from_utf8(Vec::from(buffer_as_u8_array)).unwrap()
}
pub fn get_content_range(body: Vec<u8>, mime_type: String) -> ContentRange {
let length = body.len() as u64;
let content_range = ContentRange {
unit: Range::BYTES.to_string(),
range: Range { start: 0, end: length },
size: crate::ext::decimal::Decimal::new(length as u128).as_str().to_string(),
body,
content_type: mime_type
};
content_range
}
pub fn get_content_range_of_a_file(filepath: &str) -> Result<ContentRange, String> {
let body: Vec<u8>;
let boxed_file = FileExt::read_file(filepath);
if boxed_file.is_err() {
let error = boxed_file.err().unwrap();
return Err(error);
}
body = boxed_file.unwrap();
let mime_type = MimeType::detect_mime_type(filepath);
let content_range = Range::get_content_range(body, mime_type);
Ok(content_range)
}
pub fn parse_multipart_body(cursor: &mut Cursor<&[u8]>,
mut content_range_list: Vec<ContentRange>)
-> Result<Vec<ContentRange>, String> {
let boxed_line = Range::parse_line_as_bytes(cursor);
if boxed_line.is_err() {
let message = boxed_line.err().unwrap();
return Err(message);
}
let mut buffer = boxed_line.unwrap();
let new_line_char_found = buffer.len() != 0;
let boxed_line = Range::convert_bytes_array_to_string(buffer);
if boxed_line.is_err() {
let message = boxed_line.err().unwrap();
return Err(message);
}
let mut string = boxed_line.unwrap();
if !new_line_char_found {
return Ok(content_range_list)
};
let mut content_range: ContentRange = ContentRange {
unit: Range::BYTES.to_string(),
range: Range { start: 0, end: 0 },
size: "".to_string(),
body: Default::default(),
content_type: "".to_string()
};
let content_range_is_not_parsed = content_range.body.len() == 0;
let separator = [SYMBOL.hyphen, SYMBOL.hyphen, Range::STRING_SEPARATOR].join("");
if string.starts_with(separator.as_str()) && content_range_is_not_parsed {
let boxed_line = Range::parse_line_as_bytes(cursor);
if boxed_line.is_err() {
let message = boxed_line.err().unwrap();
return Err(message);
}
buffer = boxed_line.unwrap();
let boxed_line = Range::convert_bytes_array_to_string(buffer);
if boxed_line.is_err() {
let message = boxed_line.err().unwrap();
return Err(message);
}
string = boxed_line.unwrap();
}
let content_type_is_not_parsed = content_range.content_type.len() == 0;
if string.starts_with(Header::_CONTENT_TYPE) && content_type_is_not_parsed {
let boxed_content_type = Response::parse_http_response_header_string(string.as_str());
if boxed_content_type.is_err() {
let message = boxed_content_type.err().unwrap();
return Err(message);
}
let content_type = boxed_content_type.unwrap();
content_range.content_type = content_type.value.trim().to_string();
let boxed_line = Range::parse_line_as_bytes(cursor);
if boxed_line.is_err() {
let message = boxed_line.err().unwrap();
return Err(message);
}
buffer = boxed_line.unwrap();
let boxed_line = Range::convert_bytes_array_to_string(buffer);
if boxed_line.is_err() {
let message = boxed_line.err().unwrap();
return Err(message);
}
string = boxed_line.unwrap();
}
let content_range_is_not_parsed = content_range.size.len() == 0;
if string.starts_with(Header::_CONTENT_RANGE) && content_range_is_not_parsed {
let content_range_header = Response::_parse_http_response_header_string(string.as_str());
let boxed_result = Range::_parse_content_range_header_value(content_range_header.value.into_owned());
if boxed_result.is_ok() {
let (start, end, size) = boxed_result.unwrap();
content_range.size = size.to_string();
content_range.range.start = start as u64;
content_range.range.end = end as u64;
} else {
return Err(boxed_result.err().unwrap())
}
let boxed_line = Range::parse_line_as_bytes(cursor);
if boxed_line.is_err() {
let message = boxed_line.err().unwrap();
return Err(message);
}
buffer = boxed_line.unwrap();
let boxed_line = Range::convert_bytes_array_to_string(buffer);
if boxed_line.is_err() {
let message = boxed_line.err().unwrap();
return Err(message);
}
string = boxed_line.unwrap();
if string.trim().len() > 0 {
return Err(Range::_ERROR_NO_EMPTY_LINE_BETWEEN_CONTENT_RANGE_HEADER_AND_BODY.to_string());
}
let boxed_line = Range::parse_line_as_bytes(cursor);
if boxed_line.is_err() {
let message = boxed_line.err().unwrap();
return Err(message);
}
buffer = boxed_line.unwrap();
let boxed_line = Range::convert_bytes_array_to_string(buffer);
if boxed_line.is_err() {
let message = boxed_line.err().unwrap();
return Err(message);
}
string = boxed_line.unwrap();
}
let content_range_is_parsed = content_range.size.len() != 0;
let content_type_is_parsed = content_range.content_type.len() != 0;
if content_range_is_parsed && content_type_is_parsed {
let mut body : Vec<u8> = vec![];
body = [body, string.as_bytes().to_vec()].concat();
let mut buf = Vec::from(string.as_bytes());
let separator = [SYMBOL.hyphen, SYMBOL.hyphen, Range::STRING_SEPARATOR].join("");
while !buf.starts_with(separator.as_bytes()) {
buf = vec![];
cursor.read_until(b'\n', &mut buf).unwrap();
let separator = [SYMBOL.hyphen, SYMBOL.hyphen, Range::STRING_SEPARATOR].join("");
if !buf.starts_with(separator.as_bytes()) {
body = [body, buf.to_vec()].concat();
}
}
let mut mutable_body : Vec<u8> = body;
mutable_body.pop(); mutable_body.pop();
content_range.body = mutable_body;
content_range_list.push(content_range);
}
let boxed_result = Range::_parse_multipart_body(cursor, content_range_list);
return if boxed_result.is_ok() {
Ok(boxed_result.unwrap())
} else {
let error = boxed_result.err().unwrap();
Err(error)
}
}
pub fn parse_multipart_body_with_boundary(cursor: &mut Cursor<&[u8]>,
mut content_range_list: Vec<ContentRange>,
boundary: String,
total_bytes: i32,
mut bytes_read: i32,
mut is_opening_boundary_read: bool)
-> Result<Vec<ContentRange>, String> {
loop {
let mut buffer = vec![];
let boxed_read = cursor.read_until(b'\n', &mut buffer);
if boxed_read.is_err() {
let message = boxed_read.err().unwrap().to_string();
return Err(message);
}
let bytes_offset = boxed_read.unwrap();
bytes_read = bytes_read + bytes_offset as i32;
if bytes_read == total_bytes {
}
let new_line_char_found = buffer.len() != 0;
let boxed_line = Range::convert_bytes_array_to_string(buffer);
if boxed_line.is_err() {
let message = boxed_line.err().unwrap();
return Err(message);
}
let mut string = boxed_line.unwrap();
if !new_line_char_found {
return Ok(content_range_list)
};
let mut content_range: ContentRange = ContentRange::new();
let content_range_is_not_parsed = content_range.body.len() == 0;
if string.trim().len() != 0 && !is_opening_boundary_read && !string.contains(boundary.as_str()) {
return Err("Response body doesn't start with a boundary".to_string())
}
if string.contains(boundary.as_str()) && content_range_is_not_parsed {
if !is_opening_boundary_read {
is_opening_boundary_read = true;
}
let boxed_line = Range::parse_line_as_bytes(cursor);
if boxed_line.is_err() {
let message = boxed_line.err().unwrap();
return Err(message);
}
buffer = boxed_line.unwrap();
let boxed_line = Range::convert_bytes_array_to_string(buffer);
if boxed_line.is_err() {
let message = boxed_line.err().unwrap();
return Err(message);
}
string = boxed_line.unwrap();
}
let content_type_is_not_parsed = content_range.content_type.len() == 0;
if string.starts_with(Header::_CONTENT_TYPE) && content_type_is_not_parsed {
let boxed_content_type = Response::parse_http_response_header_string(string.as_str());
if boxed_content_type.is_err() {
let message = boxed_content_type.err().unwrap();
return Err(message);
}
let content_type = boxed_content_type.unwrap();
content_range.content_type = content_type.value.trim().to_string();
let boxed_line = Range::parse_line_as_bytes(cursor);
if boxed_line.is_err() {
let message = boxed_line.err().unwrap();
return Err(message);
}
buffer = boxed_line.unwrap();
let boxed_line = Range::convert_bytes_array_to_string(buffer);
if boxed_line.is_err() {
let message = boxed_line.err().unwrap();
return Err(message);
}
string = boxed_line.unwrap();
}
let content_range_is_not_parsed = content_range.size.len() == 0;
if string.starts_with(Header::_CONTENT_RANGE) && content_range_is_not_parsed {
let content_range_header = Response::_parse_http_response_header_string(string.as_str());
let boxed_result = Range::_parse_content_range_header_value(content_range_header.value.into_owned());
if boxed_result.is_ok() {
let (start, end, size) = boxed_result.unwrap();
content_range.size = size.to_string();
content_range.range.start = start as u64;
content_range.range.end = end as u64;
} else {
return Err(boxed_result.err().unwrap())
}
let boxed_line = Range::parse_line_as_bytes(cursor);
if boxed_line.is_err() {
let message = boxed_line.err().unwrap();
return Err(message);
}
buffer = boxed_line.unwrap();
let boxed_line = Range::convert_bytes_array_to_string(buffer);
if boxed_line.is_err() {
let message = boxed_line.err().unwrap();
return Err(message);
}
string = boxed_line.unwrap();
if string.trim().len() > 0 {
return Err(Range::_ERROR_NO_EMPTY_LINE_BETWEEN_CONTENT_RANGE_HEADER_AND_BODY.to_string());
}
}
let content_range_is_parsed = content_range.size.len() != 0;
let content_type_is_parsed = content_range.content_type.len() != 0;
if content_range_is_parsed && content_type_is_parsed {
let mut body : Vec<u8> = vec![];
let mut is_not_boundary = true;
while is_not_boundary {
let mut _bytes_offset = 0;
let mut buf: Vec<u8> = vec![];
let boxed_read = cursor.read_until(b'\n', &mut buf);
if boxed_read.is_err() {
return Err("Unable to read from stream".to_string());
}
_bytes_offset = boxed_read.unwrap();
bytes_read = bytes_read + _bytes_offset as i32;
let boxed_line = Range::convert_bytes_array_to_string(buf.clone());
if boxed_line.is_err() {
body = [body, buf.to_vec()].concat();
continue;
}
string = boxed_line.unwrap();
is_not_boundary = !string.contains(boundary.as_str());
if is_not_boundary {
body = [body, buf.to_vec()].concat();
if (bytes_read == total_bytes) || _bytes_offset == 0 {
return Err("Unable to parse multipart form body, reached the end of stream and it does not contain boundary".to_string());
}
}
}
let mut mutable_body : Vec<u8> = body;
mutable_body.pop(); mutable_body.pop();
content_range.body = mutable_body;
content_range_list.push(content_range);
}
}
}
pub fn parse_line_as_bytes(cursor: &mut Cursor<&[u8]>) -> Result<Vec<u8>, String> {
let mut buffer = vec![];
let boxed_read = cursor.read_until(b'\n', &mut buffer);
if boxed_read.is_err() {
let message = boxed_read.err().unwrap().to_string();
return Err(message);
}
boxed_read.unwrap();
Ok(buffer)
}
pub fn convert_bytes_array_to_string(buffer: Vec<u8>) -> Result<String, String> {
let buffer_as_u8_array: &[u8] = &buffer;
let boxed_string = String::from_utf8(Vec::from(buffer_as_u8_array));
if boxed_string.is_err() {
let message = boxed_string.err().unwrap().to_string();
return Err(message);
}
let string = boxed_string.unwrap();
Ok(string)
}
}