Skip to content

Commit

Permalink
Fix multipart file upload.
Browse files Browse the repository at this point in the history
  • Loading branch information
fpereiro committed Jun 27, 2017
1 parent c511b77 commit 363380b
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 22 deletions.
54 changes: 36 additions & 18 deletions hitit.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
hitit - v1.0.0
hitit - v1.1.0
Written by Federico Pereiro (fpereiro@gmail.com) and released into the public domain.
*/
Expand Down Expand Up @@ -69,24 +69,10 @@ Written by Federico Pereiro (fpereiro@gmail.com) and released into the public do

o.headers = dale.obj (o.headers || {}, teishi.c (state.headers) || {}, function (v, k) {return [k, v]});

if (type (o.body) === 'object' && o.body.multipart) {
var multipart = type (o.body) === 'object' && o.body.multipart;
if (multipart) {
var boundary = Math.floor (Math.random () * Math.pow (10, 16));
var content = type (o.body.multipart) === 'array' ? o.body.multipart : [o.body.multipart];
o.body = '';
o.headers ['content-type'] = 'multipart/form-data; boundary=' + boundary;
dale.do (content, function (v) {
if (type (v) !== 'object') return log ('Invalid multipart file or field!');
if (v.path && ! v.filename) v.filename = Path.basename (v.path);

o.body += '--' + boundary + '\r\n' + 'Content-Disposition: form-data; name="' + v.name + '";';
if (v.filename) o.body += ' filename="' + encodeURIComponent (v.filename) + '"';
var contentType = v.contentType || (v.path ? mime.lookup (v.path) : (teishi.complex (v.value) ? 'application/json' : 'text/plain'));
o.body += '\r\nContent-Type: ' + contentType + '; charset=utf-8';
o.body += '\r\n\r\n';
o.body += v.path ? fs.readFileSync (v.path, 'utf8') : (teishi.complex (v.value) ? teishi.s (v.value) : v.value);
o.body += '\r\n';
});
o.body += '--' + boundary + '--\r\n';
}

else if (teishi.complex (o.body)) {
Expand Down Expand Up @@ -158,7 +144,39 @@ Written by Federico Pereiro (fpereiro@gmail.com) and released into the public do
if (! timeout) cb ({code: -1, error: error.toString (), request: o});
});

request.end (o.body);
if (! multipart) request.end (o.body);
else {
var content = type (o.body.multipart) === 'array' ? o.body.multipart : [o.body.multipart];

var queue = [], counter = 1, rwrite = function (what, enc, p) {
if (p === undefined) {
p = counter++;
queue.push (p);
}
if (Math.min.apply (Math, queue) === p) {
request.write (what, enc, function () {
queue.splice (queue.indexOf (p), 1);
if (queue.length === 0) request.end ();
});
}
else setTimeout (function () {
rwrite (what, enc, p);
}, 1);
}

dale.do (content, function (v) {
if (type (v) !== 'object') return log ('Invalid multipart file or field!', v);
if (v.path && ! v.filename) v.filename = Path.basename (v.path);
rwrite ('--' + boundary + '\r\n' + 'Content-Disposition: form-data; name="' + v.name + '";');
if (v.filename) rwrite (' filename="' + encodeURIComponent (v.filename) + '"');
var contentType = v.contentType || (v.path ? mime.lookup (v.path) : (teishi.complex (v.value) ? 'application/json' : 'text/plain'));
if (contentType !== 'application/octet-stream') rwrite ('\r\nContent-Type: ' + contentType + '; charset=utf-8');
rwrite ('\r\n\r\n');
rwrite (v.path ? fs.readFileSync (v.path, 'binary') : (teishi.complex (v.value) ? teishi.s (v.value) : v.value + ''), v.path ? 'binary' : 'utf8');
rwrite ('\r\n');
});
rwrite ('--' + boundary + '--\r\n');
}
}

h.seq = function (state, seq, cb, map) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hitit",
"version": "1.0.0",
"version": "1.1.0",
"description": "Minimalistic tool for API testing.",
"dependencies": {
"dale": "4.3.0",
Expand Down
6 changes: 3 additions & 3 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ hitit is a minimalistic tool for testing an HTTP(S) API. It is a stopgap until I

## Current status of the project

The current version of hitit, v1.0.0, is considered to be *somewhat stable* and *somewhat complete*. [Suggestions](https://github.com/fpereiro/hitit/issues) and [patches](https://github.com/fpereiro/hitit/pulls) are welcome. Future changes planned are:
The current version of hitit, v1.1.0, is considered to be *somewhat stable* and *somewhat complete*. [Suggestions](https://github.com/fpereiro/hitit/issues) and [patches](https://github.com/fpereiro/hitit/pulls) are welcome. Future changes planned are:

- Improve multipart/form-data (there's at least one bug related to uploading binary files).
- Allow empty tests.
- Support for concurrent testing (a.k.a stress testing).

## Installation
Expand Down Expand Up @@ -91,7 +91,7 @@ In this case, notice that `host` and `port` are not defined and must hence be pa

## Source code

The complete source code is contained in `hitit.js`. It is about 210 lines long.
The complete source code is contained in `hitit.js`. It is about 230 lines long.

## License

Expand Down

0 comments on commit 363380b

Please sign in to comment.