Skip to content

Commit

Permalink
Merge f20490e into 580ef52
Browse files Browse the repository at this point in the history
  • Loading branch information
nickuraltsev committed May 7, 2016
2 parents 580ef52 + f20490e commit 93d2157
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 20 deletions.
6 changes: 5 additions & 1 deletion README.md
Expand Up @@ -216,6 +216,7 @@ These are the available config options for making requests. Only the `url` is re
headers: {'X-Requested-With': 'XMLHttpRequest'},

// `params` are the URL parameters to be sent with the request
// Must be a plain object or a URLSearchParams object
params: {
ID: 12345
},
Expand All @@ -228,7 +229,10 @@ These are the available config options for making requests. Only the `url` is re

// `data` is the data to be sent as the request body
// Only applicable for request methods 'PUT', 'POST', and 'PATCH'
// When no `transformRequest` is set, must be a string, an ArrayBuffer, a hash, or a Stream
// When no `transformRequest` is set, must be of one of the following types:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - Browser only: FormData, File, Blob
// - Node only: Stream
data: {
firstName: 'Fred'
},
Expand Down
34 changes: 20 additions & 14 deletions lib/defaults.js
@@ -1,33 +1,39 @@
'use strict';

var utils = require('./utils');
var normalizeHeaderName = require('./helpers/normalizeHeaderName');

var PROTECTION_PREFIX = /^\)\]\}',?\n/;
var DEFAULT_CONTENT_TYPE = {
'Content-Type': 'application/x-www-form-urlencoded'
};

function setContentTypeIfUnset(headers, value) {
if (!utils.isUndefined(headers) && utils.isUndefined(headers['Content-Type'])) {
headers['Content-Type'] = value;
}
}

module.exports = {
transformRequest: [function transformRequest(data, headers) {
if (utils.isFormData(data) || utils.isArrayBuffer(data) || utils.isStream(data)) {
normalizeHeaderName(headers, 'Content-Type');
if (utils.isFormData(data) ||
utils.isArrayBuffer(data) ||
utils.isStream(data) ||
utils.isFile(data) ||
utils.isBlob(data)
) {
return data;
}
if (utils.isArrayBufferView(data)) {
return data.buffer;
}
if (utils.isObject(data) && !utils.isFile(data) && !utils.isBlob(data)) {
// Set application/json if no Content-Type has been specified
if (!utils.isUndefined(headers)) {
utils.forEach(headers, function processContentTypeHeader(val, key) {
if (key.toLowerCase() === 'content-type') {
headers['Content-Type'] = val;
}
});

if (utils.isUndefined(headers['Content-Type'])) {
headers['Content-Type'] = 'application/json;charset=utf-8';
}
}
if (utils.isURLSearchParams(data)) {
setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8');
return data.toString();
}
if (utils.isObject(data)) {
setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
return JSON.stringify(data);
}
return data;
Expand Down
3 changes: 2 additions & 1 deletion lib/helpers/buildURL.js
Expand Up @@ -29,6 +29,8 @@ module.exports = function buildURL(url, params, paramsSerializer) {
var serializedParams;
if (paramsSerializer) {
serializedParams = paramsSerializer(params);
} else if (utils.isURLSearchParams(params)) {
serializedParams = params.toString();
} else {
var parts = [];

Expand Down Expand Up @@ -64,4 +66,3 @@ module.exports = function buildURL(url, params, paramsSerializer) {

return url;
};

12 changes: 12 additions & 0 deletions lib/helpers/normalizeHeaderName.js
@@ -0,0 +1,12 @@
'use strict';

var utils = require('../utils');

module.exports = function normalizeHeaderName(headers, normalizedName) {
utils.forEach(headers, function processHeader(value, name) {
if (name !== normalizedName && name.toUpperCase() === normalizedName.toUpperCase()) {
headers[normalizedName] = value;
delete headers[name];
}
});
};
19 changes: 19 additions & 0 deletions lib/utils.js
Expand Up @@ -142,6 +142,24 @@ function isStream(val) {
return isObject(val) && isFunction(val.pipe);
}

/**
* Determine if a value is a URLSearchParams object
*
* @param {Object} val The value to test
* @returns {boolean} True if value is a URLSearchParams object, otherwise false
*/
function isURLSearchParams(val) {
// Object.prototype.toString will return [object Object] for a polyfill
// Hence, we have to use duck typing
return toString.call(val) === '[object URLSearchParams]' || (
isObject(val) &&
isFunction(val.append) &&
isFunction(val.delete) &&
isFunction(val.get) &&
isFunction(val.set)
);
}

/**
* Trim excess whitespace off the beginning and end of a string
*
Expand Down Expand Up @@ -259,6 +277,7 @@ module.exports = {
isBlob: isBlob,
isFunction: isFunction,
isStream: isStream,
isURLSearchParams: isURLSearchParams,
isStandardBrowserEnv: isStandardBrowserEnv,
forEach: forEach,
merge: merge,
Expand Down
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -63,7 +63,8 @@
"phantomjs-prebuilt": "2.1.6",
"sinon": "1.17.3",
"webpack": "1.12.14",
"webpack-dev-server": "1.14.1"
"webpack-dev-server": "1.14.1",
"url-search-params": "0.5.0"
},
"browser": {
"./lib/adapters/http.js": "./lib/adapters/xhr.js"
Expand Down
9 changes: 6 additions & 3 deletions test/specs/helpers/buildURL.spec.js
@@ -1,4 +1,5 @@
var buildURL = require('../../../lib/helpers/buildURL');
var URLSearchParams = require('url-search-params');

describe('helpers::buildURL', function () {
it('should support null params', function () {
Expand Down Expand Up @@ -60,7 +61,9 @@ describe('helpers::buildURL', function () {
expect(buildURL('/foo', params, serializer)).toEqual('/foo?foo=bar');
expect(serializer.calledOnce).toBe(true);
expect(serializer.calledWith(params)).toBe(true);
})
});

});

it('should support URLSearchParams', function () {
expect(buildURL('/foo', new URLSearchParams('bar=baz'))).toEqual('/foo?bar=baz');
});
});
21 changes: 21 additions & 0 deletions test/specs/helpers/normalizeHeaderName.spec.js
@@ -0,0 +1,21 @@
var normalizeHeaderName = require('../../../lib/helpers/normalizeHeaderName');

describe('helpers::normalizeHeaderName', function () {
it('should normalize matching header name', function () {
var headers = {
'conTenT-Type': 'foo/bar',
};
normalizeHeaderName(headers, 'Content-Type');
expect(headers['Content-Type']).toBe('foo/bar');
expect(headers['conTenT-Type']).toBeUndefined();
});

it('should not change non-matching header name', function () {
var headers = {
'content-type': 'foo/bar',
};
normalizeHeaderName(headers, 'Content-Length');
expect(headers['content-type']).toBe('foo/bar');
expect(headers['Content-Length']).toBeUndefined();
});
});
15 changes: 15 additions & 0 deletions test/specs/requests.spec.js
@@ -1,3 +1,5 @@
var URLSearchParams = require('url-search-params');

describe('requests', function () {
beforeEach(function () {
jasmine.Ajax.install();
Expand Down Expand Up @@ -277,4 +279,17 @@ describe('requests', function () {
});
});

it('should support URLSearchParams', function (done) {
var params = new URLSearchParams();
params.append('param1', 'value1');
params.append('param2', 'value2');

axios.post('/foo', params);

getAjaxRequest().then(function (request) {
expect(request.requestHeaders['Content-Type']).toBe('application/x-www-form-urlencoded;charset=utf-8');
expect(request.params).toBe('param1=value1&param2=value2');
done();
});
});
});
6 changes: 6 additions & 0 deletions test/specs/utils/isX.spec.js
@@ -1,5 +1,6 @@
var utils = require('../../../lib/utils');
var Stream = require('stream');
var URLSearchParams = require('url-search-params');

describe('utils::isX', function () {
it('should validate Array', function () {
Expand Down Expand Up @@ -78,4 +79,9 @@ describe('utils::isX', function () {
expect(utils.isStream(new Stream.Readable())).toEqual(true);
expect(utils.isStream({ foo: 'bar' })).toEqual(false);
});

it('should validate URLSearchParams', function () {
expect(utils.isURLSearchParams(new URLSearchParams())).toEqual(true);
expect(utils.isURLSearchParams('foo=1&bar=2')).toEqual(false);
});
});

0 comments on commit 93d2157

Please sign in to comment.