Skip to content

Commit 621e72a

Browse files
committed
fix: handle (& part) files and fields correctly
as mentioned here #531 (comment) Signed-off-by: Charlike Mike Reagent <[email protected]>
1 parent 15f174f commit 621e72a

File tree

5 files changed

+109
-85
lines changed

5 files changed

+109
-85
lines changed

.eslintignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ test-legacy
1212
*.cache
1313

1414
# TODO: lint
15-
example
15+
# example
1616
benchmark
1717

1818
# Build environment

example/json.js

Lines changed: 44 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1+
'use strict';
2+
13
const http = require('http');
24
const util = require('util');
3-
const common = require('../test/common');
4-
5-
const { formidable } = common;
6-
const { port } = common;
7-
let server;
5+
const Formidable = require('../src/index');
86

9-
server = http.createServer((req, res) => {
7+
// random OS choosen port
8+
const PORT = 13532;
9+
const server = http.createServer((req, res) => {
1010
if (req.method !== 'POST') {
1111
res.writeHead(200, { 'content-type': 'text/plain' });
12-
res.end(`Please POST a JSON payload to http://localhost:${port}/`);
12+
res.end(`Please POST a JSON payload to http://localhost:${PORT}/`);
1313
return;
1414
}
1515

16-
const form = new formidable.IncomingForm();
16+
const form = new Formidable();
1717
const fields = {};
1818

1919
form
@@ -33,41 +33,43 @@ server = http.createServer((req, res) => {
3333
});
3434
form.parse(req);
3535
});
36-
server.listen(port);
3736

38-
console.log(`listening on http://localhost:${port}/`);
37+
server.listen(PORT, () => {
38+
const choosenPort = server.address().port;
39+
console.log(`Listening on http://localhost:${choosenPort}/`);
3940

40-
const message = '{"numbers":[1,2,3,4,5],"nested":{"key":"value"}}';
41-
const request = http.request(
42-
{
43-
host: 'localhost',
44-
path: '/',
45-
port,
46-
method: 'POST',
47-
headers: {
48-
'content-type': 'application/json',
49-
'content-length': message.length,
41+
const message = '{"numbers":[1,2,3,4,5],"nested":{"key":"value"}}';
42+
const request = http.request(
43+
{
44+
host: 'localhost',
45+
path: '/',
46+
port: choosenPort,
47+
method: 'POST',
48+
headers: {
49+
'content-type': 'application/json',
50+
'content-length': message.length,
51+
},
5052
},
51-
},
52-
(response) => {
53-
const data = '';
54-
console.log('\nServer responded with:');
55-
console.log('Status:', response.statusCode);
56-
response.pipe(process.stdout);
57-
response.on('end', () => {
58-
console.log('\n');
59-
process.exit();
60-
});
61-
// response.on('data', function(chunk) {
62-
// data += chunk.toString('utf8');
63-
// });
64-
// response.on('end', function() {
65-
// console.log('Response Data:');
66-
// console.log(data);
67-
// process.exit();
68-
// });
69-
},
70-
);
53+
(response) => {
54+
console.log('\nServer responded with:');
55+
console.log('Status:', response.statusCode);
56+
response.pipe(process.stdout);
57+
response.on('end', () => {
58+
console.log('\n');
59+
process.exit();
60+
});
61+
// const data = '';
62+
// response.on('data', function(chunk) {
63+
// data += chunk.toString('utf8');
64+
// });
65+
// response.on('end', function() {
66+
// console.log('Response Data:');
67+
// console.log(data);
68+
// process.exit();
69+
// });
70+
},
71+
);
7172

72-
request.write(message);
73-
request.end();
73+
request.write(message);
74+
request.end();
75+
});

example/multipartParser.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
const { MultipartParser } = require('../lib/multipart_parser.js');
1+
'use strict';
2+
3+
const { MultipartParser } = require('../src/multipart_parser.js');
24

35
// hand crafted multipart
46
const boundary = '--abcxyz';
57
const next = '\r\n';
68
const formData = 'Content-Disposition: form-data; ';
7-
const buffer = Buffer.from(
8-
`${boundary}${next}${formData}name="text"${next}${next}text ...${next}${next}${boundary}${next}${formData}name="z"${next}${next}text inside z${next}${next}${boundary}${next}${formData}name="file1"; filename="a.txt"${next}Content-Type: text/plain${next}${next}Content of a.txt.${next}${next}${boundary}${next}${formData}name="file2"; filename="a.html"${next}Content-Type: text/html${next}${next}<!DOCTYPE html><title>Content of a.html.</title>${next}${next}${boundary}--`,
9+
const bufferToWrite = Buffer.from(
10+
`${boundary}${next}${formData}name="text"${next}${next}some text ...${next}${next}${boundary}${next}${formData}name="z"${next}${next}text inside z${next}${next}${boundary}${next}${formData}name="file1"; filename="a.txt"${next}Content-Type: text/plain${next}${next}Content of a.txt.${next}${next}${boundary}${next}${formData}name="file2"; filename="a.html"${next}Content-Type: text/html${next}${next}<!DOCTYPE html><title>Content of a.html.</title>${next}${next}${boundary}--`,
911
);
1012

1113
const multipartParser = new MultipartParser();
@@ -22,5 +24,6 @@ multipartParser.on('error', (error) => {
2224

2325
multipartParser.initWithBoundary(boundary.substring(2)); // todo make better error message when it is forgotten
2426
// const shouldWait = !multipartParser.write(buffer);
27+
multipartParser.write(bufferToWrite);
2528
multipartParser.end();
2629
// multipartParser.destroy();

example/multiple.js

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,36 @@
1+
'use strict';
2+
3+
const os = require('os');
14
const http = require('http');
25
const util = require('util');
3-
const os = require('os');
4-
const common = require('../test/common');
6+
const Formidable = require('../src/index');
57

6-
const { formidable } = common;
7-
const { port } = common;
8-
let server;
9-
10-
server = http.createServer((req, res) => {
8+
const PORT = 13532;
9+
const server = http.createServer((req, res) => {
1110
if (req.url === '/') {
1211
res.writeHead(200, { 'content-type': 'text/html' });
1312
res.end(
1413
`<form action="/upload" enctype="multipart/form-data" method="post">
15-
<label>simple<input type="text" name="simple"></label><br>
14+
<label>simple<input type="text" name="text_single" autofocus /></label><br />
1615
17-
<label>array text 0<input type="text" name="atext[]"></label><br>
18-
<label>array text 1<input type="text" name="atext[]"></label><br>
16+
<label>array text 0<input type="text" name="text_multiple[]" /></label><br />
17+
<label>array text 1<input type="text" name="text_multiple[]" /></label><br />
1918
20-
<label>file simple<input type="file" name="filesimple"></label><br>
19+
<label>file simple<input type="file" name="file_single" /></label><br />
2120
22-
<label>file attribute multiple<input type="file" name="multiplefile" multiple></label><br>
21+
<label>file attribute multiple<input type="file" name="file_multiple" multiple /></label><br />
2322
24-
<label>file html array0<input type="file" name="filearray[]"></label><br>
25-
<label>file html array1<input type="file" name="filearray[]"></label><br>
23+
<label>file html array0<input type="file" name="filearray[]" /></label><br />
24+
<label>file html array1<input type="file" name="filearray[]" /></label><br />
2625
27-
<label>file html array and mulitple0<input type="file" name="mfilearray[]" multiple></label><br>
28-
<label>file html array and mulitple1<input type="file" name="mfilearray[]" multiple></label><br>
29-
<br>
26+
<label>file html array and mulitple0<input type="file" name="filearray_with_multiple[]" multiple /></label><br />
27+
<label>file html array and mulitple1<input type="file" name="filearray_with_multiple[]" multiple /></label><br />
28+
<br />
3029
<button>Upload</button>
3130
</form>`,
3231
);
3332
} else if (req.url === '/upload') {
34-
const form = new formidable.IncomingForm({ multiples: true });
33+
const form = new Formidable({ multiples: true });
3534

3635
form.uploadDir = os.tmpdir();
3736

@@ -46,6 +45,7 @@ server = http.createServer((req, res) => {
4645
res.end('404');
4746
}
4847
});
49-
server.listen(port);
5048

51-
console.log(`listening on http://localhost:${port}/`);
49+
server.listen(PORT, () => {
50+
console.log(`listening on http://localhost:${PORT}/`);
51+
});

src/incoming_form.js

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -95,28 +95,37 @@ class IncomingForm extends EventEmitter {
9595
} else {
9696
fields[name] = value;
9797
}
98-
})
99-
.on('file', (name, file) => {
100-
// TODO: too much nesting
101-
if (this.multiples) {
102-
if (hasOwnProp(files, name)) {
103-
if (!Array.isArray(files[name])) {
104-
files[name] = [files[name]];
105-
}
106-
files[name].push(file);
107-
} else {
108-
files[name] = file;
98+
// if (name === 'simple') {
99+
// console.log('fields name!!', name);
100+
// console.log('fields value!!', value);
101+
// }
102+
});
103+
this.on('file', (name, file) => {
104+
// TODO: too much nesting
105+
if (this.multiples) {
106+
if (hasOwnProp(files, name)) {
107+
if (!Array.isArray(files[name])) {
108+
files[name] = [files[name]];
109109
}
110+
files[name].push(file);
110111
} else {
111112
files[name] = file;
112113
}
113-
})
114-
.on('error', (err) => {
115-
cb(err, fields, files);
116-
})
117-
.on('end', () => {
118-
cb(null, fields, files);
119-
});
114+
} else {
115+
files[name] = file;
116+
}
117+
// console.log('files!!', files);
118+
// if (name === 'simple') {
119+
// console.log('files name!!', name);
120+
// console.log('files value!!', file);
121+
// }
122+
});
123+
this.on('error', (err) => {
124+
cb(err, fields, files);
125+
});
126+
this.on('end', () => {
127+
cb(null, fields, files);
128+
});
120129
}
121130

122131
// Parse headers and setup the parser, ready to start listening for data.
@@ -191,8 +200,18 @@ class IncomingForm extends EventEmitter {
191200
}
192201

193202
handlePart(part) {
203+
if (part.filename && typeof part.filename !== 'string') {
204+
this._error(new Error(`the part.filename should be string when exists`));
205+
return;
206+
}
207+
194208
// This MUST check exactly for undefined. You can not change it to !part.filename.
195-
if (part.filename === undefined) {
209+
210+
// @tunnckocore: no it can be any falsey value, it most probably depends on what's returned
211+
// from somewhere else. Where recently I changed the return statements
212+
// and such thing because code style
213+
// @tunnckocore: or even better, if there is no mime, then it's for sure a field
214+
if (!part.mime) {
196215
let value = '';
197216
const decoder = new StringDecoder(this.encoding);
198217

0 commit comments

Comments
 (0)