-
Notifications
You must be signed in to change notification settings - Fork 82
/
multipart.js
138 lines (127 loc) · 4.19 KB
/
multipart.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/**
Multipart Parser (Finite State Machine)
usage:
var multipart = require('./multipart.js');
var body = multipart.DemoData(); // raw body
var body = new Buffer(event['body-json'].toString(),'base64'); // AWS case
var boundary = multipart.getBoundary(event.params.header['content-type']);
var parts = multipart.Parse(body,boundary);
// each part is:
// { filename: 'A.txt', type: 'text/plain', data: <Buffer 41 41 41 41 42 42 42 42> }
author: Cristian Salazar ([email protected]) www.chileshift.cl
Twitter: @AmazonAwsChile
*/
exports.Parse = function(multipartBodyBuffer,boundary){
var process = function(part){
// will transform this object:
// { header: 'Content-Disposition: form-data; name="uploads[]"; filename="A.txt"',
// info: 'Content-Type: text/plain',
// part: 'AAAABBBB' }
// into this one:
// { filename: 'A.txt', type: 'text/plain', data: <Buffer 41 41 41 41 42 42 42 42> }
var obj = function(str){
var k = str.split('=');
var a = k[0].trim();
var b = JSON.parse(k[1].trim());
var o = {};
Object.defineProperty( o , a ,
{ value: b, writable: true, enumerable: true, configurable: true })
return o;
}
var header = part.header.split(';');
var file = obj(header[2]);
var contentType = part.info.split(':')[1].trim();
Object.defineProperty( file , 'type' ,
{ value: contentType, writable: true, enumerable: true, configurable: true })
Object.defineProperty( file , 'data' ,
{ value: new Buffer(part.part), writable: true, enumerable: true, configurable: true })
return file;
}
var prev = null;
var lastline='';
var header = '';
var info = ''; var state=0; var buffer=[];
var allParts = [];
for(i=0;i<multipartBodyBuffer.length;i++){
var oneByte = multipartBodyBuffer[i];
var prevByte = i > 0 ? multipartBodyBuffer[i-1] : null;
var newLineDetected = ((oneByte == 0x0a) && (prevByte == 0x0d)) ? true : false;
var newLineChar = ((oneByte == 0x0a) || (oneByte == 0x0d)) ? true : false;
if(!newLineChar)
lastline += String.fromCharCode(oneByte);
if((0 == state) && newLineDetected){
if(("--"+boundary) == lastline){
state=1;
}
lastline='';
}else
if((1 == state) && newLineDetected){
header = lastline;
state=2;
lastline='';
}else
if((2 == state) && newLineDetected){
info = lastline;
state=3;
lastline='';
}else
if((3 == state) && newLineDetected){
state=4;
buffer=[];
lastline='';
}else
if(4 == state){
if(lastline.length > (boundary.length+4)) lastline=''; // mem save
if(((("--"+boundary) == lastline))){
var j = buffer.length - lastline.length;
var part = buffer.slice(0,j-1);
var p = { header : header , info : info , part : part };
allParts.push(process(p));
buffer = []; lastline=''; state=5; header=''; info='';
}else{
buffer.push(oneByte);
}
if(newLineDetected) lastline='';
}else
if(5==state){
if(newLineDetected)
state=1;
}
}
return allParts;
};
// read the boundary from the content-type header sent by the http client
// this value may be similar to:
// 'multipart/form-data; boundary=----WebKitFormBoundaryvm5A9tzU1ONaGP5B',
exports.getBoundary = function(header){
var items = header.split(';');
if(items)
for(i=0;i<items.length;i++){
var item = (new String(items[i])).trim();
if(item.indexOf('boundary') >= 0){
var k = item.split('=');
return (new String(k[1])).trim();
}
}
return "";
}
exports.DemoData = function(){
body = "trash1\r\n"
body += "------WebKitFormBoundaryvef1fLxmoUdYZWXp\r\n";
body += "Content-Disposition: form-data; name=\"uploads[]\"; filename=\"A.txt\"\r\n";
body += "Content-Type: text/plain\r\n",
body += "\r\n\r\n";
body += "@11X";
body += "111Y\r\n";
body += "111Z\rCCCC\nCCCC\r\nCCCCC@\r\n\r\n";
body += "------WebKitFormBoundaryvef1fLxmoUdYZWXp\r\n";
body += "Content-Disposition: form-data; name=\"uploads[]\"; filename=\"B.txt\"\r\n";
body += "Content-Type: text/plain\r\n",
body += "\r\n\r\n";
body += "@22X";
body += "222Y\r\n";
body += "222Z\r222W\n2220\r\n666@\r\n";
body += "------WebKitFormBoundaryvef1fLxmoUdYZWXp--\r\n";
return (new Buffer(body,'utf-8'));
// returns a Buffered payload, so the it will be treated as a binary content.
};