diff --git a/src/Angular.js b/src/Angular.js index 4187e9ad6f9e..e635f0d89eda 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -839,6 +839,23 @@ function toKeyValue(obj) { return parts.length ? parts.join('&') : ''; } + +/** + * we need our custom mehtod because encodeURIComponent is too agressive and doesn't follow + * http://www.ietf.org/rfc/rfc2396.txt with regards to the character set (pchar) allowed in path + * segments + */ +function encodeUriSegment(val) { + return encodeURIComponent(val). + replace(/%40/gi, '@'). + replace(/%3A/gi, ':'). + replace(/%26/gi, '&'). + replace(/%3D/gi, '='). + replace(/%2B/gi, '+'). + replace(/%24/g, '$'). + replace(/%2C/gi, ','); +} + /** * @workInProgress * @ngdoc directive diff --git a/src/Resource.js b/src/Resource.js index e801d20024fe..f748fb5a3e84 100644 --- a/src/Resource.js +++ b/src/Resource.js @@ -13,19 +13,20 @@ function Route(template, defaults) { Route.prototype = { url: function(params) { - var path = []; - var self = this; - var url = this.template; + var self = this, + url = this.template, + encodedVal; + params = params || {}; forEach(this.urlParams, function(_, urlParam){ - var value = params[urlParam] || self.defaults[urlParam] || ""; - url = url.replace(new RegExp(":" + urlParam + "(\\W)"), encodeURIComponent(value) + "$1"); + encodedVal = encodeUriSegment(params[urlParam] || self.defaults[urlParam] || "") + url = url.replace(new RegExp(":" + urlParam + "(\\W)"), encodedVal + "$1"); }); url = url.replace(/\/?#$/, ''); var query = []; forEachSorted(params, function(value, key){ if (!self.urlParams[key]) { - query.push(encodeURIComponent(key) + '=' + encodeURIComponent(value)); + query.push(encodeUriSegment(key) + '=' + encodeUriSegment(value)); } }); url = url.replace(/\/*$/, ''); diff --git a/test/AngularSpec.js b/test/AngularSpec.js index 010dce7c7fd3..bcc3d105ede5 100644 --- a/test/AngularSpec.js +++ b/test/AngularSpec.js @@ -141,6 +141,26 @@ describe('toKeyValue', function() { }); }); +describe('encodeUriSegment', function() { + it('should correctly encode uri segment and not encode chars defined as pchar set in rfc2396', + function() { + //don't encode alphanum + expect(encodeUriSegment('asdf1234asdf')). + toEqual('asdf1234asdf'); + + //don't encode unreserved' + expect(encodeUriSegment("-_.!~*'() -_.!~*'()")). + toEqual("-_.!~*'()%20-_.!~*'()"); + + //don't encode the rest of pchar' + expect(encodeUriSegment(':@&=+$, :@&=+$,')). + toEqual(':@&=+$,%20:@&=+$,'); + + //encode '/', ';' and ' '' + expect(encodeUriSegment('/; /;')). + toEqual('%2F%3B%20%2F%3B'); + }); +}); describe ('rngScript', function() { it('should match angular.js', function() { diff --git a/test/ResourceSpec.js b/test/ResourceSpec.js index d61282ea1540..175725aa4b75 100644 --- a/test/ResourceSpec.js +++ b/test/ResourceSpec.js @@ -43,11 +43,22 @@ describe("resource", function() { it('should correctly encode url params', function(){ var R = resource.route('/Path/:a'); xhr.expectGET('/Path/foo%231').respond({}); - xhr.expectGET('/Path/doh!%40foo?bar=baz%231').respond({}); + xhr.expectGET('/Path/doh!@foo?bar=baz%231').respond({}); R.get({a: 'foo#1'}); R.get({a: 'doh!@foo', bar: 'baz#1'}); }); + it('should not encode @ in url params', function() { + //encodeURIComponent is too agressive and doesn't follow http://www.ietf.org/rfc/rfc2396.txt + //with regards to the character set (pchar) allowed in path segments + //so we need this test to make sure that we don't over-encode the params and break stuff like + //buzz api which uses @self + + var R = resource.route('/Path/:a'); + xhr.expectGET('/Path/doh@foo?bar=baz@1').respond({}); + R.get({a: 'doh@foo', bar: 'baz@1'}); + }) + it("should build resource with default param", function(){ xhr.expectGET('/Order/123/Line/456.visa?minimum=0.05').respond({id:'abc'}); var LineItem = resource.route('/Order/:orderId/Line/:id:verb', {orderId: '123', id: '@id.key', verb:'.visa', minimum:0.05});