diff --git a/modules/angular2/src/router/url_parser.ts b/modules/angular2/src/router/url_parser.ts index 1f0afe62de..ecd91bb223 100644 --- a/modules/angular2/src/router/url_parser.ts +++ b/modules/angular2/src/router/url_parser.ts @@ -84,6 +84,11 @@ function matchUrlSegment(str: string): string { var match = RegExpWrapper.firstMatch(SEGMENT_RE, str); return isPresent(match) ? match[0] : ''; } +var QUERY_PARAM_VALUE_RE = RegExpWrapper.create('^[^\\(\\)\\?;&#]+'); +function matchUrlQueryParamValue(str: string): string { + var match = RegExpWrapper.firstMatch(QUERY_PARAM_VALUE_RE, str); + return isPresent(match) ? match[0] : ''; +} export class UrlParser { private _remaining: string; @@ -163,10 +168,10 @@ export class UrlParser { parseQueryParams(): {[key: string]: any} { var params: {[key: string]: any} = {}; this.capture('?'); - this.parseParam(params); + this.parseQueryParam(params); while (this._remaining.length > 0 && this.peekStartsWith('&')) { this.capture('&'); - this.parseParam(params); + this.parseQueryParam(params); } return params; } @@ -199,6 +204,25 @@ export class UrlParser { params[key] = value; } + parseQueryParam(params: {[key: string]: any}): void { + var key = matchUrlSegment(this._remaining); + if (isBlank(key)) { + return; + } + this.capture(key); + var value: any = true; + if (this.peekStartsWith('=')) { + this.capture('='); + var valueMatch = matchUrlQueryParamValue(this._remaining); + if (isPresent(valueMatch)) { + value = valueMatch; + this.capture(value); + } + } + + params[key] = value; + } + parseAuxiliaryRoutes(): Url[] { var routes: Url[] = []; this.capture('('); diff --git a/modules/angular2/test/router/url_parser_spec.ts b/modules/angular2/test/router/url_parser_spec.ts index e9dfba0b26..b61792f17e 100644 --- a/modules/angular2/test/router/url_parser_spec.ts +++ b/modules/angular2/test/router/url_parser_spec.ts @@ -124,5 +124,12 @@ export function main() { var url = urlParser.parse('hello/there;sort=asc(modal)?friend=true'); expect(url.toString()).toEqual('hello/there;sort=asc(modal)?friend=true'); }); + it('should allow slashes within query parameters', () => { + var url = urlParser.parse( + 'hello?code=4/B8o0n_Y7XZTb-pVKBw5daZyGAUbMljyLf7uNgTy6ja8&scope=https://www.googleapis.com/auth/analytics'); + expect(url.toString()) + .toEqual( + 'hello?code=4/B8o0n_Y7XZTb-pVKBw5daZyGAUbMljyLf7uNgTy6ja8&scope=https://www.googleapis.com/auth/analytics'); + }); }); }