3

So I have this form:

  <form id="myForm" enctype="multipart/form-data">
      <input id="name" title="name" type="text" placeholder="name" />
      <input id="quantity" title="quantity" type="text" placeholder="quantity" />
      <input id="price" title="price" type="text" placeholder="price" />
      <input id="imageLocation" title="imageLocation" type="text" placeholder="imagelocation" />
      <input id="description" title="description" type="text" placeholder="description" />
  </form>

Here Is where I send the data:

 function postMultiPartHttpCall() {
    var XHR = new XMLHttpRequest();

    var form = document.getElementById("myForm");

    var FD = new FormData(form);

    XHR.addEventListener("load", function (event) {
        var callingObj = {};
        callingObj.responseText = event.target.responseText;
        console.log(callingObj);
    });

    XHR.open("POST", '/articlePost');
    XHR.send(FD);
}

And here is where I receive it:

    function _processFormData (request, res, onSuccess,onError) {
    var requestBody = '';
    request.on('data', function (data) {
        requestBody += data;
        if (requestBody.length > 1e7) {
            res.writeHead(413, 'Request length too long', { 'Content-Type': 'text/html' });
            res.end('413 : Request Entity Too Large');
        }
    });

    request.on('end', function () {
        var oFormData = qsLib.parse(requestBody);
        console.log(request.headers);

    });
}

So when I send some data I receive this (console.log):

Debugger listening on 127.0.0.1:5858
Server was started
{ host: 'localhost:1337',
connection: 'keep-alive',
'content-length': '44',
origin: 'http://localhost:1337',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36     (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36',
'content-type': 'multipart/form-data; boundary=----WebKitFormBoundaryyVFw7KZwIaAIQeQ1',
accept: '*/*',
referer: 'http://localhost:1337/CartSPA.html',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'en-US,en;q=0.8,hr;q=0.6,de-AT;q=0.4,de;q=0.2,de-DE;q=0.2' }

So what I want is to get an object with the fields of form without using expressJS or other similar 3rd party libraries. Is it possible to get the attributes using the boundary number or where can I see which data was sent?

Sᴀᴍ Onᴇᴌᴀ
  • 8,218
  • 8
  • 36
  • 58

3 Answers3

6

Yes it is "possible to get the attributes using the boundary number", though you will have to match the fields and parse out the names manually...

Also, in order to have the values from the form get sent, the attribute name needs to be set on the input tags. For example:

<input id="quantity" title="quantity" type="text" placeholder="quantity" />

Should be updated to contain a name attribute, like below:

<input name="quantity" id="quantity" title="quantity" type="text" placeholder="quantity" />

With the name attributes set on the form fields, the body of the request should contain the form data (i.e. requestBody should then have the contents of the encoded form when the data is done being loaded). For example, it may look similar to the output below:

-----------------------------150182554619156
Content-Disposition: form-data; name="name"

z4520
-----------------------------150182554619156
Content-Disposition: form-data; name="quantity"

2
-----------------------------150182554619156
Content-Disposition: form-data; name="price"

32.90
-----------------------------150182554619156
Content-Disposition: form-data; name="imagelocation"

/img/z4520.jpg
-----------------------------150182554619156
Content-Disposition: form-data; name="description"

water filter
-----------------------------150182554619156--

###Parsing out the form fields

In the starter code below, it checks the request header Content-Type for the boundary (you might also want to ensure the Content-Type is in fact "multipart/form-data") using String.indexOf() and then sets the boundary using String.split() and taking the 2nd element from the resultant array. That boundary value can be used to separate the body data into an array (also using String.split()).

I will leave it as an exercise for the reader to parse out the values and store them in an array (see @TODO; ).

Hint: Array.reduce() might come in very handy...

request.on('end', function() {
    if (request.headers.hasOwnProperty('content-type') && request.headers['content-type'].indexOf('boundary=') > -1) {
        var parts = request.headers['content-type'].split('boundary=');
        var boundary = parts[1];
        var splitBody = requestBody.split(boundary);
        /**
         @TODO: iterate over elements in splitBody, matching name and value and add to array of fields
        */

        res.writeHead(200, {"Content-Type": "application/json"});
        res.write(JSON.stringify({formFields: splitBody}));
    }
    else {
        //bad request
        res.writeHead(400, {"Content-Type": "application/json"});
        res.write("missing boundary in content-type"));
    }
    res.end();
});
Sᴀᴍ Onᴇᴌᴀ
  • 8,218
  • 8
  • 36
  • 58
0

Use https://github.com/felixge/node-formidable:

var formidable = require('formidable'),
    http = require('http'),
    util = require('util');

http.createServer(function(req, res) {
  if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
    // parse a file upload
    var form = new formidable.IncomingForm();

    form.parse(req, function(err, fields, files) {
      res.writeHead(200, {'content-type': 'text/plain'});
      res.write('received upload:\n\n');
      res.end(util.inspect({fields: fields, files: files}));
    });

    return;
  }

  // show a file upload form
  res.writeHead(200, {'content-type': 'text/html'});
  res.end(
    '<form action="/upload" enctype="multipart/form-data" method="post">'+
    '<input type="text" name="title"><br>'+
    '<input type="file" name="upload" multiple="multiple"><br>'+
    '<input type="submit" value="Upload">'+
    '</form>'
  );
}).listen(8080);
Sergey Yarotskiy
  • 4,536
  • 2
  • 19
  • 27
  • @SergeyYaratskiy is it possible without using any libraries? So that I can the form data just by using boundary number or content-disposition? –  May 26 '17 at 00:09
  • For sure, from library I gave you, check out file https://github.com/felixge/node-formidable/blob/master/lib/incoming_form.js#L273, start from line 273 for example. – Sergey Yarotskiy May 26 '17 at 00:15
  • hmm I still need user libraries such as multipart_parser –  May 26 '17 at 00:39
0

I have been using the npm module multiparty. It is pretty straight forward.

In your request handler, do something like this.

var form = new multiparty.Form();
form.parse(req, function(err, fields, files) {
  res.writeHead(200, {'content-type': 'text/plain'});
  res.write('received upload:\n\n');
  res.end(util.inspect({fields: fields, files: files}));
});
Jay Shepherd
  • 503
  • 4
  • 6
  • is it possible using it without any libraries. So just splitting the boundary or get the data using content-disposition –  May 26 '17 at 00:40
  • Of course you can. But you have to parse the whole HTTP request including the headers.Can i ask why you don't want to use modules? If they are pure JS modules then there is really no difference if you use them or write it yourself. p.s Sorry I hate to be that guy, who says "why are you doing it like that" when there may be a good reason. – Jay Shepherd May 26 '17 at 01:21
  • I know, but in the school project in which I am involved we aren't allowed to use any libraries. So basically we should rebuild a module. I don't know why... –  May 26 '17 at 11:43