gloo
gloo copied to clipboard
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
ObjectUrl
withgloo
(doesn't work) - How I generate the
ObjectUrl
withweb_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())
}