fix(router): encode URLs the same way AngularJS did (closer to spec) (#17890)
fixes #16067
This commit is contained in:
parent
c69fff15c9
commit
ae27af7399
@ -325,8 +325,24 @@ function serializeSegment(segment: UrlSegmentGroup, root: boolean): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is intended for encoding *key* or *value* parts of query component. We need a custom
|
||||||
|
* method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
|
||||||
|
* encoded per http://tools.ietf.org/html/rfc3986:
|
||||||
|
* query = *( pchar / "/" / "?" )
|
||||||
|
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
||||||
|
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||||
|
* pct-encoded = "%" HEXDIG HEXDIG
|
||||||
|
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||||
|
* / "*" / "+" / "," / ";" / "="
|
||||||
|
*/
|
||||||
export function encode(s: string): string {
|
export function encode(s: string): string {
|
||||||
return encodeURIComponent(s);
|
return encodeURIComponent(s)
|
||||||
|
.replace(/%40/g, '@')
|
||||||
|
.replace(/%3A/gi, ':')
|
||||||
|
.replace(/%24/g, '$')
|
||||||
|
.replace(/%2C/gi, ',')
|
||||||
|
.replace(/%3B/gi, ';');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function decode(s: string): string {
|
export function decode(s: string): string {
|
||||||
|
@ -219,6 +219,22 @@ describe('url serializer', () => {
|
|||||||
expect(url.serialize(tree)).toEqual(u);
|
expect(url.serialize(tree)).toEqual(u);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should encode query params leaving sub-delimiters intact', () => {
|
||||||
|
const percentChars = '/?#[]&+= ';
|
||||||
|
const percentCharsEncoded = '%2F%3F%23%5B%5D%26%2B%3D%20';
|
||||||
|
const intactChars = '!$\'()*,;:';
|
||||||
|
const params = percentChars + intactChars;
|
||||||
|
const paramsEncoded = percentCharsEncoded + intactChars;
|
||||||
|
const mixedCaseString = 'sTrInG';
|
||||||
|
|
||||||
|
expect(percentCharsEncoded).toEqual(encode(percentChars));
|
||||||
|
expect(intactChars).toEqual(encode(intactChars));
|
||||||
|
// Verify it replaces repeated characters correctly
|
||||||
|
expect(paramsEncoded + paramsEncoded).toEqual(encode(params + params));
|
||||||
|
// Verify it doesn't change the case of alpha characters
|
||||||
|
expect(mixedCaseString + paramsEncoded).toEqual(encode(mixedCaseString + params));
|
||||||
|
});
|
||||||
|
|
||||||
it('should encode/decode fragment', () => {
|
it('should encode/decode fragment', () => {
|
||||||
const u = `/one#${encodeURI("one two=three four")}`;
|
const u = `/one#${encodeURI("one two=three four")}`;
|
||||||
const tree = url.parse(u);
|
const tree = url.parse(u);
|
||||||
|
@ -71,6 +71,6 @@ export function setUpLocationSync(ngUpgrade: UpgradeModule) {
|
|||||||
ngUpgrade.$injector.get('$rootScope')
|
ngUpgrade.$injector.get('$rootScope')
|
||||||
.$on('$locationChangeStart', (_: any, next: string, __: string) => {
|
.$on('$locationChangeStart', (_: any, next: string, __: string) => {
|
||||||
url.href = next;
|
url.href = next;
|
||||||
router.navigateByUrl(url.pathname + url.search);
|
router.navigateByUrl(url.pathname + url.search + url.hash);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user