Ugly request payload occurred while uploading documents using BLOB through FormData - javascript

I'm appending a BLOB in the FormData like,
const formData = new FormData();
formData.append('xyz', blob);
While uploading this blob, following is the ugly payload I've seen(this ugly data is too long to show here).
Content-Disposition: form-data; name="xyz"; filename="xyz.png"
Content-Type: image/png
PNG
IHDRà5ÑÜä IDATx^\½i\i¥g¾/A23««» ÂHh©×ZÔ=ÐHúÿ¿#ôQ½Õ$cñݯð<ÇÞ %öp²2Ép¿÷]l9vìØì¿ÿoÿvº\¯õ°¨ût¯óý\÷ºÖz»ªé~©UÝk5j9¿×v³ªÏ_¾Ôùr­Ù|UëÕ¶f³y]n׺MתùTóÅTÓt«ÛíR󥶫}}Ø.....
------WebKitFormBoundary1wDstGejHPb3PhBI
Due to which server is blocking this file to be get uploaded with HTTP 403 Forbidden error. As there are some rules applied at the server side using AWS WAF. These rules are re:SQL injection, XSS, etc.
I think, those rules are blocking the request because of this ugly payload and if I append basic file object(not a BLOB), 403 error is not coming! It works properly with the File Object and this error comes only for BLOB upload.
Let me know your thoughts and how to prevent it!

Related

Https Request payload too large. Help me in understanding the concept

I am trying to send a base64 string of a file in an axios request body. The file size is arond 370KB.
I got request payload too large 413 error. After doing some research in internet learned that server is limiting the request size.
Till now my understanding is clear.
Now I changed it to formData and passing that form data as a request body. And I am not getting any 413 error. Server neatly provessed my request.
So what hapenned between formData and server?
Server is running on Nginx, Node, Express.
By default axios sends data as JSON and on Node.js side JSON parser has a default limit of 100KB. So you can either continue to use formData or increase a limit in JSON parser options.
app.use(json({
limit: '20mb'
}));
But if you intend to send large content often then consider using formData or even send content as binary.
Upd. For FormData if you usually will process it by multer you will have the following limits by default:
Field size: 1048576 bytes
File size: unlimited

Sending large csv file type file in HTTP response

I have been trying to Send large csv type file in HTTP response. I tried using the following
p_response.setHeader("Content-Disposition", "attachment; filename=" + URL.encodeURLFragment(x_filename) + ";");
p_response.setHeader("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
This exports the excel files with small data easily. But when I tried exporting a bigger csv file, instead of downloading the file in csv(comma separated) format, it just dumped the entire data into the web page.
In the Response Headers (in the network tab in chrome), I can see that it does not show the Content-Disposition, Content-Type or the Content-length when sending a large CSV file. It also has
Transfer-Encoding: chunked in the Response Headers (Which is not observed when a csv file with less data is downloaded).
Can anyone please help?
You can solve using blob
csvData = new Blob([csvString], { type: 'text/csv' });
var csvUrl = URL.createObjectURL(csvData);
a.href = csvUrl;
References:
Export HTML table to csv in google chrome browser

error: Bad content type. Please use multipart

I'm totally new to file uploads....I'm using angular-file-upload which creates an XHR outside of angularjs to upload files to google cloud storage. When I try to upload I keep getting the error below. How can I resolve this?
400 Bad content type. Please use multipart.
Here's my controller setup:
var uploader = $scope.uploader = new FileUploader({
url: 'https://www.googleapis.com/upload/storage/v1/b/bucketsbuckets/o?uploadType=multipart',
headers : {
'Authorization': 'Bearer ya29.lgHmbYk-5FgxRElKafV4qdyWsdMjBFoO97S75p4vB0G0d6fryD5LASpf3JUY8Av9Yzhp9cQP8IQqhA',
'Content-Type': 'multipart/form-data'
},
autoUpload:true
});
For those who are using fetch just remove the content-type on your header.
I found this issue on github and I quote:
Setting the Content-Type header manually means it's missing the boundary parameter. Remove that header and allow fetch to generate the full content type. It will look something like this:
Content-Type: multipart/form-data;boundary=----WebKitFormBoundaryyrV7KO0BoCBuDbTL
Fetch knows which content type header to create based on the FormData object passed in as > the request body content.
^^ this one worked for me.
The problem is that the endpoint you're using is for multipart uploads, but not FORM-based multipart uploads. If you set your Content-Type to "multipart/related" instead of "multipart/form-data", you should be able to proceed.
A multipart upload to that endpoint, "www.googleapis.com/upload/storage/etc?uploadType=multipart", expects a multipart message with exactly two parts, the first part being the metadata of the object, in JSON, and the second part being the data.
More on these requirements are here: https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload
If, however, you'd like to do an upload in the style of a form submission, that's also possible, but the rules are different. In this case, you'll submit a POST to "storage.googleapis.com/BUCKET/OBJECT" with a variety of appropriate form parameters: https://cloud.google.com/storage/docs/reference-methods#postobject
Now, this all assumes you're trying to do an upload as a multipart request for some reason. That might be necessary if you need to set some specific metadata properties on the object, but if not, you may be making things harder for yourself. A simple PUT to "storage.googleapis.com/BUCKET/OBJECT" will work just fine (although I'm not familiar with angular-file-upload and don't know whether it supports non-form-style uploads).

Content type for file part of the multipart/form-data request is set wrong by the client

I'm trying to send multipart/form-data with following JavaScript and jQuery:
var formData = new FormData();
formData.append("projectName", $("#projectNameInput").val());
var file = $("#fileInput")[0].files[0];
formData.append("content", file);
var xhr = new XMLHttpRequest();
xhr.open('POST', '/project', true);
xhr.onload = function(ev) {
// Handling logic omitted
};
xhr.send(formData);
However, some client browsers (Firefox and Chrome) receive 400 Bad Request from the server. While examining the headers and request payload I discovered that some browsers set explicit content type for the file as follows:
------WebKitFormBoundaryEuDIpEU2Ci8VNwNJ
Content-Disposition: form-data; name="content"; filename="testfile.ext"
Content-Type: EXT Project Data (64bit)
------WebKitFormBoundaryEuDIpEU2Ci8VNwNJ
In a working request the Content-Type should be as follows: Content-Type: application/octet-stream, which the server can handle properly.
I suspect this has something to do with browser's configuration or file associations. Is there a way to explicitly set the content type for the file part of the request?
The problem occurs with some users using Firefox and Chrome. However, some users are able to upload succesfully using Chrome and Firefox. IE is not supported by our application.
Ok, we managed to figure out this issue. It turned out that the content type registered to the client system was actually malformed on some client machines, that had certain third-party application installed.
We cannot programmatically change the content type browser sets for the part.
As Michael-O pointed out, you should always use content-types registered with the IANA. Here's a link to the standard.
In this case it was third-party software that registered illegal content type to client's system. Content type may not contain white spaces, so the content type EXT Project Data is clearly illegal. We fixed the issue by changing the registered content type to a custom content type. So the content type we are now using is application/x-ext-project-data, which is then handled properly on the server side.

How do I send a file in binary format properly via POST?

When I upload a file the normal way without Ajax, the page reloads, and the POST request payload looks like this when I look at it in the network tab of the Chrome element inspector:
------WebKitFormBoundaryXseUYiNOVZKdYrTk
Content-Disposition: form-data; name="fdata[]"; filename="baby_bot.jpg"
Content-Type: image/jpeg
------WebKitFormBoundaryXseUYiNOVZKdYrTk
Content-Disposition: form-data; name="fdata[]"; filename="dyno_bones.png"
Content-Type: image/png
------WebKitFormBoundaryXseUYiNOVZKdYrTk--
But when I try to create the POST request manually and send the file with ajax by using the FileReader object to read the content of a file in binary format and sending the binary data via the manually created POST request, the payload looks like this in the inspector:
------CustomFormBoundaryXseUYiNOVZKdYrTk
Content-Disposition: form-data; name="fdata[]"; filename="baby_bot.jpg"
Content-Type: image/jpeg
a2q#¡B±Áð$RÑá3ñ%br4C&Scs¢ÂâÿÄ
------CustomFormBoundaryXseUYiNOVZKdYrTk
Content-Disposition: form-data; name="fdata[]"; filename="dyno_bones.png"
Content-Type: image/png
a2q#¡B±Áð$RÑá3ñ%br4C&Scs¢ÂâÿÄ
------CustomFormBoundaryXseUYiNOVZKdYrTk--
Notice that you can see the binary data (represented by those random accented characters) when in the body of the POST request. How can I make my manually created POST request be perfectly identical to that of the browser so that the I get identical results from my PHP handler script? The idea here is that I can emulate the POST requests that the browser sends and not have to modify anything in the PHP backend.
Instead of trying to emulate the POST request data, use the FormData object. Its easy to use and lets you send form data via ajax easily. A FormData object automatically creates and send the appropriate POST request with the help of an XMLHttpRequest object.
The Mozilla documentation includes a nice article on how to use the XMLHttpRequest object which itself includes a nice example on how to use the FormData object.

Categories