Skip to content

Commit 6ffdc34

Browse files
committed
Basic form (no files) working
1 parent 28f166d commit 6ffdc34

5 files changed

Lines changed: 191 additions & 0 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*.un~
2+
/node_modules/*
3+
/test/tmp

lib/form_data.js

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
var http = require('http');
2+
var oop = require('oop');
3+
var Stream = require('stream').Stream;
4+
5+
module.exports = FormData;
6+
oop.extend(FormData, Stream);
7+
var formData = FormData.prototype;
8+
9+
function FormData() {
10+
Stream.call(this);
11+
12+
this.readable = true;
13+
this.paused = true;
14+
15+
this._parts = [];
16+
this._streamPart = null;
17+
18+
this._boundary = null;
19+
this._partBegin = null;
20+
}
21+
22+
formData._init = function() {
23+
// This generates a 50 character boundary similar to those used by Firefox.
24+
// They are optimized for boyer-moore parsing.
25+
var boundary = '--------------------------';
26+
for (var i = 0; i < 24; i++) {
27+
boundary += Math.floor(Math.random() * 10).toString(16);
28+
}
29+
30+
this._partBegin = new Buffer('--' + boundary + '\r\n');
31+
this._boundary = boundary;
32+
};
33+
34+
formData.getBoundary = function() {
35+
if (!this._boundary) {
36+
this._init();
37+
}
38+
39+
return this._boundary;
40+
};
41+
42+
formData.append = function(name, value) {
43+
this._parts.push({
44+
name: name,
45+
value: value,
46+
});
47+
};
48+
49+
formData.pipe = function(destination) {
50+
var r = Stream.prototype.pipe.call(this, destination);
51+
this.resume();
52+
return r;
53+
};
54+
55+
formData.resume = function() {
56+
if (!this._boundary) {
57+
this._init();
58+
}
59+
60+
this.paused = false;
61+
process.nextTick(this._emitData.bind(this));
62+
};
63+
64+
formData.pause = function() {
65+
this.paused = true;
66+
//if (this._streamPart) {
67+
//this._streamPart.pause();
68+
//}
69+
};
70+
71+
formData._emitData = function() {
72+
if (this.paused) {
73+
return;
74+
}
75+
76+
var part = this._parts.shift();
77+
if (!part) {
78+
return;
79+
}
80+
81+
if (part.value instanceof Stream) {
82+
this._emitStreamPart(part);
83+
} else {
84+
this._emitRegularPart(part);
85+
}
86+
};
87+
88+
formData._emitRegularPart = function(part) {
89+
var header = 'Content-Disposition: form-data; name="' + part.name + '"';
90+
header += '\r\n\r\n';
91+
92+
this.emit('data', this._partBegin);
93+
this.emit('data', new Buffer(header + part.value + '\r\n', 'utf8'));
94+
95+
if (this._parts.length === 0) {
96+
this._emitEndBoundary();
97+
this.readable = false;
98+
}
99+
};
100+
101+
formData._emitEndBoundary = function() {
102+
this.emit('data', new Buffer('--' + this._boundary + '--\r\n'));
103+
};

test/common.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
var common = module.exports;
2+
var path = require('path');
3+
4+
var rootDir = path.join(__dirname, '..');
5+
common.dir = {
6+
lib: rootDir + '/lib',
7+
fixture: rootDir + '/test/fixture',
8+
tmp: rootDir + '/test/tmp',
9+
};
10+
11+
common.assert = require('assert');
12+
common.fake = require('fake');
13+
14+
common.port = 8432;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
var common = require('../common');
2+
var assert = common.assert;
3+
4+
var FormData = require(common.dir.lib + '/form_data');
5+
6+
(function testOneBoundaryPerForm() {
7+
var form = new FormData();
8+
var boundary = form.getBoundary();
9+
10+
assert.equal(boundary, form.getBoundary());
11+
assert.equal(boundary.length, 50);
12+
})();
13+
14+
(function testUniqueBoundaryPerForm() {
15+
var formA = new FormData();
16+
var formB = new FormData();
17+
assert.notEqual(formA.getBoundary(), formB.getBoundary());
18+
})();

test/integration/test-pipe.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
var common = require('../common');
2+
var assert = common.assert;
3+
var http = require('http');
4+
var FormData = require(common.dir.lib + '/form_data');
5+
var IncomingForm = require('formidable').IncomingForm;
6+
7+
var FIELDS = [
8+
{name: 'my_field', value: 'my_value'},
9+
{name: 'my_buffer', value: new Buffer([1, 2, 3])},
10+
];
11+
12+
var server = http.createServer(function(req, res) {
13+
var form = new IncomingForm();
14+
form.parse(req);
15+
form
16+
.on('field', function(name, value) {
17+
var field = FIELDS.shift();
18+
assert.strictEqual(name, field.name);
19+
assert.strictEqual(value, field.value+'');
20+
})
21+
.on('end', function() {
22+
res.writeHead(200);
23+
res.end('done');
24+
});
25+
});
26+
27+
server.listen(common.port, function() {
28+
var form = new FormData();
29+
FIELDS.forEach(function(field) {
30+
form.append(field.name, field.value);
31+
});
32+
33+
var http = require('http');
34+
35+
var request = http.request({
36+
method: 'post',
37+
port: common.port,
38+
path: '/upload',
39+
headers: {
40+
'Content-Type': 'multipart/form-data; boundary=' + form.getBoundary(),
41+
}
42+
});
43+
44+
form.pipe(request);
45+
form.on('data', function(chunk) {
46+
//process.stderr.write(chunk+'');
47+
});
48+
49+
request.on('response', function(res) {
50+
server.close();
51+
});
52+
});
53+

0 commit comments

Comments
 (0)