Skip to content
This repository has been archived by the owner on Jun 7, 2019. It is now read-only.

Commit

Permalink
Add multipart/form-data mime support
Browse files Browse the repository at this point in the history
  • Loading branch information
mjackson authored and scothis committed Jul 6, 2014
1 parent 7261ed9 commit de075cb
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 0 deletions.
6 changes: 6 additions & 0 deletions client/xhr.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@
headers = request.headers;
for (headerName in headers) {
/*jshint forin:false */
if (headerName === 'Content-Type' && headers[headerName] === 'multipart/form-data') {
// XMLHttpRequest generates its own Content-Type header with the
// appropriate multipart boundary when sending multipart/form-data.
continue;
}

client.setRequestHeader(headerName, headers[headerName]);
}

Expand Down
73 changes: 73 additions & 0 deletions mime/type/multipart/form-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright 2014 the original author or authors
* @license MIT, see LICENSE.txt for details
*
* @author Michael Jackson
*/

/* global FormData, File, Blob */

(function (define) {
'use strict';

define(function (/* require */) {

function isFormElement(object) {
return object &&
object.nodeType === 1 && // Node.ELEMENT_NODE
object.tagName === 'FORM';
}

function createFormDataFromObject(object) {
var formData = new FormData();

var value;
for (var property in object) {
if (object.hasOwnProperty(property)) {
value = object[property];

if (value instanceof File) {
formData.append(property, value, value.name);
} else if (value instanceof Blob) {
formData.append(property, value);
} else {
formData.append(property, String(value));
}
}
}

return formData;
}

return {

write: function (object) {
if (typeof FormData === 'undefined') {
throw new Error('The multipart/form-data mime serializer requires FormData support');
}

// Support FormData directly.
if (object instanceof FormData) {
return object;
}

// Support <form> elements.
if (isFormElement(object)) {
return new FormData(object);
}

// Support plain objects, may contain File/Blob as value.
if (typeof object === 'object' && object !== null) {
return createFormDataFromObject(object);
}

throw new Error('Unable to create FormData from object ' + object);
}

};
});

}(
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }
// Boilerplate for AMD and Node
));
24 changes: 24 additions & 0 deletions test/client/xhr-test-browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,30 @@
},
'should return a ResponsePromise': function () {
assert(client() instanceof responsePromise.ResponsePromise);
},
'should ignore a "Content-Type: multipart/form-data" header': function () {
function XMLHttpRequestSpy() {
var xhr = new XMLHttpRequest();

xhr.requestHeaders = {};

var setRequestHeader = xhr.setRequestHeader;
xhr.setRequestHeader = function (header, value) {
xhr.requestHeaders[header] = value;
return setRequestHeader.apply(xhr, arguments);
};

return xhr;
}

return client({
engine: XMLHttpRequestSpy,
method: 'POST',
headers: { 'Content-Type': 'multipart/form-data' },
path: '/'
}).then(function (response) {
assert(!('Content-Type' in response.raw.requestHeaders));
});
}
});
// TODO spy XmlHttpRequest
Expand Down
54 changes: 54 additions & 0 deletions test/mime/type/multipart/form-data-test-browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2014 the original author or authors
* @license MIT, see LICENSE.txt for details
*
* @author Michael Jackson
*/

(function (buster, define) {
'use strict';

var assert, refute;

assert = buster.assertions.assert;
refute = buster.assertions.refute;

define('rest/mime/type/multipart/form-data-test', function (require) {

var encoder = require('rest/mime/type/multipart/form-data');

buster.testCase('rest/mime/type/multipart/form-data', {
'': {
requiresSupportFor: { FormData: 'FormData' in window },
'should pass a FormData object through unmodified': function () {
var data = new FormData();
assert.same(encoder.write(data), data);
},
'should encode a <form> element as FormData': function () {
var form = document.createElement('form');
assert.hasPrototype(encoder.write(form), FormData.prototype);
},
'should encode a plain object as FormData': function () {
assert.hasPrototype(encoder.write({ a: 'string', b: 5 }), FormData.prototype);
},
'should throw when given a non-object': function () {
assert.exception(function () {
encoder.write('hello world');
}, 'Error');
}
}
});

});

}(
this.buster || require('buster'),
typeof define === 'function' && define.amd ? define : function (id, factory) {
var packageName = id.split(/[\/\-]/)[0], pathToRoot = id.replace(/[^\/]+/g, '..');
pathToRoot = pathToRoot.length > 2 ? pathToRoot.substr(3) : pathToRoot;
factory(function (moduleId) {
return require(moduleId.indexOf(packageName) === 0 ? pathToRoot + moduleId.substr(packageName.length) : moduleId);
});
}
// Boilerplate for AMD and Node
));

0 comments on commit de075cb

Please sign in to comment.