diff --git a/modules/@angular/router/src/url_tree.ts b/modules/@angular/router/src/url_tree.ts index 34571b1f81..118b98a731 100644 --- a/modules/@angular/router/src/url_tree.ts +++ b/modules/@angular/router/src/url_tree.ts @@ -183,7 +183,7 @@ export class DefaultUrlSerializer implements UrlSerializer { serialize(tree: UrlTree): string { const segment = `/${serializeSegment(tree.root, true)}`; const query = serializeQueryParams(tree.queryParams); - const fragment = tree.fragment !== null ? `#${tree.fragment}` : ''; + const fragment = tree.fragment !== null ? `#${encodeURIComponent(tree.fragment)}` : ''; return `${segment}${query}${fragment}`; } } @@ -223,15 +223,18 @@ function serializeSegment(segment: UrlSegment, root: boolean): string { } export function serializePath(path: UrlPathWithParams): string { - return `${path.path}${serializeParams(path.parameters)}`; + return `${encodeURIComponent(path.path)}${serializeParams(path.parameters)}`; } function serializeParams(params: {[key: string]: string}): string { - return pairs(params).map(p => `;${p.first}=${p.second}`).join(''); + return pairs(params) + .map(p => `;${encodeURIComponent(p.first)}=${encodeURIComponent(p.second)}`) + .join(''); } function serializeQueryParams(params: {[key: string]: string}): string { - const strs = pairs(params).map(p => `${p.first}=${p.second}`); + const strs = + pairs(params).map(p => `${encodeURIComponent(p.first)}=${encodeURIComponent(p.second)}`); return strs.length > 0 ? `?${strs.join("&")}` : ''; } @@ -335,7 +338,7 @@ class UrlParser { if (this.peekStartsWith(';')) { matrixParams = this.parseMatrixParams(); } - return new UrlPathWithParams(path, matrixParams); + return new UrlPathWithParams(decodeURIComponent(path), matrixParams); } parseQueryParams(): {[key: string]: any} { @@ -353,7 +356,7 @@ class UrlParser { parseFragment(): string { if (this.peekStartsWith('#')) { - return this.remaining.substring(1); + return decodeURIComponent(this.remaining.substring(1)); } else { return null; } @@ -384,7 +387,7 @@ class UrlParser { } } - params[key] = value; + params[decodeURIComponent(key)] = decodeURIComponent(value); } parseQueryParam(params: {[key: string]: any}): void { @@ -402,7 +405,7 @@ class UrlParser { this.capture(value); } } - params[key] = value; + params[decodeURIComponent(key)] = decodeURIComponent(value); } parseParens(allowPrimary: boolean): {[key: string]: UrlSegment} { diff --git a/modules/@angular/router/test/url_serializer.spec.ts b/modules/@angular/router/test/url_serializer.spec.ts index db56102acb..25e5b073ee 100644 --- a/modules/@angular/router/test/url_serializer.spec.ts +++ b/modules/@angular/router/test/url_serializer.spec.ts @@ -134,6 +134,36 @@ describe('url serializer', () => { expect(tree.fragment).toEqual(''); expect(url.serialize(tree)).toEqual('/one#'); }); + + describe('encoding/decoding', () => { + it('should encode/decode path segments and parameters', () => { + const u = + `/${encodeURIComponent("one two")};${encodeURIComponent("p 1")}=${encodeURIComponent("v 1")};${encodeURIComponent("p 2")}=${encodeURIComponent("v 2")}`; + const tree = url.parse(u); + + expect(tree.root.children[PRIMARY_OUTLET].pathsWithParams[0].path).toEqual('one two'); + expect(tree.root.children[PRIMARY_OUTLET].pathsWithParams[0].parameters) + .toEqual({['p 1']: 'v 1', ['p 2']: 'v 2'}); + expect(url.serialize(tree)).toEqual(u); + }); + + it('should encode/decode query params', () => { + const u = + `/one?${encodeURIComponent("p 1")}=${encodeURIComponent("v 1")}&${encodeURIComponent("p 2")}=${encodeURIComponent("v 2")}`; + const tree = url.parse(u); + + expect(tree.queryParams).toEqual({['p 1']: 'v 1', ['p 2']: 'v 2'}); + expect(url.serialize(tree)).toEqual(u); + }); + + it('should encode/decode fragment', () => { + const u = `/one#${encodeURIComponent("one two")}`; + const tree = url.parse(u); + + expect(tree.fragment).toEqual('one two'); + expect(url.serialize(tree)).toEqual(u); + }); + }); }); function expectSegment(segment: UrlSegment, expected: string, hasChildren: boolean = false): void {