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/src/helpers/form-data.js b/src/helpers/form-data.js new file mode 100644 index 000000000..6a9e917aa --- /dev/null +++ b/src/helpers/form-data.js @@ -0,0 +1,105 @@ +/** + * @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. + * + * Extracted from https://github.com/node-fetch/node-fetch/blob/64c5c296a0250b852010746c76144cb9e14698d9/src/utils/form-data.js + */ + +const carriage = '\r\n' +const dashes = '-'.repeat(2) + +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) +} + +module.exports.isBlob = isBlob diff --git a/src/index.js b/src/index.js index 64067f608..c943e7adb 100644 --- a/src/index.js +++ b/src/index.js @@ -1,14 +1,19 @@ +/* eslint-env browser */ + 'use strict' 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') 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 @@ -104,22 +109,59 @@ 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 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. + // - `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 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 = !(form instanceof FormDataPolyfill) + // easter egg - form._boundary = '---011000010111000001101001' + const boundary = '---011000010111000001101001' + if (!isNativeFormData) { + form._boundary = boundary + } request.postData.params.forEach(function (param) { - form.append(param.name, param.value || '', { - filename: param.fileName || null, - contentType: param.contentType || null - }) + const name = param.name + const value = param.value || '' + const filename = param.fileName || null + + if (isNativeFormData) { + if (isBlob(value)) { + form.append(name, value, filename) + } else { + form.append(name, value) + } + } else { + form.append(name, value, { + filename: filename, + contentType: param.contentType || null + }) + } }) - form.pipe(es.map(function (data, cb) { - 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 = 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 diff --git a/src/targets/node/request.js b/src/targets/node/request.js index d704ae19f..06d89ebdf 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 + '")' @@ -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/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 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/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 84d816975..defd7acbb 100644 --- a/test/fixtures/output/node/request/multipart-data.js +++ b/test/fixtures/output/node/request/multipart-data.js @@ -1,3 +1,4 @@ +const fs = require('fs'); const request = require('request'); const options = { @@ -6,11 +7,8 @@ const options = { headers: {'content-type': 'multipart/form-data; boundary=---011000010111000001101001'}, formData: { foo: { - value: 'Hello World', - options: { - filename: 'hello.txt', - contentType: 'text/plain' - } + 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 61ca0c803..8cb2864ba 100644 --- a/test/fixtures/output/node/request/multipart-file.js +++ b/test/fixtures/output/node/request/multipart-file.js @@ -7,11 +7,8 @@ const options = { headers: {'content-type': 'multipart/form-data; boundary=---011000010111000001101001'}, formData: { foo: { - value: 'fs.createReadStream("test/fixtures/files/hello.txt")', - options: { - filename: 'test/fixtures/files/hello.txt', - contentType: 'text/plain' - } + value: fs.createReadStream('test/fixtures/files/hello.txt'), + options: {filename: 'test/fixtures/files/hello.txt', contentType: 'text/plain'} } } }; 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/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 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/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() }) diff --git a/test/targets.js b/test/targets.js index 6e3e0284a..03be06502 100644 --- a/test/targets.js +++ b/test/targets.js @@ -47,7 +47,7 @@ const skipMe = { 'clj_http': ['jsonObj-null-value', 'jsonObj-multiline'] }, '*': { - '*': ['multipart-data', 'multipart-file', 'multipart-form-data'] + '*': [] } } @@ -77,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()) }) }