Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 1bd473e

Browse files
committed
fix($templateRequest): ignore JSON Content-Type header and content
Normally, if there is a Content-Type header with the string "application/json", or else the content looks sort of JSON-y, $http will attempt to deserialize the JSON into an object. $templateRequest is intended to request markup, and as such should never attempt to parse JSON, regardless of the headers or shape of the content. Closes #5756 Closes #9619
1 parent 9078a6a commit 1bd473e

File tree

4 files changed

+88
-19
lines changed

4 files changed

+88
-19
lines changed

src/.jshintrc

+2
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@
100100
"NODE_TYPE_DOCUMENT": false,
101101
"NODE_TYPE_DOCUMENT_FRAGMENT": false,
102102

103+
"httpResponseTransform": false,
104+
103105
/* filters.js */
104106
"getFirstThursdayOfYear": false,
105107

src/ng/http.js

+20-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
'use strict';
22

3+
var APPLICATION_JSON = 'application/json';
4+
var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
5+
var JSON_START = /^\s*(\[|\{[^\{])/;
6+
var JSON_END = /[\}\]]\s*$/;
7+
var JSON_PROTECTION_PREFIX = /^\)\]\}',?\n/;
8+
9+
function defaultHttpResponseTransform(data, headers) {
10+
if (isString(data)) {
11+
// strip json vulnerability protection prefix
12+
data = data.replace(JSON_PROTECTION_PREFIX, '');
13+
var contentType = headers('Content-Type');
14+
if ((contentType && contentType.indexOf(APPLICATION_JSON) === 0) ||
15+
(JSON_START.test(data) && JSON_END.test(data))) {
16+
data = fromJson(data);
17+
}
18+
}
19+
return data;
20+
}
21+
322
/**
423
* Parse headers into key value object
524
*
@@ -86,12 +105,6 @@ function isSuccess(status) {
86105
* Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
87106
* */
88107
function $HttpProvider() {
89-
var JSON_START = /^\s*(\[|\{[^\{])/,
90-
JSON_END = /[\}\]]\s*$/,
91-
PROTECTION_PREFIX = /^\)\]\}',?\n/,
92-
APPLICATION_JSON = 'application/json',
93-
CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
94-
95108
/**
96109
* @ngdoc property
97110
* @name $httpProvider#defaults
@@ -115,18 +128,7 @@ function $HttpProvider() {
115128
**/
116129
var defaults = this.defaults = {
117130
// transform incoming response data
118-
transformResponse: [function defaultHttpResponseTransform(data, headers) {
119-
if (isString(data)) {
120-
// strip json vulnerability protection prefix
121-
data = data.replace(PROTECTION_PREFIX, '');
122-
var contentType = headers('Content-Type');
123-
if ((contentType && contentType.indexOf(APPLICATION_JSON) === 0) ||
124-
(JSON_START.test(data) && JSON_END.test(data))) {
125-
data = fromJson(data);
126-
}
127-
}
128-
return data;
129-
}],
131+
transformResponse: [defaultHttpResponseTransform],
130132

131133
// transform outgoing request data
132134
transformRequest: [function(d) {

src/ng/templateRequest.js

+22-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,28 @@ function $TemplateRequestProvider() {
2525
var self = handleRequestFn;
2626
self.totalPendingRequests++;
2727

28-
return $http.get(tpl, { cache : $templateCache })
28+
var transformResponse = $http.defaults && $http.defaults.transformResponse;
29+
var idx;
30+
31+
if (isArray(transformResponse)) {
32+
var original = transformResponse;
33+
transformResponse = [];
34+
for (var i=0; i<original.length; ++i) {
35+
var transformer = original[i];
36+
if (transformer !== defaultHttpResponseTransform) {
37+
transformResponse.push(transformer);
38+
}
39+
}
40+
} else if (transformResponse === defaultHttpResponseTransform) {
41+
transformResponse = null;
42+
}
43+
44+
var httpOptions = {
45+
cache: $templateCache,
46+
transformResponse: transformResponse
47+
};
48+
49+
return $http.get(tpl, httpOptions)
2950
.then(function(response) {
3051
var html = response.data;
3152
if(!html || html.length === 0) {

test/ng/templateRequestSpec.js

+44
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,48 @@ describe('$templateRequest', function() {
8686
expect($templateRequest.totalPendingRequests).toBe(0);
8787
}));
8888

89+
it('should not try to parse a response as JSON',
90+
inject(function($templateRequest, $httpBackend) {
91+
var spy = jasmine.createSpy('success');
92+
$httpBackend.expectGET('a.html').respond('{{text}}', {
93+
'Content-Type': 'application/json'
94+
});
95+
$templateRequest('a.html').then(spy);
96+
$httpBackend.flush();
97+
expect(spy).toHaveBeenCalledOnceWith('{{text}}');
98+
}));
99+
100+
it('should use custom response transformers (array)', function() {
101+
module(function($httpProvider) {
102+
$httpProvider.defaults.transformResponse.push(function(data) {
103+
return data + '!!';
104+
});
105+
});
106+
inject(function($templateRequest, $httpBackend) {
107+
var spy = jasmine.createSpy('success');
108+
$httpBackend.expectGET('a.html').respond('{{text}}', {
109+
'Content-Type': 'application/json'
110+
});
111+
$templateRequest('a.html').then(spy);
112+
$httpBackend.flush();
113+
expect(spy).toHaveBeenCalledOnceWith('{{text}}!!');
114+
});
115+
});
116+
117+
it('should use custom response transformers (function)', function() {
118+
module(function($httpProvider) {
119+
$httpProvider.defaults.transformResponse = function(data) {
120+
return data + '!!';
121+
};
122+
});
123+
inject(function($templateRequest, $httpBackend) {
124+
var spy = jasmine.createSpy('success');
125+
$httpBackend.expectGET('a.html').respond('{{text}}', {
126+
'Content-Type': 'application/json'
127+
});
128+
$templateRequest('a.html').then(spy);
129+
$httpBackend.flush();
130+
expect(spy).toHaveBeenCalledOnceWith('{{text}}!!');
131+
});
132+
});
89133
});

0 commit comments

Comments
 (0)