`Http.uploadFile()` has a request `content-length` of 0, resulting in a 0-byte file upload
Describe the support request
How can I use this plugin to upload an image file with Http.post()?
I can't use Http.uploadFile() because my Drupal backend requires a CSRF token.
To Reproduce
In axios, I post a file like this:
const arrayStr = await readFileBlob(fileBlob) as ArrayBuffer;
axiosAuthConfig.post(
fetchUrl, arrayStr, {
headers: {
'Content-Disposition': 'file; filename="mypic.jpg"',
'Content-Type': 'application/octet-stream',
},
},
)
Here's readFileBlob():
// https://stackoverflow.com/a/46568146
function readFileBlob(fileBlob: Blob) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = () => {
// console.log('reader RESULT', reader.result);
resolve(reader.result);
};
reader.onabort = () => Promise.reject(Error('file reading was aborted'));
reader.onerror = () => Promise.reject(Error('file reading has failed'));
reader.readAsArrayBuffer(fileBlob);
});
}
I tried to do the same thing with Http.post(). Here is the config:
const fetchPostFileOptions = (url: string, data: unknown): HttpOptions => ({
method: 'POST',
url,
data,
headers: {
Accept: JSONAPI,
Cache: 'no-cache',
'Content-Disposition': 'file; filename="mypic.jpg"',
'Content-Type': 'application/octet-stream',
},
webFetchExtra: {
credentials: 'include',
},
});
And then here is where I call Http:
const options = fetchPostFileOptions(fetchUrl, arrayStr);
const csrfToken = await getCsrfToken();
if (typeof csrfToken === 'string' && options.headers) {
options.headers['X-CSRF-Token'] = csrfToken;
}
return (Http.request(options));
The axios request posts successfully, and the Http request fails to post with an nginx 502 errror.
When I check Chrome Dev Tools, I see that the request headers are identical except that the content-length is only 2 for Http and 200,000+ for axios.
So, somehow the file is not getting sent properly with Http. What do I need to do to get it working, or is this not supported?
Does using Http.uploadFile() function not fit your use case? If not, could you post a small, reproducible example so I could take a look at it?
After some more attempts, I managed to get the same error with Http.uploadFile().
Here's my code:
const postAuthFileBlob = async (
fetchUrl: string, fileBlob: Blob,
): Promise<any> => {
const csrfToken = await getCsrfToken();
if (typeof csrfToken !== 'string') {
throw new Error('Could not get CSRF token!');
}
const options = {
url: fetchUrl,
name: 'profile_pic',
blob: fileBlob,
headers: {
// Drupal's JSON:API requires the next two lines.
'Content-Disposition': 'file; filename="profile_pic.jpg"',
'Content-Type': 'application/octet-stream',
// Drupal needs a csrfToken for auth users to POST.
'X-CSRF-Token': csrfToken,
},
method: 'POST',
webFetchExtra: {
credentials: 'include' as RequestCredentials,
},
};
return (Http.uploadFile(options).then((response) => (
console.log('response', response);
)).catch((error) => {
console.log('postFileError', error, error.message);
}));
};
This code results in a successful POST-- but, on the server, the file profile_pic.jpg is a 0-byte file.
The file does not appear to be reaching the server, because in Chrome Dev tools, I'm seeing content-length: 0 in the POST Request Headers. When I upload with axios using the code in the original post, the length is 200,000+.
I am guessing this is because when I supply blob to Http.uploadFile, it needs to be read into an array buffer for Drupal to accept it (as I do with axios in the function readFileBlob() in the original post).
I'm going to continue to debug this, but to make sure I'm going in the right direction, am I correct in assuming that if http.uploadFile() is working properly, the content-length in the Request Headers should always be much larger than 0?