joltup / rn-fetch-blob

A project committed to making file access and data transfer easier, efficient for React Native developers.
MIT License
2.84k stars 784 forks source link

Failed to fetch when file has spaces in name. #653

Open Natteke opened 4 years ago

Natteke commented 4 years ago

Hello!

When I try to upload a file that has a space in its name (like "FILE A"), I get this error.

Failed to create form data from content URI:content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2FFILE A.docx, Permission Denial: reading com.android.providers.downloads.DownloadStorageProvider uri content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2FFILE A.docx from pid=28475, uid=10155 requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs

image

code:

await RNFetchBlob.fetch('POST', url, {
        token: 'token',
    }, [
        {
            name: 'file0',
            filename: file.name,
            data: RNFetchBlob.wrap(decodeURI(fileURI)),
        },
    ]);

If you remove the space from the name, everything works fine.

env platform: Android react-native: "0.62.2", rn-fetch-blob: "^0.12.0" minSdkVersion = 23 compileSdkVersion = 28 targetSdkVersion = 28

p.s: RNFB.fs.exist(uri) returns true p.p.s:"FILE_A" for example uploads fine.

Natteke commented 4 years ago

Created a repro-repo with fresh RN https://github.com/Crysp/rn-files-test

1) install node-modules 2) run react native 3) run android emulator / real device 4) drag 2 files from assets to emulator ('file_a', 'file a') 5) press 'select' button, and select file to upload 6) find error in console

In repo i used google.com, but no matter which url is selected, because error happens before network request.

In summary it was reproduced in RN 0.61.5, 0.62.2, 0.63.*. I suppose that the RN version does not matter.

Crysp commented 4 years ago

I have the same issue

Natteke commented 4 years ago

As workaround we could get base64 file data from react-native-fs, and pass it as "data", according to RNFetchBlob API.

Code below works for me. PS. Not tested in IOS

    const fileURI = file.uri.replace('file://', '');
    const fileBase64 = await RNFS.readFile(fileURI, 'base64');

    await RNFetchBlob.fetch('POST', url, {
        'Content-Type': 'multipart/form-data',
    }, [
        {
            name: 'file0',
            filename: file.name,
            data: fileBase64,
        },
    ]);
cpecorari commented 4 years ago

Hi, had the problem too, solved it like this as path is not interpreted the same way in iOS and Android :

filename: file.name.replace(/\s/g, '_'),
name: 'files[]',
data:
        Platform.OS === 'ios'
          ? 'RNFetchBlob-' + decodeURI(file.uri)
          : RNFetchBlob.wrap(file.uri.replace(/file:\/\//g, ''))
waqaramjad commented 3 years ago

same issue here

AireshBhat commented 3 years ago

Encode the URI as well as shown below:

await RNFetchBlob.fetch('POST', encodeURI(url), {
        token: 'token',
    }, [
        {
            name: 'file0',
            filename: file.name,
            data: RNFetchBlob.wrap(decodeURI(fileURI)),
        },
    ]);