Skip to content

Commit

Permalink
fix: moving form-data usage over to using the native FormData object
Browse files Browse the repository at this point in the history
  • Loading branch information
erunion committed Aug 5, 2020
1 parent f28927f commit d493781
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 90 deletions.
1 change: 1 addition & 0 deletions .jshintrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"asi": true,
"browser": true,
"node": true
}
89 changes: 13 additions & 76 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
128 changes: 128 additions & 0 deletions src/helpers/form-data.js
Original file line number Diff line number Diff line change
@@ -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
28 changes: 16 additions & 12 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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

Expand Down

0 comments on commit d493781

Please sign in to comment.