From d493781044108901b860c7ce374745bb244543fe Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Wed, 5 Aug 2020 15:02:13 -0700 Subject: [PATCH 01/16] fix: moving form-data usage over to using the native FormData object --- .jshintrc | 1 + package-lock.json | 89 ++++----------------------- package.json | 3 +- src/helpers/form-data.js | 128 +++++++++++++++++++++++++++++++++++++++ src/index.js | 28 +++++---- 5 files changed, 159 insertions(+), 90 deletions(-) create mode 100644 src/helpers/form-data.js diff --git a/.jshintrc b/.jshintrc index 086f6bacb..5619eb494 100644 --- a/.jshintrc +++ b/.jshintrc @@ -1,4 +1,5 @@ { "asi": true, + "browser": true, "node": true } diff --git a/package-lock.json b/package-lock.json index f56dc1d2a..30d310734 100644 --- a/package-lock.json +++ b/package-lock.json @@ -116,7 +116,8 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true }, "aws-sign2": { "version": "0.7.0", @@ -482,7 +483,8 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true }, "diff": { "version": "3.5.0", @@ -505,11 +507,6 @@ "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==", "dev": true }, - "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" - }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -1017,20 +1014,6 @@ "es5-ext": "~0.10.14" } }, - "event-stream": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", - "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", - "requires": { - "duplexer": "~0.1.1", - "from": "~0", - "map-stream": "~0.1.0", - "pause-stream": "0.0.11", - "split": "0.3", - "stream-combiner": "~0.0.4", - "through": "~2.3.1" - } - }, "exit-hook": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", @@ -1144,30 +1127,10 @@ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", "dev": true }, - "form-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", - "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "dependencies": { - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - } - } - }, - "from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=" + "formdata-polyfill": { + "version": "3.0.20", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-3.0.20.tgz", + "integrity": "sha512-TAaxIEwTBdoH1TWndtUH1T0/GisUHwmOKcV5hjkR/iTatHBJSOHb563FP86Lra5nXo3iNdhK7HPwMl5Ihg71pg==" }, "fs-readfile-promise": { "version": "2.0.1", @@ -1813,20 +1776,17 @@ "yallist": "^2.1.2" } }, - "map-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", - "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=" - }, "mime-db": { "version": "1.40.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true }, "mime-types": { "version": "2.1.24", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, "requires": { "mime-db": "1.40.0" } @@ -2251,14 +2211,6 @@ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", "dev": true }, - "pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", - "requires": { - "through": "~2.3" - } - }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -2703,14 +2655,6 @@ "amdefine": ">=0.0.4" } }, - "split": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", - "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", - "requires": { - "through": "2" - } - }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -2763,14 +2707,6 @@ "pkg-conf": "^2.0.0" } }, - "stream-combiner": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", - "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", - "requires": { - "duplexer": "~0.1.1" - } - }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -3146,7 +3082,8 @@ "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true }, "tough-cookie": { "version": "2.4.3", diff --git a/package.json b/package.json index 638ccbb55..43b3b0422 100644 --- a/package.json +++ b/package.json @@ -81,8 +81,7 @@ "chalk": "^1.1.1", "commander": "^2.9.0", "debug": "^2.2.0", - "event-stream": "3.3.4", - "form-data": "3.0.0", + "formdata-polyfill": "^3.0.20", "fs-readfile-promise": "^2.0.1", "fs-writefile-promise": "^1.0.3", "har-validator": "^5.0.0", diff --git a/src/helpers/form-data.js b/src/helpers/form-data.js new file mode 100644 index 000000000..343e6dc53 --- /dev/null +++ b/src/helpers/form-data.js @@ -0,0 +1,128 @@ +/** + * @license https://raw.githubusercontent.com/node-fetch/node-fetch/master/LICENSE.md + * + * The MIT License (MIT) + * + * Copyright (c) 2016 - 2020 Node Fetch Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +const carriage = '\r\n' +const dashes = '-'.repeat(2) +const carriageLength = Buffer.byteLength(carriage) + +const NAME = Symbol.toStringTag + +const isBlob = object => { + return ( + typeof object === 'object' && + typeof object.arrayBuffer === 'function' && + typeof object.type === 'string' && + typeof object.stream === 'function' && + typeof object.constructor === 'function' && + /^(Blob|File)$/.test(object[NAME]) + ) +} + +/** + * @param {string} boundary + */ +const getFooter = boundary => `${dashes}${boundary}${dashes}${carriage.repeat(2)}` + +/** + * @param {string} boundary + * @param {string} name + * @param {*} field + * + * @return {string} + */ +function getHeader (boundary, name, field) { + let header = '' + + header += `${dashes}${boundary}${carriage}` + header += `Content-Disposition: form-data; name="${name}"` + + if (isBlob(field)) { + header += `; filename="${field.name}"${carriage}` + header += `Content-Type: ${field.type || 'application/octet-stream'}` + } + + return `${header}${carriage.repeat(2)}` +} + +/** + * @return {string} + */ +module.exports.getBoundary = () => { + // This generates a 50 character boundary similar to those used by Firefox. + // They are optimized for boyer-moore parsing. + var boundary = '--------------------------' + for (var i = 0; i < 24; i++) { + boundary += Math.floor(Math.random() * 10).toString(16) + } + + return boundary +} + +/** + * @param {FormData} form + * @param {string} boundary + */ +module.exports.formDataIterator = function * (form, boundary) { + for (const [name, value] of form) { + yield getHeader(boundary, name, value) + + if (isBlob(value)) { + yield * value.stream() + } else { + yield value + } + + yield carriage + } + + yield getFooter(boundary) +} + +/** + * @param {FormData} form + * @param {string} boundary + */ +module.exports.getFormDataLength = function (form, boundary) { + let length = 0 + + for (const [name, value] of form) { + length += Buffer.byteLength(getHeader(boundary, name, value)) + + if (isBlob(value)) { + length += value.size + } else { + length += Buffer.byteLength(String(value)) + } + + length += carriageLength + } + + length += Buffer.byteLength(getFooter(boundary)) + + return length +} + +module.exports.isBlob = isBlob diff --git a/src/index.js b/src/index.js index 815593611..961ae344d 100644 --- a/src/index.js +++ b/src/index.js @@ -1,14 +1,17 @@ 'use strict' +/* eslint-env browser */ + +require('formdata-polyfill') var debug = require('debug')('httpsnippet') -var es = require('event-stream') -var MultiPartForm = require('form-data') var qs = require('querystring') var reducer = require('./helpers/reducer') var targets = require('./targets') var url = require('url') var validate = require('har-validator/lib/async') +const { formDataIterator, isBlob } = require('./helpers/form-data.js') + // constructor var HTTPSnippet = function (data) { var entries @@ -102,24 +105,25 @@ HTTPSnippet.prototype.prepare = function (request) { request.postData.mimeType = 'multipart/form-data' if (request.postData.params) { - var form = new MultiPartForm() + var form = new FormData() // easter egg - form._boundary = '---011000010111000001101001' + const boundary = '---011000010111000001101001' request.postData.params.forEach(function (param) { - form.append(param.name, param.value || '', { - filename: param.fileName || null, - contentType: param.contentType || null - }) + if (isBlob(param.value)) { + form.append(param.name, param.value || '', param.fileName || null) + } else { + form.append(param.name, param.value || '') + } }) - form.pipe(es.map(function (data, cb) { + for (var data of formDataIterator(form, boundary)) { request.postData.text += data - })) + } - request.postData.boundary = form.getBoundary() - request.headersObj['content-type'] = 'multipart/form-data; boundary=' + form.getBoundary() + request.postData.boundary = boundary + request.headersObj['content-type'] = 'multipart/form-data; boundary=' + boundary } break From 80015808bf7d0f41dcd704e3daee4243a40b7bfa Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Wed, 5 Aug 2020 15:30:52 -0700 Subject: [PATCH 02/16] test: commenting out some tests while debugging --- src/index.js | 3 ++- src/targets/index.js | 32 ++++++++++++++++---------------- src/targets/shell/index.js | 4 ++-- test/targets.js | 14 +++++++++----- 4 files changed, 29 insertions(+), 24 deletions(-) diff --git a/src/index.js b/src/index.js index 961ae344d..5e1f4325a 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,7 @@ -'use strict' /* eslint-env browser */ +'use strict' + require('formdata-polyfill') var debug = require('debug')('httpsnippet') diff --git a/src/targets/index.js b/src/targets/index.js index 68f83a6b8..e81ed081e 100644 --- a/src/targets/index.js +++ b/src/targets/index.js @@ -1,21 +1,21 @@ 'use strict' module.exports = { - c: require('./c'), - clojure: require('./clojure'), - csharp: require('./csharp'), - go: require('./go'), - http: require('./http'), - java: require('./java'), - javascript: require('./javascript'), - node: require('./node'), - objc: require('./objc'), - ocaml: require('./ocaml'), - php: require('./php'), - powershell: require('./powershell'), - python: require('./python'), - r: require('./r'), - ruby: require('./ruby'), +// c: require('./c'), +// clojure: require('./clojure'), +// csharp: require('./csharp'), +// go: require('./go'), +// http: require('./http'), +// java: require('./java'), +// javascript: require('./javascript'), +// node: require('./node'), +// objc: require('./objc'), +// ocaml: require('./ocaml'), +// php: require('./php'), +// powershell: require('./powershell'), +// python: require('./python'), +// r: require('./r'), +// ruby: require('./ruby'), shell: require('./shell'), - swift: require('./swift') +// swift: require('./swift') } diff --git a/src/targets/shell/index.js b/src/targets/shell/index.js index 0f5fc05f0..be2648e2f 100644 --- a/src/targets/shell/index.js +++ b/src/targets/shell/index.js @@ -9,6 +9,6 @@ module.exports = { }, curl: require('./curl'), - httpie: require('./httpie'), - wget: require('./wget') + // httpie: require('./httpie'), + // wget: require('./wget') } diff --git a/test/targets.js b/test/targets.js index 675293540..591f18058 100644 --- a/test/targets.js +++ b/test/targets.js @@ -47,7 +47,11 @@ const skipMe = { 'clj_http': ['jsonObj-null-value', 'jsonObj-multiline'] }, '*': { - '*': ['multipart-data', 'multipart-file', 'multipart-form-data'] + '*': [ + 'multipart-data', + 'multipart-file', + // 'multipart-form-data' + ] } } @@ -84,15 +88,15 @@ var itShouldGenerateOutput = function (request, path, target, client) { }) } -describe('Available Targets', function () { +/* describe('Available Targets', function () { HTTPSnippet.availableTargets().forEach(function (target) { it('available-targets.json should include ' + target.title, function () { fixtures['available-targets'].should.containEql(target) }) }) -}) +}) */ -describe('Custom targets', function () { +/* describe('Custom targets', function () { describe('Adding a custom target', function () { it('should throw if the target does has no info object', function () { (function () { @@ -182,7 +186,7 @@ describe('Custom targets', function () { }) }) }) -}) +}) */ // test all the things! describe('Targets', function () { From ce5f277068951998cf48044a1a70f0c547666cea Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Wed, 5 Aug 2020 16:08:55 -0700 Subject: [PATCH 03/16] fix: coding against native FormData and form-data --- package-lock.json | 90 ++++++++++++++++++++++++++++++++------ package.json | 3 +- src/index.js | 44 +++++++++++++++---- src/targets/index.js | 32 +++++++------- src/targets/shell/index.js | 4 +- test/targets.js | 10 ++--- 6 files changed, 138 insertions(+), 45 deletions(-) diff --git a/package-lock.json b/package-lock.json index 30d310734..46458c7ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -116,8 +116,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "aws-sign2": { "version": "0.7.0", @@ -483,8 +482,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "diff": { "version": "3.5.0", @@ -507,6 +505,11 @@ "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==", "dev": true }, + "duplexer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -1014,6 +1017,20 @@ "es5-ext": "~0.10.14" } }, + "event-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz", + "integrity": "sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==", + "requires": { + "duplexer": "^0.1.1", + "from": "^0.1.7", + "map-stream": "0.0.7", + "pause-stream": "^0.0.11", + "split": "^1.0.1", + "stream-combiner": "^0.2.2", + "through": "^2.3.8" + } + }, "exit-hook": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", @@ -1127,10 +1144,30 @@ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", "dev": true }, - "formdata-polyfill": { - "version": "3.0.20", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-3.0.20.tgz", - "integrity": "sha512-TAaxIEwTBdoH1TWndtUH1T0/GisUHwmOKcV5hjkR/iTatHBJSOHb563FP86Lra5nXo3iNdhK7HPwMl5Ihg71pg==" + "form-data": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", + "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "dependencies": { + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + } + } + }, + "from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=" }, "fs-readfile-promise": { "version": "2.0.1", @@ -1776,17 +1813,20 @@ "yallist": "^2.1.2" } }, + "map-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", + "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=" + }, "mime-db": { "version": "1.40.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", - "dev": true + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" }, "mime-types": { "version": "2.1.24", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", - "dev": true, "requires": { "mime-db": "1.40.0" } @@ -2211,6 +2251,14 @@ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", "dev": true }, + "pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "requires": { + "through": "~2.3" + } + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -2655,6 +2703,14 @@ "amdefine": ">=0.0.4" } }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "requires": { + "through": "2" + } + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -2707,6 +2763,15 @@ "pkg-conf": "^2.0.0" } }, + "stream-combiner": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", + "integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=", + "requires": { + "duplexer": "~0.1.1", + "through": "~2.3.4" + } + }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -3082,8 +3147,7 @@ "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "tough-cookie": { "version": "2.4.3", diff --git a/package.json b/package.json index 43b3b0422..c7ea06bb6 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,8 @@ "chalk": "^1.1.1", "commander": "^2.9.0", "debug": "^2.2.0", - "formdata-polyfill": "^3.0.20", + "event-stream": "^4.0.1", + "form-data": "^3.0.0", "fs-readfile-promise": "^2.0.1", "fs-writefile-promise": "^1.0.3", "har-validator": "^5.0.0", diff --git a/src/index.js b/src/index.js index 5e1f4325a..03da84af1 100644 --- a/src/index.js +++ b/src/index.js @@ -2,9 +2,9 @@ 'use strict' -require('formdata-polyfill') - var debug = require('debug')('httpsnippet') +var es = require('event-stream') +var MultiPartForm = require('form-data') var qs = require('querystring') var reducer = require('./helpers/reducer') var targets = require('./targets') @@ -106,21 +106,49 @@ HTTPSnippet.prototype.prepare = function (request) { request.postData.mimeType = 'multipart/form-data' if (request.postData.params) { - var form = new FormData() + var form = new MultiPartForm() + + // The `form-data` module returns one of two things: a native FormData object, or its own polyfill. Since this + // polyfill support the full API of the native FormData object, when this library is running in a browser + // environment it'll fail on two things: + // + // - The API for `form.append()` has three arguments and the third should only be present when the second is a + // Blob or USVString. + // - `FormData.pipe()` isn't a function. + // + // Since the native FormData object is iterable, we easily detect what version of `form-data` we're working + // with here to allow `multipart/form-data` requests to be compiled under both browser and Node environments. + // This hack sucks yeah, but it's the only way we can use this library in the browser as if we code this against + // just the native FormData object, we can't polyfill it back into Node because Blob and File objects, which + // something like `formdata-polyfill` requires, don't exist there. + const isNativeFormData = (typeof form[Symbol.iterator] === 'function'); // easter egg const boundary = '---011000010111000001101001' request.postData.params.forEach(function (param) { - if (isBlob(param.value)) { - form.append(param.name, param.value || '', param.fileName || null) + if (isNativeFormData) { + if (isBlob(param.value)) { + form.append(param.name, param.value || '', param.fileName || null) + } else { + form.append(param.name, param.value || '') + } } else { - form.append(param.name, param.value || '') + form.append(param.name, param.value || '', { + filename: param.fileName || null, + contentType: param.contentType || null + }) } }) - for (var data of formDataIterator(form, boundary)) { - request.postData.text += data + if (isNativeFormData) { + for (var data of formDataIterator(form, boundary)) { + request.postData.text += data + } + } else { + form.pipe(es.map(function (data, cb) { + request.postData.text += data + })) } request.postData.boundary = boundary diff --git a/src/targets/index.js b/src/targets/index.js index e81ed081e..68f83a6b8 100644 --- a/src/targets/index.js +++ b/src/targets/index.js @@ -1,21 +1,21 @@ 'use strict' module.exports = { -// c: require('./c'), -// clojure: require('./clojure'), -// csharp: require('./csharp'), -// go: require('./go'), -// http: require('./http'), -// java: require('./java'), -// javascript: require('./javascript'), -// node: require('./node'), -// objc: require('./objc'), -// ocaml: require('./ocaml'), -// php: require('./php'), -// powershell: require('./powershell'), -// python: require('./python'), -// r: require('./r'), -// ruby: require('./ruby'), + c: require('./c'), + clojure: require('./clojure'), + csharp: require('./csharp'), + go: require('./go'), + http: require('./http'), + java: require('./java'), + javascript: require('./javascript'), + node: require('./node'), + objc: require('./objc'), + ocaml: require('./ocaml'), + php: require('./php'), + powershell: require('./powershell'), + python: require('./python'), + r: require('./r'), + ruby: require('./ruby'), shell: require('./shell'), -// swift: require('./swift') + swift: require('./swift') } diff --git a/src/targets/shell/index.js b/src/targets/shell/index.js index be2648e2f..0f5fc05f0 100644 --- a/src/targets/shell/index.js +++ b/src/targets/shell/index.js @@ -9,6 +9,6 @@ module.exports = { }, curl: require('./curl'), - // httpie: require('./httpie'), - // wget: require('./wget') + httpie: require('./httpie'), + wget: require('./wget') } diff --git a/test/targets.js b/test/targets.js index 591f18058..ed9502dbb 100644 --- a/test/targets.js +++ b/test/targets.js @@ -50,7 +50,7 @@ const skipMe = { '*': [ 'multipart-data', 'multipart-file', - // 'multipart-form-data' + 'multipart-form-data' ] } } @@ -88,15 +88,15 @@ var itShouldGenerateOutput = function (request, path, target, client) { }) } -/* describe('Available Targets', function () { +describe('Available Targets', function () { HTTPSnippet.availableTargets().forEach(function (target) { it('available-targets.json should include ' + target.title, function () { fixtures['available-targets'].should.containEql(target) }) }) -}) */ +}) -/* describe('Custom targets', function () { +describe('Custom targets', function () { describe('Adding a custom target', function () { it('should throw if the target does has no info object', function () { (function () { @@ -186,7 +186,7 @@ var itShouldGenerateOutput = function (request, path, target, client) { }) }) }) -}) */ +}) // test all the things! describe('Targets', function () { From 346db5866b629c8dd481fcda4f8d034b549a4b59 Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Wed, 5 Aug 2020 16:15:43 -0700 Subject: [PATCH 04/16] chore: rolling back dep changes --- package-lock.json | 41 ++++++++++++++++++++--------------------- package.json | 4 ++-- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index 46458c7ca..f56dc1d2a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1018,17 +1018,17 @@ } }, "event-stream": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz", - "integrity": "sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "requires": { - "duplexer": "^0.1.1", - "from": "^0.1.7", - "map-stream": "0.0.7", - "pause-stream": "^0.0.11", - "split": "^1.0.1", - "stream-combiner": "^0.2.2", - "through": "^2.3.8" + "duplexer": "~0.1.1", + "from": "~0", + "map-stream": "~0.1.0", + "pause-stream": "0.0.11", + "split": "0.3", + "stream-combiner": "~0.0.4", + "through": "~2.3.1" } }, "exit-hook": { @@ -1814,9 +1814,9 @@ } }, "map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=" + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=" }, "mime-db": { "version": "1.40.0", @@ -2704,9 +2704,9 @@ } }, "split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", "requires": { "through": "2" } @@ -2764,12 +2764,11 @@ } }, "stream-combiner": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", - "integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=", + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", "requires": { - "duplexer": "~0.1.1", - "through": "~2.3.4" + "duplexer": "~0.1.1" } }, "string-width": { diff --git a/package.json b/package.json index c7ea06bb6..638ccbb55 100644 --- a/package.json +++ b/package.json @@ -81,8 +81,8 @@ "chalk": "^1.1.1", "commander": "^2.9.0", "debug": "^2.2.0", - "event-stream": "^4.0.1", - "form-data": "^3.0.0", + "event-stream": "3.3.4", + "form-data": "3.0.0", "fs-readfile-promise": "^2.0.1", "fs-writefile-promise": "^1.0.3", "har-validator": "^5.0.0", From 86c52ba99e4ad36ecbd441d22f4ac525f7c9b39f Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Wed, 5 Aug 2020 16:17:12 -0700 Subject: [PATCH 05/16] fix: setting the form-data boundary when under node --- src/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/index.js b/src/index.js index 03da84af1..c24ee892f 100644 --- a/src/index.js +++ b/src/index.js @@ -125,6 +125,9 @@ HTTPSnippet.prototype.prepare = function (request) { // easter egg const boundary = '---011000010111000001101001' + if (!isNativeFormData) { + form._boundary = boundary; + } request.postData.params.forEach(function (param) { if (isNativeFormData) { From b3268ef71c4429f2d6c98874b9516b26bc0ae8f0 Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Wed, 5 Aug 2020 16:19:04 -0700 Subject: [PATCH 06/16] docs: language fixes --- src/index.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index c24ee892f..787787641 100644 --- a/src/index.js +++ b/src/index.js @@ -118,9 +118,10 @@ HTTPSnippet.prototype.prepare = function (request) { // // Since the native FormData object is iterable, we easily detect what version of `form-data` we're working // with here to allow `multipart/form-data` requests to be compiled under both browser and Node environments. - // This hack sucks yeah, but it's the only way we can use this library in the browser as if we code this against - // just the native FormData object, we can't polyfill it back into Node because Blob and File objects, which - // something like `formdata-polyfill` requires, don't exist there. + // + // This hack is pretty awful but it's the only way we can use this library in the browser as if we code this + // against just the native FormData object, we can't polyfill that back into Node because Blob and File objects, + // which something like `formdata-polyfill` requires, don't exist there. const isNativeFormData = (typeof form[Symbol.iterator] === 'function'); // easter egg From 02356b62fcb0eefa7bf0928386bb513d8f18a5dd Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Thu, 6 Aug 2020 11:21:50 -0700 Subject: [PATCH 07/16] test: fixing broken multipart tests --- src/index.js | 4 ++-- .../output/http/1.1/application-form-encoded | 10 +++++----- .../fixtures/output/http/1.1/application-json | 10 +++++----- test/fixtures/output/http/1.1/cookies | 8 ++++---- test/fixtures/output/http/1.1/custom-method | 6 +++--- test/fixtures/output/http/1.1/full | 14 +++++++------- test/fixtures/output/http/1.1/headers | 10 +++++----- test/fixtures/output/http/1.1/https | 6 +++--- .../output/http/1.1/jsonObj-multiline | 10 +++++----- .../output/http/1.1/jsonObj-null-value | 10 +++++----- test/fixtures/output/http/1.1/multipart-data | 19 ++++++++++--------- test/fixtures/output/http/1.1/multipart-file | 19 ++++++++++--------- .../output/http/1.1/multipart-form-data | 17 +++++++++-------- test/fixtures/output/http/1.1/query | 6 +++--- test/fixtures/output/http/1.1/short | 6 +++--- test/fixtures/output/http/1.1/text-plain | 10 +++++----- .../output/node/request/multipart-data.js | 5 +---- .../output/node/request/multipart-file.js | 5 +---- .../output/php/http1/multipart-data.php | 12 ++++++------ .../output/php/http1/multipart-file.php | 12 ++++++------ .../output/php/http1/multipart-form-data.php | 10 +++++----- .../powershell/restmethod/multipart-data.ps1 | 12 +++++++----- .../powershell/restmethod/multipart-file.ps1 | 10 ++++++---- .../restmethod/multipart-form-data.ps1 | 10 ++++++---- .../powershell/webrequest/multipart-data.ps1 | 4 +++- .../powershell/webrequest/multipart-file.ps1 | 2 ++ .../webrequest/multipart-form-data.ps1 | 4 +++- .../output/shell/httpie/multipart-data.sh | 12 ++++++------ .../output/shell/httpie/multipart-file.sh | 12 ++++++------ .../shell/httpie/multipart-form-data.sh | 10 +++++----- test/targets.js | 13 ++++++------- 31 files changed, 153 insertions(+), 145 deletions(-) diff --git a/src/index.js b/src/index.js index 787787641..635a5b4a7 100644 --- a/src/index.js +++ b/src/index.js @@ -122,12 +122,12 @@ HTTPSnippet.prototype.prepare = function (request) { // This hack is pretty awful but it's the only way we can use this library in the browser as if we code this // against just the native FormData object, we can't polyfill that back into Node because Blob and File objects, // which something like `formdata-polyfill` requires, don't exist there. - const isNativeFormData = (typeof form[Symbol.iterator] === 'function'); + const isNativeFormData = (typeof form[Symbol.iterator] === 'function') // easter egg const boundary = '---011000010111000001101001' if (!isNativeFormData) { - form._boundary = boundary; + form._boundary = boundary } request.postData.params.forEach(function (param) { diff --git a/test/fixtures/output/http/1.1/application-form-encoded b/test/fixtures/output/http/1.1/application-form-encoded index ce1fea04b..723d94a90 100644 --- a/test/fixtures/output/http/1.1/application-form-encoded +++ b/test/fixtures/output/http/1.1/application-form-encoded @@ -1,6 +1,6 @@ -POST /har HTTP/1.1 -Content-Type: application/x-www-form-urlencoded -Host: mockbin.com -Content-Length: 19 - +POST /har HTTP/1.1 +Content-Type: application/x-www-form-urlencoded +Host: mockbin.com +Content-Length: 19 + foo=bar&hello=world diff --git a/test/fixtures/output/http/1.1/application-json b/test/fixtures/output/http/1.1/application-json index 6b2808eb0..ee65b5469 100644 --- a/test/fixtures/output/http/1.1/application-json +++ b/test/fixtures/output/http/1.1/application-json @@ -1,6 +1,6 @@ -POST /har HTTP/1.1 -Content-Type: application/json -Host: mockbin.com -Content-Length: 118 - +POST /har HTTP/1.1 +Content-Type: application/json +Host: mockbin.com +Content-Length: 118 + {"number":1,"string":"f\"oo","arr":[1,2,3],"nested":{"a":"b"},"arr_mix":[1,"a",{"arr_mix_nested":{}}],"boolean":false} diff --git a/test/fixtures/output/http/1.1/cookies b/test/fixtures/output/http/1.1/cookies index 6a2413d9a..15945bcc8 100644 --- a/test/fixtures/output/http/1.1/cookies +++ b/test/fixtures/output/http/1.1/cookies @@ -1,5 +1,5 @@ -POST /har HTTP/1.1 -Cookie: foo=bar; bar=baz -Host: mockbin.com - +POST /har HTTP/1.1 +Cookie: foo=bar; bar=baz +Host: mockbin.com + diff --git a/test/fixtures/output/http/1.1/custom-method b/test/fixtures/output/http/1.1/custom-method index 5a818ed57..76f546524 100644 --- a/test/fixtures/output/http/1.1/custom-method +++ b/test/fixtures/output/http/1.1/custom-method @@ -1,4 +1,4 @@ -PROPFIND /har HTTP/1.1 -Host: mockbin.com - +PROPFIND /har HTTP/1.1 +Host: mockbin.com + diff --git a/test/fixtures/output/http/1.1/full b/test/fixtures/output/http/1.1/full index 1a2f499d9..d4d41ecff 100644 --- a/test/fixtures/output/http/1.1/full +++ b/test/fixtures/output/http/1.1/full @@ -1,8 +1,8 @@ -POST /har?foo=bar&foo=baz&baz=abc&key=value HTTP/1.1 -Cookie: foo=bar; bar=baz -Accept: application/json -Content-Type: application/x-www-form-urlencoded -Host: mockbin.com -Content-Length: 7 - +POST /har?foo=bar&foo=baz&baz=abc&key=value HTTP/1.1 +Cookie: foo=bar; bar=baz +Accept: application/json +Content-Type: application/x-www-form-urlencoded +Host: mockbin.com +Content-Length: 7 + foo=bar diff --git a/test/fixtures/output/http/1.1/headers b/test/fixtures/output/http/1.1/headers index 0a23b57d9..7bde2bcc7 100644 --- a/test/fixtures/output/http/1.1/headers +++ b/test/fixtures/output/http/1.1/headers @@ -1,6 +1,6 @@ -GET /har HTTP/1.1 -Accept: application/json -X-Foo: Bar -Host: mockbin.com - +GET /har HTTP/1.1 +Accept: application/json +X-Foo: Bar +Host: mockbin.com + diff --git a/test/fixtures/output/http/1.1/https b/test/fixtures/output/http/1.1/https index 854df52c9..122711d7a 100644 --- a/test/fixtures/output/http/1.1/https +++ b/test/fixtures/output/http/1.1/https @@ -1,4 +1,4 @@ -GET /har HTTP/1.1 -Host: mockbin.com - +GET /har HTTP/1.1 +Host: mockbin.com + diff --git a/test/fixtures/output/http/1.1/jsonObj-multiline b/test/fixtures/output/http/1.1/jsonObj-multiline index 4e48138d1..ebc26ade1 100644 --- a/test/fixtures/output/http/1.1/jsonObj-multiline +++ b/test/fixtures/output/http/1.1/jsonObj-multiline @@ -1,8 +1,8 @@ -POST /har HTTP/1.1 -Content-Type: application/json -Host: mockbin.com -Content-Length: 18 - +POST /har HTTP/1.1 +Content-Type: application/json +Host: mockbin.com +Content-Length: 18 + { "foo": "bar" } diff --git a/test/fixtures/output/http/1.1/jsonObj-null-value b/test/fixtures/output/http/1.1/jsonObj-null-value index e879e2298..240a57bce 100644 --- a/test/fixtures/output/http/1.1/jsonObj-null-value +++ b/test/fixtures/output/http/1.1/jsonObj-null-value @@ -1,6 +1,6 @@ -POST /har HTTP/1.1 -Content-Type: application/json -Host: mockbin.com -Content-Length: 12 - +POST /har HTTP/1.1 +Content-Type: application/json +Host: mockbin.com +Content-Length: 12 + {"foo":null} diff --git a/test/fixtures/output/http/1.1/multipart-data b/test/fixtures/output/http/1.1/multipart-data index 4a2b44469..cbe1c5f5a 100644 --- a/test/fixtures/output/http/1.1/multipart-data +++ b/test/fixtures/output/http/1.1/multipart-data @@ -1,10 +1,11 @@ -POST /har HTTP/1.1 -Content-Type: multipart/form-data; boundary=---011000010111000001101001 -Host: mockbin.com -Content-Length: 136 - ------011000010111000001101001 -Content-Disposition: form-data; name="foo"; filename="hello.txt" -Content-Type: text/plain - +POST /har HTTP/1.1 +Content-Type: multipart/form-data; boundary=---011000010111000001101001 +Host: mockbin.com +Content-Length: 171 + +-----011000010111000001101001 +Content-Disposition: form-data; name="foo"; filename="hello.txt" +Content-Type: text/plain + Hello World +-----011000010111000001101001-- diff --git a/test/fixtures/output/http/1.1/multipart-file b/test/fixtures/output/http/1.1/multipart-file index 16a76e1ae..be0776f19 100644 --- a/test/fixtures/output/http/1.1/multipart-file +++ b/test/fixtures/output/http/1.1/multipart-file @@ -1,10 +1,11 @@ -POST /har HTTP/1.1 -Content-Type: multipart/form-data; boundary=---011000010111000001101001 -Host: mockbin.com -Content-Length: 125 - ------011000010111000001101001 -Content-Disposition: form-data; name="foo"; filename="hello.txt" -Content-Type: text/plain - +POST /har HTTP/1.1 +Content-Type: multipart/form-data; boundary=---011000010111000001101001 +Host: mockbin.com +Content-Length: 160 +-----011000010111000001101001 +Content-Disposition: form-data; name="foo"; filename="hello.txt" +Content-Type: text/plain + + +-----011000010111000001101001-- diff --git a/test/fixtures/output/http/1.1/multipart-form-data b/test/fixtures/output/http/1.1/multipart-form-data index 752acd4c9..5fd60b6f4 100644 --- a/test/fixtures/output/http/1.1/multipart-form-data +++ b/test/fixtures/output/http/1.1/multipart-form-data @@ -1,9 +1,10 @@ -POST /har HTTP/1.1 -Content-Type: multipart/form-data; boundary=---011000010111000001101001 -Host: mockbin.com -Content-Length: 80 - ------011000010111000001101001 -Content-Disposition: form-data; name="foo" - +POST /har HTTP/1.1 +Content-Type: multipart/form-data; boundary=---011000010111000001101001 +Host: mockbin.com +Content-Length: 115 + +-----011000010111000001101001 +Content-Disposition: form-data; name="foo" + bar +-----011000010111000001101001-- diff --git a/test/fixtures/output/http/1.1/query b/test/fixtures/output/http/1.1/query index 8217c2361..5d2fd5d42 100644 --- a/test/fixtures/output/http/1.1/query +++ b/test/fixtures/output/http/1.1/query @@ -1,4 +1,4 @@ -GET /har?foo=bar&foo=baz&baz=abc&key=value HTTP/1.1 -Host: mockbin.com - +GET /har?foo=bar&foo=baz&baz=abc&key=value HTTP/1.1 +Host: mockbin.com + diff --git a/test/fixtures/output/http/1.1/short b/test/fixtures/output/http/1.1/short index 854df52c9..122711d7a 100644 --- a/test/fixtures/output/http/1.1/short +++ b/test/fixtures/output/http/1.1/short @@ -1,4 +1,4 @@ -GET /har HTTP/1.1 -Host: mockbin.com - +GET /har HTTP/1.1 +Host: mockbin.com + diff --git a/test/fixtures/output/http/1.1/text-plain b/test/fixtures/output/http/1.1/text-plain index e0db5c854..c341a43ac 100644 --- a/test/fixtures/output/http/1.1/text-plain +++ b/test/fixtures/output/http/1.1/text-plain @@ -1,6 +1,6 @@ -POST /har HTTP/1.1 -Content-Type: text/plain -Host: mockbin.com -Content-Length: 11 - +POST /har HTTP/1.1 +Content-Type: text/plain +Host: mockbin.com +Content-Length: 11 + Hello World diff --git a/test/fixtures/output/node/request/multipart-data.js b/test/fixtures/output/node/request/multipart-data.js index 2af993d89..16181383e 100644 --- a/test/fixtures/output/node/request/multipart-data.js +++ b/test/fixtures/output/node/request/multipart-data.js @@ -7,10 +7,7 @@ var options = { formData: { foo: { value: 'Hello World', - options: { - filename: 'hello.txt', - contentType: 'text/plain' - } + options: {filename: 'hello.txt', contentType: 'text/plain'} } } }; diff --git a/test/fixtures/output/node/request/multipart-file.js b/test/fixtures/output/node/request/multipart-file.js index 0eae5dea1..181affbb6 100644 --- a/test/fixtures/output/node/request/multipart-file.js +++ b/test/fixtures/output/node/request/multipart-file.js @@ -8,10 +8,7 @@ var options = { formData: { foo: { value: 'fs.createReadStream("test/fixtures/files/hello.txt")', - options: { - filename: 'test/fixtures/files/hello.txt', - contentType: 'text/plain' - } + options: {filename: 'test/fixtures/files/hello.txt', contentType: 'text/plain'} } } }; diff --git a/test/fixtures/output/php/http1/multipart-data.php b/test/fixtures/output/php/http1/multipart-data.php index d5e20ac4d..06a28658e 100644 --- a/test/fixtures/output/php/http1/multipart-data.php +++ b/test/fixtures/output/php/http1/multipart-data.php @@ -8,12 +8,12 @@ 'content-type' => 'multipart/form-data; boundary=---011000010111000001101001' )); -$request->setBody('-----011000010111000001101001 -Content-Disposition: form-data; name="foo"; filename="hello.txt" -Content-Type: text/plain - -Hello World ------011000010111000001101001-- +$request->setBody('-----011000010111000001101001 +Content-Disposition: form-data; name="foo"; filename="hello.txt" +Content-Type: text/plain + +Hello World +-----011000010111000001101001-- '); try { diff --git a/test/fixtures/output/php/http1/multipart-file.php b/test/fixtures/output/php/http1/multipart-file.php index 721be8237..b2b16581a 100644 --- a/test/fixtures/output/php/http1/multipart-file.php +++ b/test/fixtures/output/php/http1/multipart-file.php @@ -8,12 +8,12 @@ 'content-type' => 'multipart/form-data; boundary=---011000010111000001101001' )); -$request->setBody('-----011000010111000001101001 -Content-Disposition: form-data; name="foo"; filename="hello.txt" -Content-Type: text/plain - - ------011000010111000001101001-- +$request->setBody('-----011000010111000001101001 +Content-Disposition: form-data; name="foo"; filename="hello.txt" +Content-Type: text/plain + + +-----011000010111000001101001-- '); try { diff --git a/test/fixtures/output/php/http1/multipart-form-data.php b/test/fixtures/output/php/http1/multipart-form-data.php index c78c84f8e..55f536e9c 100644 --- a/test/fixtures/output/php/http1/multipart-form-data.php +++ b/test/fixtures/output/php/http1/multipart-form-data.php @@ -8,11 +8,11 @@ 'content-type' => 'multipart/form-data; boundary=---011000010111000001101001' )); -$request->setBody('-----011000010111000001101001 -Content-Disposition: form-data; name="foo" - -bar ------011000010111000001101001-- +$request->setBody('-----011000010111000001101001 +Content-Disposition: form-data; name="foo" + +bar +-----011000010111000001101001-- '); try { diff --git a/test/fixtures/output/powershell/restmethod/multipart-data.ps1 b/test/fixtures/output/powershell/restmethod/multipart-data.ps1 index 5c340a95f..9324af570 100644 --- a/test/fixtures/output/powershell/restmethod/multipart-data.ps1 +++ b/test/fixtures/output/powershell/restmethod/multipart-data.ps1 @@ -1,7 +1,9 @@ $headers=@{} $headers.Add("content-type", "multipart/form-data; boundary=---011000010111000001101001") -$response = Invoke-RestMethod -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'multipart/form-data; boundary=---011000010111000001101001' -Body '-----011000010111000001101001 -Content-Disposition: form-data; name="foo"; filename="hello.txt" -Content-Type: text/plain - -Hello World' +$response = Invoke-RestMethod -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'multipart/form-data; boundary=---011000010111000001101001' -Body '-----011000010111000001101001 +Content-Disposition: form-data; name="foo"; filename="hello.txt" +Content-Type: text/plain + +Hello World +-----011000010111000001101001-- +' diff --git a/test/fixtures/output/powershell/restmethod/multipart-file.ps1 b/test/fixtures/output/powershell/restmethod/multipart-file.ps1 index a1a02c79c..e1329cb24 100644 --- a/test/fixtures/output/powershell/restmethod/multipart-file.ps1 +++ b/test/fixtures/output/powershell/restmethod/multipart-file.ps1 @@ -1,7 +1,9 @@ $headers=@{} $headers.Add("content-type", "multipart/form-data; boundary=---011000010111000001101001") -$response = Invoke-RestMethod -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'multipart/form-data; boundary=---011000010111000001101001' -Body '-----011000010111000001101001 -Content-Disposition: form-data; name="foo"; filename="hello.txt" -Content-Type: text/plain - +$response = Invoke-RestMethod -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'multipart/form-data; boundary=---011000010111000001101001' -Body '-----011000010111000001101001 +Content-Disposition: form-data; name="foo"; filename="hello.txt" +Content-Type: text/plain + + +-----011000010111000001101001-- ' diff --git a/test/fixtures/output/powershell/restmethod/multipart-form-data.ps1 b/test/fixtures/output/powershell/restmethod/multipart-form-data.ps1 index dc110e420..f389a2757 100644 --- a/test/fixtures/output/powershell/restmethod/multipart-form-data.ps1 +++ b/test/fixtures/output/powershell/restmethod/multipart-form-data.ps1 @@ -1,6 +1,8 @@ $headers=@{} $headers.Add("content-type", "multipart/form-data; boundary=---011000010111000001101001") -$response = Invoke-RestMethod -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'multipart/form-data; boundary=---011000010111000001101001' -Body '-----011000010111000001101001 -Content-Disposition: form-data; name="foo" - -bar' +$response = Invoke-RestMethod -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'multipart/form-data; boundary=---011000010111000001101001' -Body '-----011000010111000001101001 +Content-Disposition: form-data; name="foo" + +bar +-----011000010111000001101001-- +' diff --git a/test/fixtures/output/powershell/webrequest/multipart-data.ps1 b/test/fixtures/output/powershell/webrequest/multipart-data.ps1 index 43f66f4b7..64a05c86b 100644 --- a/test/fixtures/output/powershell/webrequest/multipart-data.ps1 +++ b/test/fixtures/output/powershell/webrequest/multipart-data.ps1 @@ -4,4 +4,6 @@ $response = Invoke-WebRequest -Uri 'http://mockbin.com/har' -Method POST -Header Content-Disposition: form-data; name="foo"; filename="hello.txt" Content-Type: text/plain -Hello World' +Hello World +-----011000010111000001101001-- +' diff --git a/test/fixtures/output/powershell/webrequest/multipart-file.ps1 b/test/fixtures/output/powershell/webrequest/multipart-file.ps1 index 9ff731856..c1dc54b57 100644 --- a/test/fixtures/output/powershell/webrequest/multipart-file.ps1 +++ b/test/fixtures/output/powershell/webrequest/multipart-file.ps1 @@ -4,4 +4,6 @@ $response = Invoke-WebRequest -Uri 'http://mockbin.com/har' -Method POST -Header Content-Disposition: form-data; name="foo"; filename="hello.txt" Content-Type: text/plain + +-----011000010111000001101001-- ' diff --git a/test/fixtures/output/powershell/webrequest/multipart-form-data.ps1 b/test/fixtures/output/powershell/webrequest/multipart-form-data.ps1 index 386f30630..9fe0ed80b 100644 --- a/test/fixtures/output/powershell/webrequest/multipart-form-data.ps1 +++ b/test/fixtures/output/powershell/webrequest/multipart-form-data.ps1 @@ -3,4 +3,6 @@ $headers.Add("content-type", "multipart/form-data; boundary=---01100001011100000 $response = Invoke-WebRequest -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'multipart/form-data; boundary=---011000010111000001101001' -Body '-----011000010111000001101001 Content-Disposition: form-data; name="foo" -bar' +bar +-----011000010111000001101001-- +' diff --git a/test/fixtures/output/shell/httpie/multipart-data.sh b/test/fixtures/output/shell/httpie/multipart-data.sh index 5cb1606a1..64b17a1f4 100644 --- a/test/fixtures/output/shell/httpie/multipart-data.sh +++ b/test/fixtures/output/shell/httpie/multipart-data.sh @@ -1,9 +1,9 @@ -echo '-----011000010111000001101001 -Content-Disposition: form-data; name="foo"; filename="hello.txt" -Content-Type: text/plain - -Hello World ------011000010111000001101001-- +echo '-----011000010111000001101001 +Content-Disposition: form-data; name="foo"; filename="hello.txt" +Content-Type: text/plain + +Hello World +-----011000010111000001101001-- ' | \ http POST http://mockbin.com/har \ content-type:'multipart/form-data; boundary=---011000010111000001101001' diff --git a/test/fixtures/output/shell/httpie/multipart-file.sh b/test/fixtures/output/shell/httpie/multipart-file.sh index 550a40ee1..25b7ede3e 100644 --- a/test/fixtures/output/shell/httpie/multipart-file.sh +++ b/test/fixtures/output/shell/httpie/multipart-file.sh @@ -1,9 +1,9 @@ -echo '-----011000010111000001101001 -Content-Disposition: form-data; name="foo"; filename="hello.txt" -Content-Type: text/plain - - ------011000010111000001101001-- +echo '-----011000010111000001101001 +Content-Disposition: form-data; name="foo"; filename="hello.txt" +Content-Type: text/plain + + +-----011000010111000001101001-- ' | \ http POST http://mockbin.com/har \ content-type:'multipart/form-data; boundary=---011000010111000001101001' diff --git a/test/fixtures/output/shell/httpie/multipart-form-data.sh b/test/fixtures/output/shell/httpie/multipart-form-data.sh index a177c60e5..a6d170094 100644 --- a/test/fixtures/output/shell/httpie/multipart-form-data.sh +++ b/test/fixtures/output/shell/httpie/multipart-form-data.sh @@ -1,8 +1,8 @@ -echo '-----011000010111000001101001 -Content-Disposition: form-data; name="foo" - -bar ------011000010111000001101001-- +echo '-----011000010111000001101001 +Content-Disposition: form-data; name="foo" + +bar +-----011000010111000001101001-- ' | \ http POST http://mockbin.com/har \ content-type:'multipart/form-data; boundary=---011000010111000001101001' diff --git a/test/targets.js b/test/targets.js index ed9502dbb..d26667ec3 100644 --- a/test/targets.js +++ b/test/targets.js @@ -47,11 +47,7 @@ const skipMe = { 'clj_http': ['jsonObj-null-value', 'jsonObj-multiline'] }, '*': { - '*': [ - 'multipart-data', - 'multipart-file', - 'multipart-form-data' - ] + '*': [] } } @@ -81,10 +77,13 @@ var itShouldGenerateOutput = function (request, path, target, client) { this.skip() } var instance = new HTTPSnippet(fixtures.requests[request]) - var result = instance.convert(target, client) + '\n' + + // `form-data` sets the line break as `\r\n`, but we can't easily replicate that in our fixtures so let's convert + // it to a standard line break instead. + var result = instance.convert(target, client).replace(/\r\n/g, '\n').trim() result.should.be.a.String() - result.should.equal(output[fixture].toString()) + result.should.equal(output[fixture].toString().trim()) }) } From 731d6649f914602d62188d9c03503dcaa6ef6235 Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Thu, 6 Aug 2020 11:53:56 -0700 Subject: [PATCH 08/16] test: cloning some data to another var to prevent test corruption --- test/requests.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/test/requests.js b/test/requests.js index b7cda7c72..dbc38e7e9 100644 --- a/test/requests.js +++ b/test/requests.js @@ -45,11 +45,16 @@ fixtures.cli.forEach(function (cli) { err.should.be.null() } + // Clone the fixture we're testing against to another object because for multipart/form-data cases we're + // deleting the header, and if we don't clone the fixture to another object, that deleted header will cause + // other tests to fail because it's missing where other tests are expecting it. + const fixture = JSON.parse(JSON.stringify(fixtures.requests[request])) + // make an exception for multipart/form-data - if (fixtures.requests[request].headers) { - fixtures.requests[request].headers.forEach(function (header, index) { + if (fixture.headers) { + fixture.headers.forEach(function (header, index) { if (header.name === 'content-type' && header.value === 'multipart/form-data') { - delete fixtures.requests[request].headers[index] + delete fixture.headers[index] } }) } @@ -59,7 +64,7 @@ fixtures.cli.forEach(function (cli) { har.log.entries[0].should.have.property('request') // BUG: Mockbin returns http url even when request is for https url if (request !== 'https') { - har.log.entries[0].request.should.containDeep(fixtures.requests[request]) + har.log.entries[0].request.should.containDeep(fixture) } done() }) From 89177c34634c4481aab5ef1c0da1c6bbceb78a1f Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Thu, 6 Aug 2020 12:04:05 -0700 Subject: [PATCH 09/16] fix: out of date regex that was causing readstreams to be stringified --- src/targets/node/request.js | 2 +- test/fixtures/output/node/request/multipart-file.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/targets/node/request.js b/src/targets/node/request.js index 7711d63db..e1f1c28fc 100644 --- a/src/targets/node/request.js +++ b/src/targets/node/request.js @@ -115,7 +115,7 @@ module.exports = function (source, options) { .push('});') .blank() - return code.join().replace('"JAR"', 'jar').replace(/"fs\.createReadStream\(\\"(.+)\\"\)"/, 'fs.createReadStream("$1")') + return code.join().replace('"JAR"', 'jar').replace(/'fs\.createReadStream\(\"(.+)\"\)'/g, 'fs.createReadStream("$1")') } module.exports.info = { diff --git a/test/fixtures/output/node/request/multipart-file.js b/test/fixtures/output/node/request/multipart-file.js index 181affbb6..407757a0f 100644 --- a/test/fixtures/output/node/request/multipart-file.js +++ b/test/fixtures/output/node/request/multipart-file.js @@ -7,7 +7,7 @@ var options = { headers: {'content-type': 'multipart/form-data; boundary=---011000010111000001101001'}, formData: { foo: { - value: 'fs.createReadStream("test/fixtures/files/hello.txt")', + value: fs.createReadStream("test/fixtures/files/hello.txt"), options: {filename: 'test/fixtures/files/hello.txt', contentType: 'text/plain'} } } From ea50f9909bf6a7d4325318578128abffdd8e27fb Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Thu, 6 Aug 2020 13:35:20 -0700 Subject: [PATCH 10/16] fix: updating the curl target to prioritize param.fileName --- src/targets/shell/curl.js | 7 ++++--- test/fixtures/output/shell/curl/multipart-data.sh | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/targets/shell/curl.js b/src/targets/shell/curl.js index 3b6397f4a..b6a82d386 100644 --- a/src/targets/shell/curl.js +++ b/src/targets/shell/curl.js @@ -44,10 +44,11 @@ module.exports = function (source, options) { switch (source.postData.mimeType) { case 'multipart/form-data': source.postData.params.map(function (param) { - var post = util.format('%s=%s', param.name, param.value) - - if (param.fileName && !param.value) { + var post = '' + if (param.fileName) { post = util.format('%s=@%s', param.name, param.fileName) + } else { + post = util.format('%s=%s', param.name, param.value) } code.push('%s %s', opts.short ? '-F' : '--form', helpers.quote(post)) diff --git a/test/fixtures/output/shell/curl/multipart-data.sh b/test/fixtures/output/shell/curl/multipart-data.sh index 8dee5514c..40a0201c7 100644 --- a/test/fixtures/output/shell/curl/multipart-data.sh +++ b/test/fixtures/output/shell/curl/multipart-data.sh @@ -1,4 +1,4 @@ curl --request POST \ --url http://mockbin.com/har \ --header 'content-type: multipart/form-data; boundary=---011000010111000001101001' \ - --form 'foo=Hello World' + --form foo=@hello.txt From 36a1a5bd97728b716cca6012d505946e1023b03a Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Thu, 6 Aug 2020 13:42:40 -0700 Subject: [PATCH 11/16] fix: updating the node request target to prioritize param.fileName --- src/targets/node/request.js | 2 +- test/fixtures/output/node/request/multipart-data.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/targets/node/request.js b/src/targets/node/request.js index e1f1c28fc..c7f2d3eca 100644 --- a/src/targets/node/request.js +++ b/src/targets/node/request.js @@ -61,7 +61,7 @@ module.exports = function (source, options) { return } - if (param.fileName && !param.value) { + if (param.fileName) { includeFS = true attachment.value = 'fs.createReadStream("' + param.fileName + '")' diff --git a/test/fixtures/output/node/request/multipart-data.js b/test/fixtures/output/node/request/multipart-data.js index 16181383e..418f53c9d 100644 --- a/test/fixtures/output/node/request/multipart-data.js +++ b/test/fixtures/output/node/request/multipart-data.js @@ -1,3 +1,4 @@ +var fs = require("fs"); var request = require("request"); var options = { @@ -6,7 +7,7 @@ var options = { headers: {'content-type': 'multipart/form-data; boundary=---011000010111000001101001'}, formData: { foo: { - value: 'Hello World', + value: fs.createReadStream("hello.txt"), options: {filename: 'hello.txt', contentType: 'text/plain'} } } From f98662c03ccf3875550d55cda9c51c263af27a36 Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Thu, 6 Aug 2020 14:01:25 -0700 Subject: [PATCH 12/16] fix: updating the node request target to prefer single quotes --- src/targets/node/request.js | 8 ++++---- .../output/node/request/application-form-encoded.js | 2 +- test/fixtures/output/node/request/application-json.js | 2 +- test/fixtures/output/node/request/cookies.js | 6 +++--- test/fixtures/output/node/request/custom-method.js | 2 +- test/fixtures/output/node/request/full.js | 6 +++--- test/fixtures/output/node/request/headers.js | 2 +- test/fixtures/output/node/request/https.js | 2 +- test/fixtures/output/node/request/jsonObj-multiline.js | 2 +- test/fixtures/output/node/request/jsonObj-null-value.js | 2 +- test/fixtures/output/node/request/multipart-data.js | 6 +++--- test/fixtures/output/node/request/multipart-file.js | 6 +++--- test/fixtures/output/node/request/multipart-form-data.js | 2 +- test/fixtures/output/node/request/query.js | 2 +- test/fixtures/output/node/request/short.js | 2 +- test/fixtures/output/node/request/text-plain.js | 2 +- 16 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/targets/node/request.js b/src/targets/node/request.js index c7f2d3eca..68487d201 100644 --- a/src/targets/node/request.js +++ b/src/targets/node/request.js @@ -22,7 +22,7 @@ module.exports = function (source, options) { var includeFS = false var code = new CodeBuilder(opts.indent) - code.push('var request = require("request");') + code.push("var request = require('request');") .blank() var reqOpts = { @@ -95,13 +95,13 @@ module.exports = function (source, options) { var url = source.url source.cookies.forEach(function (cookie) { - code.push('jar.setCookie(request.cookie("%s=%s"), "%s");', encodeURIComponent(cookie.name), encodeURIComponent(cookie.value), url) + code.push("jar.setCookie(request.cookie('%s=%s'), '%s');", encodeURIComponent(cookie.name), encodeURIComponent(cookie.value), url) }) code.blank() } if (includeFS) { - code.unshift('var fs = require("fs");') + code.unshift("var fs = require('fs');") } code.push('var options = %s;', stringifyObject(reqOpts, { indent: ' ', inlineCharacterLimit: 80 })) @@ -115,7 +115,7 @@ module.exports = function (source, options) { .push('});') .blank() - return code.join().replace('"JAR"', 'jar').replace(/'fs\.createReadStream\(\"(.+)\"\)'/g, 'fs.createReadStream("$1")') + return code.join().replace('"JAR"', 'jar').replace(/'fs\.createReadStream\("(.+)"\)'/g, "fs.createReadStream('$1')") } module.exports.info = { diff --git a/test/fixtures/output/node/request/application-form-encoded.js b/test/fixtures/output/node/request/application-form-encoded.js index 54c6cb9d9..dca582e95 100644 --- a/test/fixtures/output/node/request/application-form-encoded.js +++ b/test/fixtures/output/node/request/application-form-encoded.js @@ -1,4 +1,4 @@ -var request = require("request"); +var request = require('request'); var options = { method: 'POST', diff --git a/test/fixtures/output/node/request/application-json.js b/test/fixtures/output/node/request/application-json.js index 47ccb206a..4b00d0a09 100644 --- a/test/fixtures/output/node/request/application-json.js +++ b/test/fixtures/output/node/request/application-json.js @@ -1,4 +1,4 @@ -var request = require("request"); +var request = require('request'); var options = { method: 'POST', diff --git a/test/fixtures/output/node/request/cookies.js b/test/fixtures/output/node/request/cookies.js index a739c0cef..9d3adb250 100644 --- a/test/fixtures/output/node/request/cookies.js +++ b/test/fixtures/output/node/request/cookies.js @@ -1,8 +1,8 @@ -var request = require("request"); +var request = require('request'); var jar = request.jar(); -jar.setCookie(request.cookie("foo=bar"), "http://mockbin.com/har"); -jar.setCookie(request.cookie("bar=baz"), "http://mockbin.com/har"); +jar.setCookie(request.cookie('foo=bar'), 'http://mockbin.com/har'); +jar.setCookie(request.cookie('bar=baz'), 'http://mockbin.com/har'); var options = {method: 'POST', url: 'http://mockbin.com/har', jar: 'JAR'}; diff --git a/test/fixtures/output/node/request/custom-method.js b/test/fixtures/output/node/request/custom-method.js index 947650559..3a2202282 100644 --- a/test/fixtures/output/node/request/custom-method.js +++ b/test/fixtures/output/node/request/custom-method.js @@ -1,4 +1,4 @@ -var request = require("request"); +var request = require('request'); var options = {method: 'PROPFIND', url: 'http://mockbin.com/har'}; diff --git a/test/fixtures/output/node/request/full.js b/test/fixtures/output/node/request/full.js index b24ae4bb6..3d9f30302 100644 --- a/test/fixtures/output/node/request/full.js +++ b/test/fixtures/output/node/request/full.js @@ -1,8 +1,8 @@ -var request = require("request"); +var request = require('request'); var jar = request.jar(); -jar.setCookie(request.cookie("foo=bar"), "http://mockbin.com/har"); -jar.setCookie(request.cookie("bar=baz"), "http://mockbin.com/har"); +jar.setCookie(request.cookie('foo=bar'), 'http://mockbin.com/har'); +jar.setCookie(request.cookie('bar=baz'), 'http://mockbin.com/har'); var options = { method: 'POST', diff --git a/test/fixtures/output/node/request/headers.js b/test/fixtures/output/node/request/headers.js index 1e28531ff..bb46ef51d 100644 --- a/test/fixtures/output/node/request/headers.js +++ b/test/fixtures/output/node/request/headers.js @@ -1,4 +1,4 @@ -var request = require("request"); +var request = require('request'); var options = { method: 'GET', diff --git a/test/fixtures/output/node/request/https.js b/test/fixtures/output/node/request/https.js index d655d6835..18998433d 100644 --- a/test/fixtures/output/node/request/https.js +++ b/test/fixtures/output/node/request/https.js @@ -1,4 +1,4 @@ -var request = require("request"); +var request = require('request'); var options = {method: 'GET', url: 'https://mockbin.com/har'}; diff --git a/test/fixtures/output/node/request/jsonObj-multiline.js b/test/fixtures/output/node/request/jsonObj-multiline.js index 3a0c3a8d0..91294f754 100644 --- a/test/fixtures/output/node/request/jsonObj-multiline.js +++ b/test/fixtures/output/node/request/jsonObj-multiline.js @@ -1,4 +1,4 @@ -var request = require("request"); +var request = require('request'); var options = { method: 'POST', diff --git a/test/fixtures/output/node/request/jsonObj-null-value.js b/test/fixtures/output/node/request/jsonObj-null-value.js index a06dd028a..71caff935 100644 --- a/test/fixtures/output/node/request/jsonObj-null-value.js +++ b/test/fixtures/output/node/request/jsonObj-null-value.js @@ -1,4 +1,4 @@ -var request = require("request"); +var request = require('request'); var options = { method: 'POST', diff --git a/test/fixtures/output/node/request/multipart-data.js b/test/fixtures/output/node/request/multipart-data.js index 418f53c9d..738cbc56a 100644 --- a/test/fixtures/output/node/request/multipart-data.js +++ b/test/fixtures/output/node/request/multipart-data.js @@ -1,5 +1,5 @@ -var fs = require("fs"); -var request = require("request"); +var fs = require('fs'); +var request = require('request'); var options = { method: 'POST', @@ -7,7 +7,7 @@ var options = { headers: {'content-type': 'multipart/form-data; boundary=---011000010111000001101001'}, formData: { foo: { - value: fs.createReadStream("hello.txt"), + value: fs.createReadStream('hello.txt'), options: {filename: 'hello.txt', contentType: 'text/plain'} } } diff --git a/test/fixtures/output/node/request/multipart-file.js b/test/fixtures/output/node/request/multipart-file.js index 407757a0f..553351042 100644 --- a/test/fixtures/output/node/request/multipart-file.js +++ b/test/fixtures/output/node/request/multipart-file.js @@ -1,5 +1,5 @@ -var fs = require("fs"); -var request = require("request"); +var fs = require('fs'); +var request = require('request'); var options = { method: 'POST', @@ -7,7 +7,7 @@ var options = { headers: {'content-type': 'multipart/form-data; boundary=---011000010111000001101001'}, formData: { foo: { - value: fs.createReadStream("test/fixtures/files/hello.txt"), + value: fs.createReadStream('test/fixtures/files/hello.txt'), options: {filename: 'test/fixtures/files/hello.txt', contentType: 'text/plain'} } } diff --git a/test/fixtures/output/node/request/multipart-form-data.js b/test/fixtures/output/node/request/multipart-form-data.js index 05ddf57dd..b0c8e28b0 100644 --- a/test/fixtures/output/node/request/multipart-form-data.js +++ b/test/fixtures/output/node/request/multipart-form-data.js @@ -1,4 +1,4 @@ -var request = require("request"); +var request = require('request'); var options = { method: 'POST', diff --git a/test/fixtures/output/node/request/query.js b/test/fixtures/output/node/request/query.js index dfcb2e763..72aa3c1a9 100644 --- a/test/fixtures/output/node/request/query.js +++ b/test/fixtures/output/node/request/query.js @@ -1,4 +1,4 @@ -var request = require("request"); +var request = require('request'); var options = { method: 'GET', diff --git a/test/fixtures/output/node/request/short.js b/test/fixtures/output/node/request/short.js index 823ad63e2..0028f607d 100644 --- a/test/fixtures/output/node/request/short.js +++ b/test/fixtures/output/node/request/short.js @@ -1,4 +1,4 @@ -var request = require("request"); +var request = require('request'); var options = {method: 'GET', url: 'http://mockbin.com/har'}; diff --git a/test/fixtures/output/node/request/text-plain.js b/test/fixtures/output/node/request/text-plain.js index bf646234e..00bb443b5 100644 --- a/test/fixtures/output/node/request/text-plain.js +++ b/test/fixtures/output/node/request/text-plain.js @@ -1,4 +1,4 @@ -var request = require("request"); +var request = require('request'); var options = { method: 'POST', From 146b8c3d04b1a0912e4e29e339edcfaba9ba3040 Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Fri, 7 Aug 2020 08:44:15 -0700 Subject: [PATCH 13/16] docs: adjusting some incorrect comments --- src/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index 635a5b4a7..7421381a2 100644 --- a/src/index.js +++ b/src/index.js @@ -108,9 +108,9 @@ HTTPSnippet.prototype.prepare = function (request) { if (request.postData.params) { var form = new MultiPartForm() - // The `form-data` module returns one of two things: a native FormData object, or its own polyfill. Since this - // polyfill support the full API of the native FormData object, when this library is running in a browser - // environment it'll fail on two things: + // The `form-data` module returns one of two things: a native FormData object, or its own polyfill. Since the + // polyfill does not support the full API of the native FormData object, when this library is running in a + // browser environment it'll fail on two things: // // - The API for `form.append()` has three arguments and the third should only be present when the second is a // Blob or USVString. From 52ef6117ba90803846172f69c1f62e31dbb1e578 Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Fri, 7 Aug 2020 10:22:58 -0700 Subject: [PATCH 14/16] style: removing some unused code --- src/helpers/form-data.js | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/src/helpers/form-data.js b/src/helpers/form-data.js index 343e6dc53..c43469fb5 100644 --- a/src/helpers/form-data.js +++ b/src/helpers/form-data.js @@ -26,7 +26,6 @@ const carriage = '\r\n' const dashes = '-'.repeat(2) -const carriageLength = Buffer.byteLength(carriage) const NAME = Symbol.toStringTag @@ -101,28 +100,4 @@ module.exports.formDataIterator = function * (form, boundary) { yield getFooter(boundary) } -/** - * @param {FormData} form - * @param {string} boundary - */ -module.exports.getFormDataLength = function (form, boundary) { - let length = 0 - - for (const [name, value] of form) { - length += Buffer.byteLength(getHeader(boundary, name, value)) - - if (isBlob(value)) { - length += value.size - } else { - length += Buffer.byteLength(String(value)) - } - - length += carriageLength - } - - length += Buffer.byteLength(getFooter(boundary)) - - return length -} - module.exports.isBlob = isBlob From 6dbb2b70575fec160c417a74d49ab3fc613947bd Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Mon, 17 Aug 2020 11:10:58 -0700 Subject: [PATCH 15/16] fix: using `null` instead of `NULL` --- src/targets/php/http2.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/targets/php/http2.js b/src/targets/php/http2.js index 9c3afc28e..9f48e45a8 100644 --- a/src/targets/php/http2.js +++ b/src/targets/php/http2.js @@ -60,8 +60,8 @@ module.exports = function (source, options) { code.push('$body = new http\\Message\\Body;') .push('$body->addForm(%s, %s);', - Object.keys(fields).length ? helpers.convert(fields, opts.indent) : 'NULL', - files.length ? helpers.convert(files, opts.indent) : 'NULL' + Object.keys(fields).length ? helpers.convert(fields, opts.indent) : 'null', + files.length ? helpers.convert(files, opts.indent) : 'null' ) // remove the contentType header From e00ea3a6f525d72d9c2250bc2e1328a85c04bc72 Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Thu, 20 Aug 2020 15:06:55 -0700 Subject: [PATCH 16/16] style: addressing some feedback from pr review --- src/helpers/form-data.js | 2 ++ src/index.js | 17 +++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/helpers/form-data.js b/src/helpers/form-data.js index c43469fb5..6a9e917aa 100644 --- a/src/helpers/form-data.js +++ b/src/helpers/form-data.js @@ -22,6 +22,8 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. + * + * Extracted from https://github.com/node-fetch/node-fetch/blob/64c5c296a0250b852010746c76144cb9e14698d9/src/utils/form-data.js */ const carriage = '\r\n' diff --git a/src/index.js b/src/index.js index bf85fc7d1..c943e7adb 100644 --- a/src/index.js +++ b/src/index.js @@ -5,6 +5,7 @@ var debug = require('debug')('httpsnippet') var es = require('event-stream') var MultiPartForm = require('form-data') +var FormDataPolyfill = require('form-data/lib/form_data') var qs = require('querystring') var reducer = require('./helpers/reducer') var targets = require('./targets') @@ -122,7 +123,7 @@ HTTPSnippet.prototype.prepare = function (request) { // This hack is pretty awful but it's the only way we can use this library in the browser as if we code this // against just the native FormData object, we can't polyfill that back into Node because Blob and File objects, // which something like `formdata-polyfill` requires, don't exist there. - const isNativeFormData = (typeof form[Symbol.iterator] === 'function') + const isNativeFormData = !(form instanceof FormDataPolyfill) // easter egg const boundary = '---011000010111000001101001' @@ -131,15 +132,19 @@ HTTPSnippet.prototype.prepare = function (request) { } request.postData.params.forEach(function (param) { + const name = param.name + const value = param.value || '' + const filename = param.fileName || null + if (isNativeFormData) { - if (isBlob(param.value)) { - form.append(param.name, param.value || '', param.fileName || null) + if (isBlob(value)) { + form.append(name, value, filename) } else { - form.append(param.name, param.value || '') + form.append(name, value) } } else { - form.append(param.name, param.value || '', { - filename: param.fileName || null, + form.append(name, value, { + filename: filename, contentType: param.contentType || null }) }