Skip to content

Blob & ObjecUrl generate invalid dowload link  #406

Description

@Tartopoms

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions