fix($http): honor application/json response header and parse json primitives

When server responds with Content-Type header set to application/json we now properly parse the response as JSON

Closes #2973
This commit is contained in:
Igor Minar
2014-10-02 13:46:22 -07:00
parent 858360b680
commit 7b6c1d08ac
2 changed files with 62 additions and 3 deletions

View File

@@ -89,7 +89,8 @@ function $HttpProvider() {
var JSON_START = /^\s*(\[|\{[^\{])/,
JSON_END = /[\}\]]\s*$/,
PROTECTION_PREFIX = /^\)\]\}',?\n/,
CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': 'application/json;charset=utf-8'};
APPLICATION_JSON = 'application/json',
CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
/**
* @ngdoc property
@@ -114,12 +115,15 @@ function $HttpProvider() {
**/
var defaults = this.defaults = {
// transform incoming response data
transformResponse: [function(data) {
transformResponse: [function defaultHttpResponseTransform(data, headers) {
if (isString(data)) {
// strip json vulnerability protection prefix
data = data.replace(PROTECTION_PREFIX, '');
if (JSON_START.test(data) && JSON_END.test(data))
var contentType = headers('Content-Type');
if ((contentType && contentType.indexOf(APPLICATION_JSON) === 0) ||
(JSON_START.test(data) && JSON_END.test(data))) {
data = fromJson(data);
}
}
return data;
}],

View File

@@ -1020,6 +1020,61 @@ describe('$http', function() {
});
it('should deserialize json numbers when response header contains application/json',
function() {
$httpBackend.expect('GET', '/url').respond('123', {'Content-Type': 'application/json'});
$http({method: 'GET', url: '/url'}).success(callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
expect(callback.mostRecentCall.args[0]).toEqual(123);
});
it('should deserialize json strings when response header contains application/json',
function() {
$httpBackend.expect('GET', '/url').respond('"asdf"', {'Content-Type': 'application/json'});
$http({method: 'GET', url: '/url'}).success(callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
expect(callback.mostRecentCall.args[0]).toEqual('asdf');
});
it('should deserialize json nulls when response header contains application/json',
function() {
$httpBackend.expect('GET', '/url').respond('null', {'Content-Type': 'application/json'});
$http({method: 'GET', url: '/url'}).success(callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
expect(callback.mostRecentCall.args[0]).toEqual(null);
});
it('should deserialize json true when response header contains application/json',
function() {
$httpBackend.expect('GET', '/url').respond('true', {'Content-Type': 'application/json'});
$http({method: 'GET', url: '/url'}).success(callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
expect(callback.mostRecentCall.args[0]).toEqual(true);
});
it('should deserialize json false when response header contains application/json',
function() {
$httpBackend.expect('GET', '/url').respond('false', {'Content-Type': 'application/json'});
$http({method: 'GET', url: '/url'}).success(callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
expect(callback.mostRecentCall.args[0]).toEqual(false);
});
it('should deserialize json with security prefix', function() {
$httpBackend.expect('GET', '/url').respond(')]}\',\n[1, "abc", {"foo":"bar"}]');
$http({method: 'GET', url: '/url'}).success(callback);