UNPKG

parse-multipart

Version:

A javascript/nodejs multipart/form-data parser which operates on raw data.

139 lines (127 loc) 4.29 kB
/** 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 (christiansalazarh@gmail.com) 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. };