From c20f60b1444f6e7af784be7281535bd5db03c499 Mon Sep 17 00:00:00 2001 From: Jason Aden Date: Fri, 26 May 2017 11:02:31 -0700 Subject: [PATCH] fix(router): make remove trailing slash consistent with URL params closes #16069 --- packages/common/src/location/location.ts | 11 ++++- .../common/test/location/location_spec.ts | 42 +++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 packages/common/test/location/location_spec.ts diff --git a/packages/common/src/location/location.ts b/packages/common/src/location/location.ts index 2ff9133e00..ed895260e4 100644 --- a/packages/common/src/location/location.ts +++ b/packages/common/src/location/location.ts @@ -168,9 +168,16 @@ export class Location { } /** - * If url has a trailing slash, remove it, otherwise return url as is. + * If url has a trailing slash, remove it, otherwise return url as is. This + * method looks for the first occurence of either #, ?, or the end of the + * line as `/` characters after any of these should not be replaced. */ - public static stripTrailingSlash(url: string): string { return url.replace(/\/$/, ''); } + public static stripTrailingSlash(url: string): string { + const match = url.match(/#|\?|$/); + const pathEndIdx = match && match.index || url.length; + const droppedSlashIdx = pathEndIdx - (url[pathEndIdx - 1] === '/' ? 1 : 0); + return url.slice(0, droppedSlashIdx) + url.slice(pathEndIdx); + } } function _stripBaseHref(baseHref: string, url: string): string { diff --git a/packages/common/test/location/location_spec.ts b/packages/common/test/location/location_spec.ts new file mode 100644 index 0000000000..7a110955d7 --- /dev/null +++ b/packages/common/test/location/location_spec.ts @@ -0,0 +1,42 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Location} from '../../src/location/location'; + +export function main() { + const baseUrl = '/base'; + + describe('Location Class', () => { + describe('stripTrailingSlash', () => { + it('should strip single character slash', () => { + const input = '/'; + expect(Location.stripTrailingSlash(input)).toBe(''); + }); + + it('should normalize strip a trailing slash', () => { + const input = baseUrl + '/'; + expect(Location.stripTrailingSlash(input)).toBe(baseUrl); + }); + + it('should ignore query params when stripping a slash', () => { + const input = baseUrl + '/?param=1'; + expect(Location.stripTrailingSlash(input)).toBe(baseUrl + '?param=1'); + }); + + it('should not remove slashes inside query params', () => { + const input = baseUrl + '?test/?=3'; + expect(Location.stripTrailingSlash(input)).toBe(input); + }); + + it('should not remove slashes after a pound sign', () => { + const input = baseUrl + '#test/?=3'; + expect(Location.stripTrailingSlash(input)).toBe(input); + }); + }); + }); +} \ No newline at end of file