Skip to content

Commit 03fc92c

Browse files
authored
fix(core): resolve request instead of panicking on asset protocol (#3347)
1 parent 3d92f4c commit 03fc92c

3 files changed

Lines changed: 69 additions & 33 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": patch
3+
---
4+
5+
Resolve `asset` protocol HTTP request instead of panicking if the file does not exist or cannot be read.

core/tauri/src/manager.rs

Lines changed: 63 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -519,34 +519,56 @@ impl<R: Runtime> WindowManager<R> {
519519
.to_string();
520520

521521
if !asset_scope.is_allowed(&path) {
522-
return HttpResponseBuilder::new()
523-
.status(403)
524-
.body(Vec::with_capacity(0));
522+
#[cfg(debug_assertions)]
523+
eprintln!("asset protocol not configured to allow the path: {}", path);
524+
return HttpResponseBuilder::new().status(403).body(Vec::new());
525525
}
526526

527-
let path_for_data = path.clone();
527+
let path_ = path.clone();
528528

529529
let mut response =
530530
HttpResponseBuilder::new().header("Access-Control-Allow-Origin", &window_origin);
531531

532532
// handle 206 (partial range) http request
533-
if let Some(range) = request.headers().get("range").cloned() {
534-
let mut status_code = 200;
535-
let path_for_data = path_for_data.clone();
533+
if let Some(range) = request
534+
.headers()
535+
.get("range")
536+
.and_then(|r| r.to_str().map(|r| r.to_string()).ok())
537+
{
536538
let (headers, status_code, data) = crate::async_runtime::safe_block_on(async move {
537539
let mut headers = HashMap::new();
538540
let mut buf = Vec::new();
539-
let mut file = tokio::fs::File::open(path_for_data.clone()).await.unwrap();
541+
// open the file
542+
let mut file = match tokio::fs::File::open(path_.clone()).await {
543+
Ok(file) => file,
544+
Err(e) => {
545+
#[cfg(debug_assertions)]
546+
eprintln!("Failed to open asset: {}", e);
547+
return (headers, 404, buf);
548+
}
549+
};
540550
// Get the file size
541-
let file_size = file.metadata().await.unwrap().len();
551+
let file_size = match file.metadata().await {
552+
Ok(metadata) => metadata.len(),
553+
Err(e) => {
554+
#[cfg(debug_assertions)]
555+
eprintln!("Failed to read asset metadata: {}", e);
556+
return (headers, 404, buf);
557+
}
558+
};
542559
// parse the range
543-
let range =
544-
crate::runtime::http::HttpRange::parse(range.to_str().unwrap(), file_size).unwrap();
560+
let range = match crate::runtime::http::HttpRange::parse(&range, file_size) {
561+
Ok(r) => r,
562+
Err(e) => {
563+
#[cfg(debug_assertions)]
564+
eprintln!("Failed to parse range: {:?}", e);
565+
return (headers, 400, buf);
566+
}
567+
};
545568

546569
// FIXME: Support multiple ranges
547570
// let support only 1 range for now
548-
let first_range = range.first();
549-
if let Some(range) = first_range {
571+
let status_code = if let Some(range) = range.first() {
550572
let mut real_length = range.length;
551573
// prevent max_length;
552574
// specially on webview2
@@ -559,8 +581,6 @@ impl<R: Runtime> WindowManager<R> {
559581
// last byte we are reading, the length of the range include the last byte
560582
// who should be skipped on the header
561583
let last_byte = range.start + real_length - 1;
562-
// partial content
563-
status_code = 206;
564584

565585
headers.insert("Connection", "Keep-Alive".into());
566586
headers.insert("Accept-Ranges", "bytes".into());
@@ -570,12 +590,22 @@ impl<R: Runtime> WindowManager<R> {
570590
format!("bytes {}-{}/{}", range.start, last_byte, file_size),
571591
);
572592

573-
file
574-
.seek(std::io::SeekFrom::Start(range.start))
575-
.await
576-
.unwrap();
577-
file.take(real_length).read_to_end(&mut buf).await.unwrap();
578-
}
593+
if let Err(e) = file.seek(std::io::SeekFrom::Start(range.start)).await {
594+
#[cfg(debug_assertions)]
595+
eprintln!("Failed to seek file to {}: {}", range.start, e);
596+
return (headers, 422, buf);
597+
}
598+
599+
if let Err(e) = file.take(real_length).read_to_end(&mut buf).await {
600+
#[cfg(debug_assertions)]
601+
eprintln!("Failed read file: {}", e);
602+
return (headers, 422, buf);
603+
}
604+
// partial content
605+
206
606+
} else {
607+
200
608+
};
579609

580610
(headers, status_code, buf)
581611
});
@@ -584,19 +614,20 @@ impl<R: Runtime> WindowManager<R> {
584614
response = response.header(k, v);
585615
}
586616

587-
if !data.is_empty() {
588-
let mime_type = MimeType::parse(&data, &path);
589-
return response.mimetype(&mime_type).status(status_code).body(data);
590-
}
591-
}
592-
593-
if let Ok(data) =
594-
crate::async_runtime::safe_block_on(async move { tokio::fs::read(path_for_data).await })
595-
{
596617
let mime_type = MimeType::parse(&data, &path);
597-
response.mimetype(&mime_type).body(data)
618+
response.mimetype(&mime_type).status(status_code).body(data)
598619
} else {
599-
response.status(404).body(Vec::new())
620+
match crate::async_runtime::safe_block_on(async move { tokio::fs::read(path_).await }) {
621+
Ok(data) => {
622+
let mime_type = MimeType::parse(&data, &path);
623+
response.mimetype(&mime_type).body(data)
624+
}
625+
Err(e) => {
626+
#[cfg(debug_assertions)]
627+
eprintln!("Failed to read file: {}", e);
628+
response.status(404).body(Vec::new())
629+
}
630+
}
600631
}
601632
});
602633
}

examples/api/src-tauri/tauri.conf.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@
101101
},
102102
"protocol": {
103103
"asset": true,
104-
"assetScope": ["$RESOURCE/**"]
104+
"assetScope": ["$RESOURCE/**", "$APP/**"]
105105
},
106106
"http": {
107107
"scope": ["https://jsonplaceholder.typicode.com/todos/*"]

0 commit comments

Comments
 (0)