1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | var multiparty = require('multiparty');
|
14 | var qs = require('qs');
|
15 | var typeis = require('type-is');
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 | exports = module.exports = function(options){
|
38 | options = options || {};
|
39 |
|
40 | return function multipart(req, res, next) {
|
41 | if (req._body) return next();
|
42 | req.body = req.body || {};
|
43 | req.files = req.files || {};
|
44 |
|
45 |
|
46 | if ('GET' === req.method || 'HEAD' === req.method) return next();
|
47 |
|
48 |
|
49 | if (!typeis(req, 'multipart/form-data')) return next();
|
50 |
|
51 |
|
52 | req._body = true;
|
53 |
|
54 |
|
55 | var form = new multiparty.Form(options);
|
56 | var data = {};
|
57 | var files = {};
|
58 | var waitend = true;
|
59 | var done = false;
|
60 |
|
61 | req.on('aborted', cleanup)
|
62 | req.on('end', cleanup)
|
63 | req.on('error', cleanup)
|
64 |
|
65 | function cleanup() {
|
66 | waitend = false;
|
67 | req.removeListener('aborted', cleanup);
|
68 | req.removeListener('end', cleanup);
|
69 | req.removeListener('error', cleanup);
|
70 | }
|
71 |
|
72 | function ondata(name, val, data){
|
73 | if (Array.isArray(data[name])) {
|
74 | data[name].push(val);
|
75 | } else if (data[name]) {
|
76 | data[name] = [data[name], val];
|
77 | } else {
|
78 | data[name] = val;
|
79 | }
|
80 | }
|
81 |
|
82 | form.on('field', function(name, val){
|
83 | ondata(name, val, data);
|
84 | });
|
85 |
|
86 | form.on('file', function(name, val){
|
87 | val.name = val.originalFilename;
|
88 | val.type = val.headers['content-type'] || null;
|
89 | ondata(name, val, files);
|
90 | });
|
91 |
|
92 | form.on('error', function(err){
|
93 | if (done) return;
|
94 |
|
95 | done = true;
|
96 | err.status = 400;
|
97 |
|
98 | process.nextTick(function(){
|
99 | if (waitend && req.readable) {
|
100 |
|
101 | req.resume();
|
102 | req.once('end', function onEnd() {
|
103 | next(err)
|
104 | });
|
105 | return;
|
106 | }
|
107 |
|
108 | next(err);
|
109 | });
|
110 | });
|
111 |
|
112 | form.on('close', function() {
|
113 | if (done) return;
|
114 |
|
115 | done = true;
|
116 |
|
117 | try {
|
118 | req.body = qs.parse(data);
|
119 | req.files = qs.parse(files);
|
120 | next();
|
121 | } catch (err) {
|
122 | err.status = 400;
|
123 | next(err);
|
124 | }
|
125 | });
|
126 |
|
127 | form.parse(req);
|
128 | }
|
129 | };
|