fix(router): add ability to recover from malformed url (#23283)
Fixes #21468 PR Close #23283
This commit is contained in:
@ -160,6 +160,11 @@ function defaultErrorHandler(error: any): any {
|
||||
throw error;
|
||||
}
|
||||
|
||||
function defaultMalformedUriErrorHandler(
|
||||
error: URIError, urlSerializer: UrlSerializer, url: string): UrlTree {
|
||||
return urlSerializer.parse('/');
|
||||
}
|
||||
|
||||
type NavStreamValue =
|
||||
boolean | {appliedUrl: UrlTree, snapshot: RouterStateSnapshot, shouldActivate?: boolean};
|
||||
|
||||
@ -230,7 +235,14 @@ export class Router {
|
||||
*/
|
||||
errorHandler: ErrorHandler = defaultErrorHandler;
|
||||
|
||||
|
||||
/**
|
||||
* Malformed uri error handler is invoked when `Router.parseUrl(url)` throws an
|
||||
* error due to containing an invalid character. The most common case would be a `%` sign
|
||||
* that's not encoded and is not part of a percent encoded sequence.
|
||||
*/
|
||||
malformedUriErrorHandler:
|
||||
(error: URIError, urlSerializer: UrlSerializer,
|
||||
url: string) => UrlTree = defaultMalformedUriErrorHandler;
|
||||
|
||||
/**
|
||||
* Indicates if at least one navigation happened.
|
||||
@ -325,7 +337,7 @@ export class Router {
|
||||
// run into ngZone
|
||||
if (!this.locationSubscription) {
|
||||
this.locationSubscription = <any>this.location.subscribe((change: any) => {
|
||||
const rawUrlTree = this.urlSerializer.parse(change['url']);
|
||||
let rawUrlTree = this.parseUrl(change['url']);
|
||||
const source: NavigationTrigger = change['type'] === 'popstate' ? 'popstate' : 'hashchange';
|
||||
const state = change.state && change.state.navigationId ?
|
||||
{navigationId: change.state.navigationId} :
|
||||
@ -503,7 +515,15 @@ export class Router {
|
||||
serializeUrl(url: UrlTree): string { return this.urlSerializer.serialize(url); }
|
||||
|
||||
/** Parses a string into a `UrlTree` */
|
||||
parseUrl(url: string): UrlTree { return this.urlSerializer.parse(url); }
|
||||
parseUrl(url: string): UrlTree {
|
||||
let urlTree: UrlTree;
|
||||
try {
|
||||
urlTree = this.urlSerializer.parse(url);
|
||||
} catch (e) {
|
||||
urlTree = this.malformedUriErrorHandler(e, this.urlSerializer, url);
|
||||
}
|
||||
return urlTree;
|
||||
}
|
||||
|
||||
/** Returns whether the url is activated */
|
||||
isActive(url: string|UrlTree, exact: boolean): boolean {
|
||||
@ -511,7 +531,7 @@ export class Router {
|
||||
return containsTree(this.currentUrlTree, url, exact);
|
||||
}
|
||||
|
||||
const urlTree = this.urlSerializer.parse(url);
|
||||
const urlTree = this.parseUrl(url);
|
||||
return containsTree(this.currentUrlTree, urlTree, exact);
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ import {NoPreloading, PreloadAllModules, PreloadingStrategy, RouterPreloader} fr
|
||||
import {RouterScroller} from './router_scroller';
|
||||
import {ActivatedRoute} from './router_state';
|
||||
import {UrlHandlingStrategy} from './url_handling_strategy';
|
||||
import {DefaultUrlSerializer, UrlSerializer} from './url_tree';
|
||||
import {DefaultUrlSerializer, UrlSerializer, UrlTree} from './url_tree';
|
||||
import {flatten} from './utils/collection';
|
||||
|
||||
|
||||
@ -393,6 +393,18 @@ export interface ExtraOptions {
|
||||
* - `'always'`, enables unconditional inheritance of parent params.
|
||||
*/
|
||||
paramsInheritanceStrategy?: 'emptyOnly'|'always';
|
||||
|
||||
/**
|
||||
* A custom malformed uri error handler function. This handler is invoked when encodedURI contains
|
||||
* invalid character sequences. The default implementation is to redirect to the root url dropping
|
||||
* any path or param info. This function passes three parameters:
|
||||
*
|
||||
* - `'URIError'` - Error thrown when parsing a bad URL
|
||||
* - `'UrlSerializer'` - UrlSerializer that’s configured with the router.
|
||||
* - `'url'` - The malformed URL that caused the URIError
|
||||
* */
|
||||
malformedUriErrorHandler?:
|
||||
(error: URIError, urlSerializer: UrlSerializer, url: string) => UrlTree;
|
||||
}
|
||||
|
||||
export function setupRouter(
|
||||
@ -415,6 +427,10 @@ export function setupRouter(
|
||||
router.errorHandler = opts.errorHandler;
|
||||
}
|
||||
|
||||
if (opts.malformedUriErrorHandler) {
|
||||
router.malformedUriErrorHandler = opts.malformedUriErrorHandler;
|
||||
}
|
||||
|
||||
if (opts.enableTracing) {
|
||||
const dom = getDOM();
|
||||
router.events.subscribe((e: RouterEvent) => {
|
||||
|
Reference in New Issue
Block a user