Pawel Uchida-Psztyc
Pawel Uchida-Psztyc

Reputation: 3838

Creating multipart/form-data request in own library in javascript

I tried to search for solution (for 2 days now) bot nothing helps me.

Because of many reasons I was forced to write own library in JavaScript to build a multipart/dorm-data body.

I checked how other libraries (for node) works and I read the spec. Then I wrote the code (https://github.com/jarrodek/ChromeRestClient/blob/files/app/elements/payload-editor/multipart-form-data.js) which is quite simple because the spec is.

However, my test server do not recognise parameters in the request. Any parameters (text or files).

My library generates generating the following HTTP message:

([NL] represents new line character which is \r\n)

POST /post HTTP/1.1[NL]
HOST: localhost:8081[NL]
content-type: multipart/form-data; boundary=-------------805520824430161118507807[NL]
content-length: 17789[NL]

-------------805520824430161118507807[NL]
Content-Disposition: form-data; name="image"; filename="arc-icon.png"[NL]
Content-Type: image/png[NL]
[NL]
�PNG[NL]
[binary data for about ~17700 bytes)[NL]
[NL]
-------------805520824430161118507807--[NL]

This is snapshot what is actually passed to a socket. The library builds the HTTP message and converts it into the ArrayBuffer which is an argument in socket send function.

Now, I know there's some issue with my code, I just can't find it. I tried to add new line after message part (as in the code above) or not (after image data I always adding new line). Maybe someone can see an issue with the message here and point it out because I have no more ideas how to fix it :)

Upvotes: 1

Views: 1264

Answers (2)

Pawel Uchida-Psztyc
Pawel Uchida-Psztyc

Reputation: 3838

Finally found it. The issue was with the boundary. According to spec body parts are separated from each other with two dash (-) signs and the boundary string defined in content type. This two dashes missing in my message.

So the correct version of the message body is:

POST /post HTTP/1.1[NL]
HOST: localhost:8081[NL]
content-type: multipart/form-data; boundary=-------------805520824430161118507807[NL]
content-length: 17789[NL]

---------------805520824430161118507807[NL]
Content-Disposition: form-data; name="image"; filename="arc-icon.png"[NL]
Content-Type: image/png[NL]
[NL]
�PNG[NL]
[binary data for about ~17700 bytes)[NL]
[NL]
---------------805520824430161118507807--[NL]

Upvotes: 1

guest271314
guest271314

Reputation: 1

Not sure how I can get HTTP body message from FormData :) I can only do it using Fetch API and the request object.

You can iterate FormData object, call .blob(), first, then pass Blob to new Response() with .arrayBuffer() chained.

<input name="files" type="file" accepts="image/*" multiple="multiple">
<script>
  document.querySelector("input[type=file]")
    .onchange = (e) => {
      const [files, fd, arr] = [e.target.files, new FormData(), Array()];

      for (let file of files) {
        console.log(file);
        fd.append(`file-${[...fd.keys()].length}`, file, file.name);
      }

      for (let [prop] of fd) {
        let request = new Request("/", {
          method: "POST",
          body: fd.get(prop)
        });
        arr.push(
          request.blob()
          .then(blob => new Response(blob).arrayBuffer())
        )
      }

      Promise.all(arr)
        .then(buffers => {
          for (let ab of buffers) {
            console.log(ab);
            let img = new Image;
            img.onload = () => {
              document.body.appendChild(img)
            }
            let url = URL.createObjectURL(new Blob([ab]));
            img.src = url;
          }
        })
    }
</script>

To read "multipart/form-data" use .text() chained to Request() then parse returned data using String or RegExp methods.

Upvotes: 0

Related Questions