From fc01a4401f71fddb8effd806f7cffff623edb022 Mon Sep 17 00:00:00 2001 From: Atsushi Nakatsugawa Date: Tue, 26 Jul 2016 22:37:46 +0900 Subject: [PATCH 1/2] Support Form data --- index.js | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 5314e7b..a5faaba 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,6 @@ var words = require('shellwords') +var url = require('url') // TODO -F, --form // TODO --data-binary @@ -49,7 +50,9 @@ module.exports = exports.default = function(s) { case arg == '-b' || arg =='--cookie': state = 'cookie' break; - + case arg == "--data-binary": + state = 'form' + break; case arg == '--compressed': out.header['Accept-Encoding'] = out.header['Accept-Encoding'] || 'deflate, gzip' break; @@ -65,6 +68,23 @@ module.exports = exports.default = function(s) { out.header['User-Agent'] = arg state = '' break; + case 'form': + if (out.method == 'GET' || out.method == 'HEAD') out.method = 'POST' + out.header['Content-Type'] = out.header['Content-Type'] || 'application/x-www-form-urlencoded' + form_data = arg.split(";"); + var boundary = form_data[0].match(/^\$(.*?)r\\n/)[1]; + re = new RegExp('^\\sname=\"(.*)\"\\\\r\\\\n\\\\r\\\\n(.*?)\\\\r\\\\n'+boundary.replace(/\-/g, "\\-")); + out.body = {}; + for (var index in form_data) { + if (index == 0) + continue; + var string = form_data[index]; + if (m = re.exec(string)) { + out.body[m[1]] = m[2]; + } + } + state = '' + break; case 'data': if (out.method == 'GET' || out.method == 'HEAD') out.method = 'POST' out.header['Content-Type'] = out.header['Content-Type'] || 'application/x-www-form-urlencoded' @@ -89,7 +109,6 @@ module.exports = exports.default = function(s) { break; } }) - return out } From 9ef28c25ec15fd1760c46874e663de78bcedc55f Mon Sep 17 00:00:00 2001 From: Atsushi Nakatsugawa Date: Wed, 27 Jul 2016 00:36:24 +0900 Subject: [PATCH 2/2] Write test --- index.js | 25 +++++++++++++++++++++---- test.js | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index a5faaba..c7a0282 100644 --- a/index.js +++ b/index.js @@ -16,7 +16,7 @@ module.exports = exports.default = function(s) { var args = rewrite(words.split(s)) var out = { method: 'GET', header: {} } var state = '' - + var boundary = "" args.forEach(function(arg){ switch (true) { case isURL(arg): @@ -62,6 +62,10 @@ module.exports = exports.default = function(s) { case 'header': var field = parseField(arg) out.header[field[0]] = field[1] + if (field[0] == 'Content-Type') { + if (match = field[1].match(/boundary=(.*?)$/)) + boundary = match[1] + } state = '' break; case 'user-agent': @@ -71,9 +75,12 @@ module.exports = exports.default = function(s) { case 'form': if (out.method == 'GET' || out.method == 'HEAD') out.method = 'POST' out.header['Content-Type'] = out.header['Content-Type'] || 'application/x-www-form-urlencoded' - form_data = arg.split(";"); - var boundary = form_data[0].match(/^\$(.*?)r\\n/)[1]; - re = new RegExp('^\\sname=\"(.*)\"\\\\r\\\\n\\\\r\\\\n(.*?)\\\\r\\\\n'+boundary.replace(/\-/g, "\\-")); + form_data = arg.split("form-data;"); + if (typeof window != 'undefined') { + re = new RegExp('^\\sname="(.*)"\\\\r\\\\n\\\\r\\\\n(.*?)\\\\r\\\\n--'+boundary) + } else { + re = new RegExp('^\\sname="(.*)"\\r\\n\\r\\n(.*?)\\r\\n--'+boundary) + } out.body = {}; for (var index in form_data) { if (index == 0) @@ -81,6 +88,16 @@ module.exports = exports.default = function(s) { var string = form_data[index]; if (m = re.exec(string)) { out.body[m[1]] = m[2]; + } else { + // Upload file + if (typeof window != 'undefined') { + re2 = new RegExp('^\\sname="(.*)";.*?filename="(.*?)"\\\\r\\\\n(.*?)\\\\r\\\\n\\\\r\\\\n\\\\r\\\\n--'+boundary) + } else { + re2 = new RegExp('^\\sname="(.*)";.*?filename="(.*?)"\\r\\n(.*?)\\r\\n\\r\\n\\r\\n--'+boundary) + } + if (m = re2.exec(string)) { + out.body[m[1]] = {filename: m[2]}; + } } } state = '' diff --git a/test.js b/test.js index b4f57bb..b9019ae 100644 --- a/test.js +++ b/test.js @@ -179,6 +179,42 @@ cases.push({ header: { 'Set-Cookie': 'species=sloth;type=galactic' } } }) +cases.push({ + input: 'curl \'https://api.sloths.com\' -H \'Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryJ3Km5hSrAfDw4a9q\' --data-binary $\'------WebKitFormBoundaryJ3Km5hSrAfDw4a9q\r\nContent-Disposition: form-data; name="close"\r\n\r\n\r\n------WebKitFormBoundaryJ3Km5hSrAfDw4a9q\r\nContent-Disposition: form-data; name="body"\r\n\r\nhello world!\r\n------WebKitFormBoundaryJ3Km5hSrAfDw4a9q\r\nContent-Disposition: form-data; name="type"\r\n\r\n0\r\n------WebKitFormBoundaryJ3Km5hSrAfDw4a9q\r\nContent-Disposition: form-data; name="icon"; filename=""\r\nContent-Type: application/octet-stream\r\n\r\n\r\n------WebKitFormBoundaryJ3Km5hSrAfDw4a9q--\r\n\'', + output: { + method: "POST", + header: { + "Content-Type":"multipart/form-data; boundary=----WebKitFormBoundaryJ3Km5hSrAfDw4a9q" + }, + url: 'https://api.sloths.com', + body: { + close: "", + body: "hello world!", + type: 0, + icon: {filename: ""} + } + } +}) + +cases.push({ + input: 'curl \'https://api.sloths.com\' -H \'Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryHKOJEwZFCnY9xIEy\' --data-binary $\'------WebKitFormBoundaryHKOJEwZFCnY9xIEy\r\nContent-Disposition: form-data; name="show"\r\n\r\n615727\r\n------WebKitFormBoundaryHKOJEwZFCnY9xIEy\r\nContent-Disposition: form-data; name="body"\r\n\r\nhello world!\r\n------WebKitFormBoundaryHKOJEwZFCnY9xIEy\r\nContent-Disposition: form-data; name="type"\r\n\r\n0\r\n------WebKitFormBoundaryHKOJEwZFCnY9xIEy\r\nContent-Disposition: form-data; name="icon"; filename="testorig.jpg"\r\nContent-Type: image/jpeg\r\n\r\n\r\n------WebKitFormBoundaryHKOJEwZFCnY9xIEy\r\nContent-Disposition: form-data; name="serviceId"\r\n\r\nAAA\r\n------WebKitFormBoundaryHKOJEwZFCnY9xIEy\r\nContent-Disposition: form-data; name="accessToken"\r\n\r\nBBB\r\n------WebKitFormBoundaryHKOJEwZFCnY9xIEy--\r\n\'', + output: { + method: "POST", + header: { + "Content-Type":"multipart/form-data; boundary=----WebKitFormBoundaryHKOJEwZFCnY9xIEy" + }, + url: 'https://api.sloths.com', + body: { + show: "615727", + body: "hello world!", + type: 0, + icon: {filename: "testorig.jpg"}, + serviceId: "AAA", + accessToken: "BBB" + } + } +}) + cases.forEach(function(c){ const out = parse(c.input)