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

Commit

Permalink
SQUASH ME: feat($httpBackend): JSONP requests now require trusted res…
Browse files Browse the repository at this point in the history
…ource
  • Loading branch information
petebacondarwin committed Sep 20, 2016
1 parent fcd8fa9 commit da74d2d
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 17 deletions.
6 changes: 5 additions & 1 deletion docs/content/error/$http/badreq.ngdoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
@fullName Bad Request Configuration
@description

This error occurs when the request configuration parameter passed to the {@link ng.$http `$http`} service is not an object.  `$http` expects a single parameter, the request configuration object, but received a parameter that was not an object.  The error message should provide additional context such as the actual value of the parameter that was received.  If you passed a string parameter, perhaps you meant to call one of the shorthand methods on `$http` such as `$http.get(…)`, etc.
This error occurs when the request configuration parameter passed to the {@link ng.$http `$http`} service is not a valid object.
`$http` expects a single parameter, the request configuration object, but received a parameter that was not an object or did not contain valid properties.

The error message should provide additional context such as the actual value of the parameter that was received.
If you passed a string parameter, perhaps you meant to call one of the shorthand methods on `$http` such as `$http.get(…)`, etc.

To resolve this error, make sure you pass a valid request configuration object to `$http`.

Expand Down
34 changes: 24 additions & 10 deletions src/ng/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -802,7 +802,8 @@ function $HttpProvider() {
* processed. The object has following properties:
*
* - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
* - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
* - **url** – `{string|TrustedObject}` – Absolute or relative URL of the resource that is being requested;
* or an object created by a call to `$sce.trustAsResourceUrl(url)`.
* - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be serialized
* with the `paramSerializer` and appended as GET parameters.
* - **data** – `{string|Object}` – Data to be sent as the request message data.
Expand Down Expand Up @@ -882,6 +883,7 @@ function $HttpProvider() {
<file name="script.js">
angular.module('httpExample', [])
.config(['$sceDelegateProvider', function($sceDelegateProvider) {
// We must whitelist the JSONP endpoint that we are using to show that we trust it
$sceDelegateProvider.resourceUrlWhitelist([
'self',
'https://angularjs.org/**'
Expand Down Expand Up @@ -955,7 +957,7 @@ function $HttpProvider() {
}

if (!isString($sce.valueOf(requestConfig.url))) {
throw minErr('$http')('badreq', 'Http request configuration url must be a string. Received: {0}', requestConfig.url);
throw minErr('$http')('badreq', 'Http request configuration url must be a string or a $sce trusted object. Received: {0}', requestConfig.url);
}

var config = extend({
Expand Down Expand Up @@ -1095,11 +1097,10 @@ function $HttpProvider() {

// send request
try {
var promise = sendReq(config, reqData);
return sendReq(config, reqData).then(transformResponse, transformResponse);
} catch (e) {
return $q.reject(e);
}
return promise.then(transformResponse, transformResponse);
}

function transformResponse(response) {
Expand All @@ -1122,7 +1123,8 @@ function $HttpProvider() {
* @description
* Shortcut method to perform `GET` request.
*
* @param {string} url Relative or absolute URL specifying the destination of the request
* @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
* or an object created by a call to `$sce.trustAsResourceUrl(url)`.
* @param {Object=} config Optional configuration object
* @returns {HttpPromise} Future object
*/
Expand All @@ -1134,7 +1136,8 @@ function $HttpProvider() {
* @description
* Shortcut method to perform `DELETE` request.
*
* @param {string} url Relative or absolute URL specifying the destination of the request
* @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
* or an object created by a call to `$sce.trustAsResourceUrl(url)`.
* @param {Object=} config Optional configuration object
* @returns {HttpPromise} Future object
*/
Expand All @@ -1146,7 +1149,8 @@ function $HttpProvider() {
* @description
* Shortcut method to perform `HEAD` request.
*
* @param {string} url Relative or absolute URL specifying the destination of the request
* @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
* or an object created by a call to `$sce.trustAsResourceUrl(url)`.
* @param {Object=} config Optional configuration object
* @returns {HttpPromise} Future object
*/
Expand All @@ -1157,11 +1161,18 @@ function $HttpProvider() {
*
* @description
* Shortcut method to perform `JSONP` request.
*
* Note that, since JSONP requests are sensitive because the response is given full acces to the browser,
* the url must be declared, via {@link $sce} as a trusted resource URL.
* You can trust a URL by adding it to the whitelist via
* {@link $sceDelegateProvider#resourceUrlWhitelist `$sceDelegateProvider.resourceUrlWhitelist`} or
* by explicitly trusted the URL via {@link $sce#trustAsResourceUrl `$sce.trustAsResourceUrl(url)`}.
*
* If you would like to customise where and how the callbacks are stored then try overriding
* or decorating the {@link $jsonpCallbacks} service.
*
* @param {string} url Relative or absolute URL specifying the destination of the request.
* The name of the callback should be the string `JSON_CALLBACK`.
* @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
* or an object created by a call to `$sce.trustAsResourceUrl(url)`.
* @param {Object=} config Optional configuration object
* @returns {HttpPromise} Future object
*/
Expand Down Expand Up @@ -1263,9 +1274,12 @@ function $HttpProvider() {
url = config.url;

if (lowercase(config.method) === 'jsonp') {
// This is a pretty sensitive operation where we're allowing a script to have full access to
// JSONP is a pretty sensitive operation where we're allowing a script to have full access to
// our DOM and JS space. So we require that the URL satisfies SCE.RESOURCE_URL.
url = $sce.getTrustedResourceUrl(url);
} else if (!isString(url)) {
// If it is not a string then the URL must be a $sce trusted object
url = $sce.valueOf(url);
}

url = buildUrl(url, config.paramSerializer(config.params));
Expand Down
27 changes: 21 additions & 6 deletions test/ng/httpSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -306,16 +306,31 @@ describe('$http', function() {

it('should throw error if the request configuration is not an object', function() {
expect(function() {
$http('/url');
$http('/url');
}).toThrowMinErr('$http','badreq', 'Http request configuration must be an object. Received: /url');
});

it('should throw error if the request configuration url is not a string', function() {
it('should throw error if the request configuration url is not a string nor a trusted object', function() {
expect(function() {
$http({url: false});
}).toThrowMinErr('$http','badreq', 'Http request configuration url must be a string. Received: false');
$http({url: false});
}).toThrowMinErr('$http','badreq', 'Http request configuration url must be a string or a $sce trusted object. Received: false');
expect(function() {
$http({url: null});
}).toThrowMinErr('$http','badreq', 'Http request configuration url must be a string or a $sce trusted object. Received: null');
expect(function() {
$http({url: 42});
}).toThrowMinErr('$http','badreq', 'Http request configuration url must be a string or a $sce trusted object. Received: 42');
expect(function() {
$http({});
}).toThrowMinErr('$http','badreq', 'Http request configuration url must be a string or a $sce trusted object. Received: undefined');
});

it('should accept a $sce trusted object for the request configuration url', function() {
expect(function() {
$httpBackend.expect('GET', '/url').respond('');
$http({url: $sce.trustAsResourceUrl('/url')});
}).not.toThrowMinErr('$http','badreq', 'Http request configuration url must be a string. Received: false');
});

it('should send GET requests if no method specified', function() {
$httpBackend.expect('GET', '/url').respond('');
Expand Down Expand Up @@ -1033,7 +1048,7 @@ describe('$http', function() {
function(e) { error = e; }
);
$rootScope.$digest();
expect(error.message).toContain("[$sce:insecurl]");
expect(error.message).toContain('[$sce:insecurl]');
});

it('should not throw error if the url is an explicitly trusted resource', function() {
Expand All @@ -1043,7 +1058,7 @@ describe('$http', function() {
}).not.toThrow();
});

it('jsonp() should allow trusted url', inject(['$sce', function($sce) {
it('jsonp() should accept explictly trusted urls', inject(['$sce', function($sce) {
$httpBackend.expect('JSONP', '/url').respond('');
$http({method: 'JSONP', url: $sce.trustAsResourceUrl('/url')});

Expand Down

0 comments on commit da74d2d

Please sign in to comment.