Skip to content

Commit

Permalink
fix(core): use safe_block_on (#7047)
Browse files Browse the repository at this point in the history
fixes regression introduced in 45330e3

ref: #6375 (comment)
  • Loading branch information
amrbashir authored May 24, 2023
1 parent 359058c commit 2317913
Showing 1 changed file with 98 additions and 87 deletions.
185 changes: 98 additions & 87 deletions core/tauri/src/asset_protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub fn asset_protocol_handler(

let mut resp = ResponseBuilder::new().header("Access-Control-Allow-Origin", &window_origin);

crate::async_runtime::block_on(async move {
let (mut file, len, mime_type, read_bytes) = crate::async_runtime::safe_block_on(async move {
let mut file = File::open(&path).await?;

// get file length
Expand All @@ -72,91 +72,99 @@ pub fn asset_protocol_handler(
)
};

resp = resp.header(CONTENT_TYPE, &mime_type);

// handle 206 (partial range) http requests
let response = if let Some(range_header) = request
.headers()
.get("range")
.and_then(|r| r.to_str().map(|r| r.to_string()).ok())
{
resp = resp.header(ACCEPT_RANGES, "bytes");

let not_satisfiable = || {
ResponseBuilder::new()
.status(StatusCode::RANGE_NOT_SATISFIABLE)
.header(CONTENT_RANGE, format!("bytes */{len}"))
.body(vec![])
};

// parse range header
let ranges = if let Ok(ranges) = HttpRange::parse(&range_header, len) {
ranges
.iter()
// map the output to spec range <start-end>, example: 0-499
.map(|r| (r.start, r.start + r.length - 1))
.collect::<Vec<_>>()
} else {
return not_satisfiable();
};
Ok::<(File, u64, String, Option<Vec<u8>>), anyhow::Error>((file, len, mime_type, read_bytes))
})?;

/// The Maximum bytes we send in one range
const MAX_LEN: u64 = 1000 * 1024;
resp = resp.header(CONTENT_TYPE, &mime_type);

// single-part range header
if ranges.len() == 1 {
let &(start, mut end) = ranges.first().unwrap();
// handle 206 (partial range) http requests
let response = if let Some(range_header) = request
.headers()
.get("range")
.and_then(|r| r.to_str().map(|r| r.to_string()).ok())
{
resp = resp.header(ACCEPT_RANGES, "bytes");

// check if a range is not satisfiable
//
// this should be already taken care of by the range parsing library
// but checking here again for extra assurance
if start >= len || end >= len || end < start {
return not_satisfiable();
}
let not_satisfiable = || {
ResponseBuilder::new()
.status(StatusCode::RANGE_NOT_SATISFIABLE)
.header(CONTENT_RANGE, format!("bytes */{len}"))
.body(vec![])
};

// parse range header
let ranges = if let Ok(ranges) = HttpRange::parse(&range_header, len) {
ranges
.iter()
// map the output to spec range <start-end>, example: 0-499
.map(|r| (r.start, r.start + r.length - 1))
.collect::<Vec<_>>()
} else {
return not_satisfiable();
};

/// The Maximum bytes we send in one range
const MAX_LEN: u64 = 1000 * 1024;

// single-part range header
if ranges.len() == 1 {
let &(start, mut end) = ranges.first().unwrap();

// adjust end byte for MAX_LEN
end = start + (end - start).min(len - start).min(MAX_LEN - 1);
// check if a range is not satisfiable
//
// this should be already taken care of by the range parsing library
// but checking here again for extra assurance
if start >= len || end >= len || end < start {
return not_satisfiable();
}

// calculate number of bytes needed to be read
let nbytes = end + 1 - start;
// adjust end byte for MAX_LEN
end = start + (end - start).min(len - start).min(MAX_LEN - 1);

// calculate number of bytes needed to be read
let nbytes = end + 1 - start;

let buf = crate::async_runtime::safe_block_on(async move {
let mut buf = Vec::with_capacity(nbytes as usize);
file.seek(SeekFrom::Start(start)).await?;
file.take(nbytes).read_to_end(&mut buf).await?;
Ok::<Vec<u8>, anyhow::Error>(buf)
})?;

resp = resp.header(CONTENT_RANGE, format!("bytes {start}-{end}/{len}"));
resp = resp.header(CONTENT_LENGTH, end + 1 - start);
resp = resp.status(StatusCode::PARTIAL_CONTENT);
resp.body(buf)
} else {
resp = resp.header(CONTENT_RANGE, format!("bytes {start}-{end}/{len}"));
resp = resp.header(CONTENT_LENGTH, end + 1 - start);
resp = resp.status(StatusCode::PARTIAL_CONTENT);
resp.body(buf)
} else {
let ranges = ranges
.iter()
.filter_map(|&(start, mut end)| {
// filter out unsatisfiable ranges
//
// this should be already taken care of by the range parsing library
// but checking here again for extra assurance
if start >= len || end >= len || end < start {
None
} else {
// adjust end byte for MAX_LEN
end = start + (end - start).min(len - start).min(MAX_LEN - 1);
Some((start, end))
}
})
.collect::<Vec<_>>();

let boundary = random_boundary();
let boundary_sep = format!("\r\n--{boundary}\r\n");
let boundary_closer = format!("\r\n--{boundary}\r\n");

resp = resp.header(
CONTENT_TYPE,
format!("multipart/byteranges; boundary={boundary}"),
);

let buf = crate::async_runtime::safe_block_on(async move {
// multi-part range header
let mut buf = Vec::new();
let ranges = ranges
.iter()
.filter_map(|&(start, mut end)| {
// filter out unsatisfiable ranges
//
// this should be already taken care of by the range parsing library
// but checking here again for extra assurance
if start >= len || end >= len || end < start {
None
} else {
// adjust end byte for MAX_LEN
end = start + (end - start).min(len - start).min(MAX_LEN - 1);
Some((start, end))
}
})
.collect::<Vec<_>>();

let boundary = random_boundary();
let boundary_sep = format!("\r\n--{boundary}\r\n");
let boundary_closer = format!("\r\n--{boundary}\r\n");

resp = resp.header(
CONTENT_TYPE,
format!("multipart/byteranges; boundary={boundary}"),
);

for (end, start) in ranges {
// a new range is being written, write the range boundary
Expand Down Expand Up @@ -184,24 +192,27 @@ pub fn asset_protocol_handler(
// all ranges have been written, write the closing boundary
buf.write_all(boundary_closer.as_bytes()).await?;

resp.body(buf)
}
Ok::<Vec<u8>, anyhow::Error>(buf)
})?;
resp.body(buf)
}
} else {
// avoid reading the file if we already read it
// as part of mime type detection
let buf = if let Some(b) = read_bytes {
b
} else {
// avoid reading the file if we already read it
// as part of mime type detection
let buf = if let Some(b) = read_bytes {
b
} else {
crate::async_runtime::safe_block_on(async move {
let mut local_buf = Vec::with_capacity(len as usize);
file.read_to_end(&mut local_buf).await?;
local_buf
};
resp = resp.header(CONTENT_LENGTH, len);
resp.body(buf)
Ok::<Vec<u8>, anyhow::Error>(local_buf)
})?
};
resp = resp.header(CONTENT_LENGTH, len);
resp.body(buf)
};

response
})
response
}

fn random_boundary() -> String {
Expand Down

0 comments on commit 2317913

Please sign in to comment.