Skip to content

Commit

Permalink
Flatten parameters in multipart requests
Browse files Browse the repository at this point in the history
  • Loading branch information
ob-stripe committed Apr 26, 2019
1 parent 4d03a67 commit 77b7367
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 1 deletion.
3 changes: 2 additions & 1 deletion lib/MultipartDataGenerator.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

var Buffer = require('safe-buffer').Buffer;
var utils = require('./utils');

// Method for formatting HTTP body for the multipart/form-data specification
// Mostly taken from Fermata.js
Expand All @@ -23,7 +24,7 @@ function multipartDataGenerator(method, data, headers) {
return '"' + s.replace(/"|"/g, '%22').replace(/\r\n|\r|\n/g, ' ') + '"';
}

for (var k in data) {
for (var k in utils.flattenAndStringify(data)) {
var v = data[k];
push('--' + segno);
if (v.hasOwnProperty('data')) {
Expand Down
35 changes: 35 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,41 @@ var utils = module.exports = {

// For mocking in tests.
_exec: exec,

// For use in multipart requests
flattenAndStringify: function flattenAndStringify(data) {
var result = {};

function isObject(obj) {
var type = typeof obj;
return (type === 'function' || type === 'object') && !!obj;
}

function step(obj, prevKey) {
Object.keys(obj).forEach(function (key) {
var value = obj[key];

var newKey = prevKey ? `${prevKey}[${key}]` : key;

if (isObject(value)) {
if (!Buffer.isBuffer(value) && !value.hasOwnProperty('data')) {
// Non-buffer non-file Objects are recursively flattened
return step(value, newKey);
} else {
// Buffers and file objects are stored without modification
result[newKey] = value;
}
} else {
// Primitives are converted to strings
result[newKey] = String(value);
}
})
}

step(data);

return result;
}
};

function emitWarning(warning) {
Expand Down
4 changes: 4 additions & 0 deletions test/resources/FileUploads.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ describe('File Uploads Resource', function() {
name: 'minimal.pdf',
type: 'application/octet-stream',
},
file_link_data: {create: true},
});

expect(stripe.LAST_REQUEST).to.deep.property('host', 'files.stripe.com');
Expand All @@ -73,6 +74,7 @@ describe('File Uploads Resource', function() {
name: 'minimal.pdf',
type: 'application/octet-stream',
},
file_link_data: {create: true},
}, TEST_AUTH_KEY);

expect(stripe.LAST_REQUEST).to.deep.property('host', 'files.stripe.com');
Expand All @@ -92,6 +94,7 @@ describe('File Uploads Resource', function() {
name: 'minimal.pdf',
type: 'application/octet-stream',
},
file_link_data: {create: true},
}).then(function() {
expect(stripe.LAST_REQUEST).to.deep.property('host', 'files.stripe.com');
expect(stripe.LAST_REQUEST).to.deep.property('method', 'POST');
Expand All @@ -110,6 +113,7 @@ describe('File Uploads Resource', function() {
name: 'minimal.pdf',
type: 'application/octet-stream',
},
file_link_data: {create: true},
}, TEST_AUTH_KEY).then(function() {
expect(stripe.LAST_REQUEST).to.deep.property('host', 'files.stripe.com');
expect(stripe.LAST_REQUEST).to.deep.property('method', 'POST');
Expand Down
4 changes: 4 additions & 0 deletions test/resources/Files.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ describe('Files Resource', function() {
name: 'minimal.pdf',
type: 'application/octet-stream',
},
file_link_data: {create: true},
});

expect(stripe.LAST_REQUEST).to.deep.property('host', 'files.stripe.com');
Expand All @@ -73,6 +74,7 @@ describe('Files Resource', function() {
name: 'minimal.pdf',
type: 'application/octet-stream',
},
file_link_data: {create: true},
}, TEST_AUTH_KEY);

expect(stripe.LAST_REQUEST).to.deep.property('host', 'files.stripe.com');
Expand All @@ -92,6 +94,7 @@ describe('Files Resource', function() {
name: 'minimal.pdf',
type: 'application/octet-stream',
},
file_link_data: {create: true},
}).then(function() {
expect(stripe.LAST_REQUEST).to.deep.property('host', 'files.stripe.com');
expect(stripe.LAST_REQUEST).to.deep.property('method', 'POST');
Expand All @@ -110,6 +113,7 @@ describe('Files Resource', function() {
name: 'minimal.pdf',
type: 'application/octet-stream',
},
file_link_data: {create: true},
}, TEST_AUTH_KEY).then(function() {
expect(stripe.LAST_REQUEST).to.deep.property('host', 'files.stripe.com');
expect(stripe.LAST_REQUEST).to.deep.property('method', 'POST');
Expand Down
46 changes: 46 additions & 0 deletions test/utils.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ require('../testUtils');

var utils = require('../lib/utils');
var expect = require('chai').expect;
var Buffer = require('safe-buffer').Buffer;

describe('utils', function() {
describe('makeURLInterpolator', function() {
Expand Down Expand Up @@ -338,6 +339,51 @@ describe('utils', function() {
]);
});
})

describe('flattenAndStringify', function() {
it('Stringifies primitive types', function() {
expect(utils.flattenAndStringify({
a: 1,
b: 'foo',
c: true,
d: null,
})).to.eql({'a': '1', 'b': 'foo', 'c': 'true', 'd': 'null'});
});

it('Flattens nested values', function() {
expect(utils.flattenAndStringify({
x: {
a: 1,
b: 'foo',
},
})).to.eql({'x[a]': '1', 'x[b]': 'foo'});
});

it('Does not flatten File objects', function() {
expect(utils.flattenAndStringify({
file: {
data: 'foo'
},
x: {
a: 1,
},
})).to.eql({'file': {data: 'foo'}, 'x[a]': '1'});
});

it('Does not flatten Buffer objects', function() {
var buf = Buffer.from('Hi!');
var flattened = utils.flattenAndStringify({
buf: buf,
x: {
a: 1,
},
});
expect(flattened).to.have.property('buf');
expect(flattened.buf).to.deep.equal(buf);
expect(flattened).to.have.property('x[a]');
expect(flattened['x[a]']).to.equal('1');
});
});
});

function handleWarnings(doWithShimmedConsoleWarn, onWarn) {
Expand Down

0 comments on commit 77b7367

Please sign in to comment.