0

According to this SO post the boundary value of the header Content-Type can be changed, MDN says the same too. But in my case it doesn't happen, I don't get it why.

When I inspect the console (Chrome, Firefox), the header is set correctly, as I defined it: content-type: multipart/form-data; boundary=aBoundaryString

At the same time when I look at the request (in the console) I see data separated by ------WebKitFormBoundarymdIB1kNGNJ3dldnm in Chrome, and some big number-boundary in Firefox.


I use PHP on server side, and in this case when I try to read request data there via var_dump(file_get_contents('php://input')) I get result as string(0) "".

I have to say, that when I set the Content-Type header without "boundary", like this: content-type: multipart/form-data (and this is what I see in the console too), in this case the Request Payload is also separated with the same browser boundaries, but in this case, on the server side, request data is not empty, but as it should be and separated with same boundaries which I see in browser console.


So what's the problem, why can't I change the boundary? I mean it's definitely set, because I see that in the header Content-Type, but why isn't it applied to the request?


Screenshots from the Firefox v100 console

first 3 images is a request without boundary value

enter image description here enter image description here enter image description here

next 3 images is a request with boundary value

enter image description here enter image description here enter image description here


there's no difference if the file (uploads) is attached or not, result the same; and as I said in Chrome result the same

request sent via XMLHttpRequest, headers set by setRequestHeader()


Update

Okay, I've made my data to get to the server even with "boundary". For that I added " to the value, now it's like this:

content-type: "multipart/form-data; boundary=aBoundaryString"

before was like this:

content-type: multipart/form-data; boundary=aBoundaryString

BUT! The the boundary is still not applied, the Request Payload is still has browser's boundary, not mine. I've also printed $_SERVER["CONTENT_TYPE"] and there's "multipart/form-data; boundary=aBoundaryString". What's the problem?

  • https://www.php.net/manual/en/wrappers.php.php: _"php://input is not available with `enctype="multipart/form-data"`."_ – CBroe Jun 22 '22 at 12:37
  • A couple of things to look for here are if your server timed out (closed the connection before the request was completely sent) or if the request was malformed (you could trybinspecting it with wireshark for example). – Sherif Jun 22 '22 at 12:38
  • Well @CBroe this is strange, because as I said when the header is set to the `content-type: multipart/form-data` without "boundary", I have a correct value in `php://input`. And in both cases i.e. with custom "boundary" and without it, the `$_POST` is an empty Array! – SizuNakomoto Jun 22 '22 at 13:24
  • It probably would have some sense @Sherif, but I have to repeat that when the content-type header is `content-type: multipart/form-data` without "boundary" value, everything is normal, request is good, data sent by browser and received by server side correctly, I see no anomalies in this case – SizuNakomoto Jun 22 '22 at 13:31
  • Sending `multipart/form-data` _without_ a boundary, that doesn't make much sense to begin with. Without it, the receiver would have to _guess_ what the actual parts are. – CBroe Jun 22 '22 at 13:40
  • Let me ask you this @CBroe, I've read the info of your link, and I don't know why, but there is stated what you said, still you have my answer on that and I said the truth, my `$_POST` array is empty with `enctype="multipart/form-data"` and the `php://input` is not, but okay, tell this, how do I get the request data on server side sent with `enctype="multipart/form-data"`? – SizuNakomoto Jun 22 '22 at 13:42
  • The receiver @CBroe anyway get the boundary, because is it's not set the browser do it, so I guess the receiver have nothing to guess. If I understand correctly, when I explicitly specify the boundary, in my case, the problem is that the data is empty on the server because the receiver does not read it, because he sees a mismatch between the boundary in the header (which I set) and the boundary in the request (which set by browser itself) – SizuNakomoto Jun 22 '22 at 13:46
  • _"but okay, tell this, how do I get the request data on server side sent with enctype="multipart/form-data"?"_ - well by using $_POST, and if file uploads are also part of your request, $_FILES. – CBroe Jun 22 '22 at 13:50
  • The $_POST and $_FILES are an empty array with enctype="multipart/form-data", php://input is not without explicit set boundary, uploads are presented, that's why I use multipart/form-data. – SizuNakomoto Jun 22 '22 at 13:53
  • Well then I guess your request might simply be faulty - but you haven't given us any real details of what exactly you are sending, and how. – CBroe Jun 22 '22 at 13:58
  • Well @CBroe then I added **Screenshots** – SizuNakomoto Jun 22 '22 at 14:49

1 Answers1

1

The boundary is used to mark the edge between each part of a multipart request.

The Content-Type header needs to specify what string of characters is used to mark the boundary.

Thus, the Content-Type header needs to match the actual boundary.


You've shown us the code you are using to generate the Content-Type header. It's a hard-coded string.

You haven't shown us the code you are using to generate the request body. Whatever it is, it is generating a body that uses a different string to mark the boundary to the one you claimed it was using when you set the Content-Type header.

Since they don't match, the parser can't find the boundary that it is looking for.


While you haven't shown us what you are using to generate the body, it's a reasonable assumption that you are passing a FormData object.

The browser will generate a multipart request body from it, and it will generate a boundary that is safe (i.e. one that doesn't match any data actually in the object).

Under normal circumstances, the browser will also generate the correct Content-Type header from it … but you're overriding it.

Don't do that.

Let the browser infer the Content-Type header without your interference.


 const options = {
     method: 'POST',
     body: new FormData(document.querySelector('form')),
     // headers: // Stop. Leave the headers alone.
 };
 const response = await fetch(url, options);
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • F**k I hate this, I mean you're right, I tested, it works without explicit set content-type... and I saw somewhere that in some cases it must be this way, why didn't I try... now I have everything in the `$_POST` and `$_FILES`, and of course this is more convenient than parsing `php://input`, but I hate it, because I see it as a lack of some documentation, why not to mention this somewhere, except SO... why put it like I can control "this boundary", it turns out that not quite, at least not in all cases. @Quentin you my Tarantino :) the rest of the day saved! – SizuNakomoto Jun 22 '22 at 16:24