gloo icon indicating copy to clipboard operation
gloo copied to clipboard

Blob & ObjecUrl generate invalid dowload link

Open Tartopoms opened this issue 1 year ago • 3 comments

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:

  1. How the download link element is created
  2. How I generate the ObjectUrl with gloo (doesn't work)
  3. How I generate the ObjectUrl with web_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

screenshot

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())
}

Tartopoms avatar Nov 24 '23 13:11 Tartopoms