Skip to content

Commit 5c5f7eb

Browse files
fix(redirect): Do not allow onBefore hooks to cause infinite redirect loops
Closes #6
1 parent 8892ecc commit 5c5f7eb

File tree

2 files changed

+25
-7
lines changed

2 files changed

+25
-7
lines changed

src/transition/transition.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,11 @@ export class Transition implements IHookRegistry {
442442
* @returns Returns a new [[Transition]] instance.
443443
*/
444444
redirect(targetState: TargetState): Transition {
445+
let redirects = 1, trans: Transition = this;
446+
while((trans = trans.redirectedFrom()) != null) {
447+
if (++redirects > 20) throw new Error(`Too many consecutive Transition redirects (20+)`);
448+
}
449+
445450
let newOptions = extend({}, this.options(), targetState.options(), { redirectedFrom: this, source: "redirect" });
446451
targetState = new TargetState(targetState.identifier(), targetState.$state(), targetState.params(), newOptions);
447452

@@ -613,11 +618,6 @@ export class Transition implements IHookRegistry {
613618
error() {
614619
let state: State = this.$to();
615620

616-
let redirects = 0, trans: Transition = this;
617-
while((trans = trans.redirectedFrom()) != null) {
618-
if (++redirects > 20) return `Too many Transition redirects (20+)`;
619-
}
620-
621621
if (state.self.abstract)
622622
return `Cannot transition to abstract state '${state.name}'`;
623623
if (!Param.validates(state.parameters(), this.params()))

test/stateServiceSpec.ts

+20-2
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ describe('stateService', function () {
5959
.then(done, done);
6060
}));
6161

62-
it('should error after 20+ redirects', (done) => {
62+
it('should error after 20+ async redirects', (done) => {
6363
let errors = [];
6464
$transitions.onEnter({ entering: "D" }, trans => trans.router.stateService.target('D'));
6565
$transitions.onError({}, trans => { errors.push(trans.error()) });
@@ -68,7 +68,25 @@ describe('stateService', function () {
6868

6969
$state.go("D").catch(err => {
7070
expect(errors.length).toBe(21);
71-
expect(err.message).toContain('Too many Transition redirects');
71+
expect(err.message).toContain('Too many consecutive Transition redirects');
72+
done();
73+
});
74+
});
75+
76+
it('synchronous redirects should not be allowed to cause an infinite redirect loop', (done) => {
77+
let errors = [];
78+
let count = 0;
79+
$transitions.onBefore({ entering: "D" }, trans => {
80+
if (count++ >= 1000) throw new Error(`Doh! 1000 redirects O_o`);
81+
return trans.router.stateService.target('D');
82+
});
83+
$transitions.onError({}, trans => { errors.push(trans.error()) });
84+
85+
$state.defaultErrorHandler(function() {});
86+
87+
$state.go("D").catch(err => {
88+
expect(count).toBe(21);
89+
expect(err.message).toContain('Too many consecutive Transition redirects');
7290
done();
7391
});
7492
});

0 commit comments

Comments
 (0)