Skip to content

Commit

Permalink
fix(params): Bi-directionally en/decode path and search params. (#618)
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
wawyed committed Jul 17, 2020
1 parent 3d8c4a8 commit 89e99cd
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 130 deletions.
2 changes: 2 additions & 0 deletions src/url/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export interface UrlMatcherCompileConfig {
state?: StateDeclaration;
strict?: boolean;
caseInsensitive?: boolean;
// If params are pre-decoded, set to false to avoid double decoding
decodeParams?: boolean;
}

/** @deprecated use [[UrlConfig]] */
Expand Down
1 change: 1 addition & 0 deletions src/url/urlConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { isDefined, isString } from '../common';
*/
export class UrlConfig implements Disposable {
/** @internal */ paramTypes = new ParamTypes();
/** @internal */ _decodeParams = true;
/** @internal */ _isCaseInsensitive = false;
/** @internal */ _isStrictMode = true;
/** @internal */ _defaultSquashPolicy: boolean | string = false;
Expand Down
25 changes: 20 additions & 5 deletions src/url/urlMatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const defaultConfig: UrlMatcherCompileConfig = {
state: { params: {} },
strict: true,
caseInsensitive: true,
decodeParams: true,
};

/**
Expand Down Expand Up @@ -338,6 +339,18 @@ export class UrlMatcher {
return this.pattern;
}

private _getDecodedParamValue(value: any, param: Param): any {
if (isDefined(value)) {
if (this.config.decodeParams && !param.type.raw && !isArray(value)) {
value = decodeURIComponent(value);
}

value = param.type.decode(value);
}

return param.value(value);
}

/**
* Tests the specified url/path against this matcher.
*
Expand Down Expand Up @@ -406,17 +419,19 @@ export class UrlMatcher {
for (let j = 0; j < param.replace.length; j++) {
if (param.replace[j].from === value) value = param.replace[j].to;
}

if (value && param.array === true) value = decodePathArray(value);
if (isDefined(value)) value = param.type.decode(value);
values[param.id] = param.value(value);

values[param.id] = this._getDecodedParamValue(value, param);
}
searchParams.forEach((param) => {
searchParams.forEach((param: Param) => {
let value = search[param.id];

for (let j = 0; j < param.replace.length; j++) {
if (param.replace[j].from === value) value = param.replace[j].to;
}
if (isDefined(value)) value = param.type.decode(value);
values[param.id] = param.value(value);

values[param.id] = this._getDecodedParamValue(value, param);
});

if (hash) values['#'] = hash;
Expand Down
13 changes: 9 additions & 4 deletions src/url/urlMatcherFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ export class ParamFactory {
export class UrlMatcherFactory {
/** Creates a new [[Param]] for a given location (DefType) */
paramFactory = new ParamFactory(this.router);
// TODO: Check if removal of this will break anything, then remove these
UrlMatcher: typeof UrlMatcher = UrlMatcher;
Param: typeof Param = Param;

// TODO: move implementations to UrlConfig (urlService.config)
constructor(/** @internal */ private router: UIRouter) {
extend(this, { UrlMatcher, Param });
}
constructor(/** @internal */ private router: UIRouter) {}

/**
* Creates a [[UrlMatcher]] for the specified pattern.
Expand All @@ -48,7 +49,11 @@ export class UrlMatcherFactory {
// backward-compatible support for config.params -> config.state.params
const params = config && !config.state && (config as any).params;
config = params ? { state: { params }, ...config } : config;
const globalConfig = { strict: urlConfig._isStrictMode, caseInsensitive: urlConfig._isCaseInsensitive };
const globalConfig: UrlMatcherCompileConfig = {
strict: urlConfig._isStrictMode,
caseInsensitive: urlConfig._isCaseInsensitive,
decodeParams: urlConfig._decodeParams,
};
return new UrlMatcher(pattern, urlConfig.paramTypes, this.paramFactory, extend(globalConfig, config));
}

Expand Down
Loading

0 comments on commit 89e99cd

Please sign in to comment.