Skip to content

Commit 89e99cd

Browse files
authored
fix(params): Bi-directionally en/decode path and search params. (#618)
- fixes urls double and triple encoding some characters when synchronising the state with the current url. - adds a flag on UrlConfig to disable this decoding (for AngularJS which pre-decodes in the $location api) Fixes ui-router/angular#340
1 parent 3d8c4a8 commit 89e99cd

File tree

5 files changed

+159
-130
lines changed

5 files changed

+159
-130
lines changed

src/url/interface.ts

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export interface UrlMatcherCompileConfig {
2121
state?: StateDeclaration;
2222
strict?: boolean;
2323
caseInsensitive?: boolean;
24+
// If params are pre-decoded, set to false to avoid double decoding
25+
decodeParams?: boolean;
2426
}
2527

2628
/** @deprecated use [[UrlConfig]] */

src/url/urlConfig.ts

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { isDefined, isString } from '../common';
1818
*/
1919
export class UrlConfig implements Disposable {
2020
/** @internal */ paramTypes = new ParamTypes();
21+
/** @internal */ _decodeParams = true;
2122
/** @internal */ _isCaseInsensitive = false;
2223
/** @internal */ _isStrictMode = true;
2324
/** @internal */ _defaultSquashPolicy: boolean | string = false;

src/url/urlMatcher.ts

+20-5
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ const defaultConfig: UrlMatcherCompileConfig = {
5353
state: { params: {} },
5454
strict: true,
5555
caseInsensitive: true,
56+
decodeParams: true,
5657
};
5758

5859
/**
@@ -338,6 +339,18 @@ export class UrlMatcher {
338339
return this.pattern;
339340
}
340341

342+
private _getDecodedParamValue(value: any, param: Param): any {
343+
if (isDefined(value)) {
344+
if (this.config.decodeParams && !param.type.raw && !isArray(value)) {
345+
value = decodeURIComponent(value);
346+
}
347+
348+
value = param.type.decode(value);
349+
}
350+
351+
return param.value(value);
352+
}
353+
341354
/**
342355
* Tests the specified url/path against this matcher.
343356
*
@@ -406,17 +419,19 @@ export class UrlMatcher {
406419
for (let j = 0; j < param.replace.length; j++) {
407420
if (param.replace[j].from === value) value = param.replace[j].to;
408421
}
422+
409423
if (value && param.array === true) value = decodePathArray(value);
410-
if (isDefined(value)) value = param.type.decode(value);
411-
values[param.id] = param.value(value);
424+
425+
values[param.id] = this._getDecodedParamValue(value, param);
412426
}
413-
searchParams.forEach((param) => {
427+
searchParams.forEach((param: Param) => {
414428
let value = search[param.id];
429+
415430
for (let j = 0; j < param.replace.length; j++) {
416431
if (param.replace[j].from === value) value = param.replace[j].to;
417432
}
418-
if (isDefined(value)) value = param.type.decode(value);
419-
values[param.id] = param.value(value);
433+
434+
values[param.id] = this._getDecodedParamValue(value, param);
420435
});
421436

422437
if (hash) values['#'] = hash;

src/url/urlMatcherFactory.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,12 @@ export class ParamFactory {
3030
export class UrlMatcherFactory {
3131
/** Creates a new [[Param]] for a given location (DefType) */
3232
paramFactory = new ParamFactory(this.router);
33+
// TODO: Check if removal of this will break anything, then remove these
34+
UrlMatcher: typeof UrlMatcher = UrlMatcher;
35+
Param: typeof Param = Param;
3336

3437
// TODO: move implementations to UrlConfig (urlService.config)
35-
constructor(/** @internal */ private router: UIRouter) {
36-
extend(this, { UrlMatcher, Param });
37-
}
38+
constructor(/** @internal */ private router: UIRouter) {}
3839

3940
/**
4041
* Creates a [[UrlMatcher]] for the specified pattern.
@@ -48,7 +49,11 @@ export class UrlMatcherFactory {
4849
// backward-compatible support for config.params -> config.state.params
4950
const params = config && !config.state && (config as any).params;
5051
config = params ? { state: { params }, ...config } : config;
51-
const globalConfig = { strict: urlConfig._isStrictMode, caseInsensitive: urlConfig._isCaseInsensitive };
52+
const globalConfig: UrlMatcherCompileConfig = {
53+
strict: urlConfig._isStrictMode,
54+
caseInsensitive: urlConfig._isCaseInsensitive,
55+
decodeParams: urlConfig._decodeParams,
56+
};
5257
return new UrlMatcher(pattern, urlConfig.paramTypes, this.paramFactory, extend(globalConfig, config));
5358
}
5459

0 commit comments

Comments
 (0)