Blob & ObjecUrl generate invalid dowload link
Bug description
Either gloo::file::Blob::new(bytes.as_slice()) generated an invalid Blob,
or gloo::file::ObjectUrl::from(blob) generates an invalid ObjectUrl.
However, it works with web_sys.
Steps to Reproduce
Summary:
- How the download link element is created
- How I generate the
ObjectUrlwithgloo(doesn't work) - How I generate the
ObjectUrlwithweb_sys(works)
1. How the download link element is created
Download link example with Dioxus. See full example at the end
rsx!(
a {
href: download_url(),
download: "sample.txt",
"Download file"
}
)
2. How I generate the object url with gloo (the one that failed)
use gloo::file::{Blob as gloo_Blob, ObjectUrl};
/// Generate a downlaod file url using gloo
/// /!\ Not working
pub fn download_url(blob: Vec<u8>) -> &'static str {
let blob = gloo_Blob::new(blob.as_slice());
let obj_url = ObjectUrl::from(blob);
let download_url = obj_url.to_string();
Box::leak(download_url.to_string().into_boxed_str())
}
3. How I generate the ObjectUrl with web_sys (the one that succeed)
use web_sys::{js_sys::{Uint8Array, Array}, Blob as web_sys_Blob, Url};
/// Generate a downlaod file url using web_sys
pub fn download_url(bytes: Vec<u8>) -> &'static str {
let uint8arr = Uint8Array::new(&unsafe { Uint8Array::view(&bytes) }.into());
let array = Array::of1(&uint8arr.buffer());
let blob = web_sys_Blob::new_with_u8_array_sequence(&array).unwrap();
let download_url = Url::create_object_url_with_blob(&blob).unwrap();
Box::leak(download_url.to_string().into_boxed_str())
}
Expected Behavior
Being able to downlaod the uploaded file
Actual Behavior
Network error appear in the 'browser download' pannel instantly after download started. See image below.
Translation "Téléchargements "-> Downloads "Ouvrir un fichier" -> Open a file "Impossible de télécharger - Problème de réseau" -> Cannot download - Network issue
Full example to reproduce
The main.rs.txt file contains the code shown below.
1. Run with:
dx serve
Install dx with
cargo install dioxus-cli
2. Cargo.toml
[dependencies]
dioxus-web = { version = "0.4.0" }
dioxus = { version = "0.4.0" }
gloo = { version = "0.10.0" }
web-sys = { version = "0.3.65" }
3. How-to-reproduce main.rs.txt file content:
use dioxus::prelude::*;
use gloo::file::{Blob as gloo_Blob, ObjectUrl};
use web_sys::{js_sys::{Array, Uint8Array},Blob as web_sys_Blob, Url,};
fn main() {
dioxus_web::launch(app);
}
fn app(cx: Scope) -> Element {
// Shared value for file name, and content
let filename = use_state(cx, String::new);
let filecontent = use_state(cx, Vec::<u8>::new);
// Closure for onchange file input handler
let file_input_onchange = |evt: Event<FormData>| {
to_owned![filename];
to_owned![filecontent];
async move {
let file_engine = &evt.files.clone().expect("Failed to get file_engine");
let files = file_engine.files();
let name = files.get(0).expect("Failed to get the uploaded file");
let content = file_engine
.read_file(name)
.await
.expect("Failed to read file");
filename.set(name.clone());
filecontent.set(content);
}
};
render! {
// upload file input, takes a onchange handler closure to retrieve the file name and blob
input {
r#type: "file",
onchange: file_input_onchange,
}
// will spawn two download button when a file is uploaded
if !filename.is_empty() && !filecontent.is_empty() {
rsx!(
ul {
li {
a {
href: gloo_download_url(filecontent.get().clone()),
download: "{filename.get().clone()}",
"gloo download of {filename.get().clone()}"
}
}
li {
a {
href: web_sys_download_url(filecontent.get().clone()),
download: "{filename.get().clone()}",
"web_sys download of {filename.get().clone()}"
}
}
}
)
}
}
}
/// Generate a downlaod file url using gloo
/// /!\ Not working
pub fn gloo_download_url(blob: Vec<u8>) -> &'static str {
let blob = gloo_Blob::new(blob.as_slice());
let obj_url = ObjectUrl::from(blob);
let download_url = obj_url.to_string();
Box::leak(download_url.to_string().into_boxed_str())
}
/// Generate a downlaod file url using web_sys
pub fn web_sys_download_url(bytes: Vec<u8>) -> &'static str {
let uint8arr = Uint8Array::new(&unsafe { Uint8Array::view(&bytes) }.into());
let array = Array::of1(&uint8arr.buffer());
let blob = web_sys_Blob::new_with_u8_array_sequence(&array).unwrap();
let download_url = Url::create_object_url_with_blob(&blob).unwrap();
Box::leak(download_url.to_string().into_boxed_str())
}
Did you figure this out @Tartopoms. I am using firefox and the web_sys_download_url works fine, but yours or the slightly different,
let blob = Blob::new_with_options(byte_slice, Some("application/pdf"));
let object_url = ObjectUrl::from(blob);
let download_url = object_url.to_string();
fails with
Security Error: Content at http:localhost:XXXXXXXX may not load data from blob:http:localhost:XXXX`, which is probably the same error you got but with the GUI.
@dmatos2012, I didn't figure it out, I stuck to the web_sys solution because it wasn't a major problem to me.
Same issue on gloo 0.11.0.