Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

fix(ngRoute): Don't deep-copy the route object, just plain copy it instead. #14699

Closed
wants to merge 2 commits into from

Conversation

rjamet
Copy link
Contributor

@rjamet rjamet commented May 31, 2016

What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)
Bug fix for #14478

What is the current behavior? (You can also link to an open issue here)
Angular runs angular.copy on its routes, which isn't necessary and breaks some things

What is the new behavior (if this is a feature change)?
No more angular.copy on these, which appears to not break anything.

Does this PR introduce a breaking change?
No, it shouldn't.

Please check if the PR fulfills these requirements

That's Angular's guts, the previous behavior wasn't documented, and the new one seems obvious enough.

Other information:

This seems to fix #14478. No need for a deep copy, just a plain one is enough as ngRoute does not modify the fields in the route object.

I'm not that familiar with ngRoute, and the fix seems too easy: if something's wrong, I'll be glad to add tests for that :) As mentionned in the issue, #8181 and #9731 seems to be relevant, but this PR shouldn't reopen the issues.

This seems to fix angular#14478. No need for a deep copy, just a plain one
is enough as ngRoute does not modify the fields in the route object.
@gkalpak
Copy link
Member

gkalpak commented May 31, 2016

The question is why was the original extend used. We need to find out, to make sure this change isn't breaking anything.

@rjamet
Copy link
Contributor Author

rjamet commented May 31, 2016

The commit introducing the code is this: b477058, where they switched extending an object with route (without the inherited components of route) to extending routeCopy. Their test still pass, and my way will keep the original prototype chain of the route object.

@gkalpak
Copy link
Member

gkalpak commented May 31, 2016

I'm talking about the commit that introduced the previous implementation, using extend(). I haven't looked for it yet, though.

@Narretz
Copy link
Contributor

Narretz commented Jun 1, 2016

In it's current form, it seems to come from here: 15ecc6f

Note the comment in the changed version that talks about merging routes

@gkalpak
Copy link
Member

gkalpak commented Jun 3, 2016

It seems it has been using .extend since forever (70e401e), but for no apparent reason.
In any case, this is a breaking change - should be documented as such.

I agree that taking into account inherited properties is a more common usecase than extending a route, but ideally we should provide a way to support both.

@@ -160,7 +160,7 @@ function $RouteProvider() {
*/
this.when = function(path, route) {
//copy original route object to preserve params inherited from proto chain
var routeCopy = angular.copy(route);
var routeCopy = route;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that the intention of the copying the object was to avoid the possibility of the user mutating the passed in object after the router partially processed it. This could get the router into an unknown state.

By copying we know for sure that the state we read has not changed.

The problem this causes is that if the templateUrl is set to be a TrustedResourceUrl instance, the instance is not copied correctly and the templateUrl fails to be properly unwrapped by sce later.

Since both template and templateUrl properties are both (wrapped) immutable strings, we could use shallowCopy instead to protect the router from internal state corruption while not corrupting the sce wrappers.

Another option is to teach angular.copy how to copy sce wrappers safely, but given that there could be custom implementations of these wrappers (e.g. at google we have our own), making the the mechanism generic might be tricky.

shallowCopy seems to give us all of the benefits with little down-sides, so I'd prefer that one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the intention of using copy instead of extend was to preserve inherited properties (talk about using a sledgehammer to crack a nut 😃). shallowCopy (which we need to copy over to angular-route btw) would also shallow-copy inherited properties, so we are covered.

gkalpak added a commit to gkalpak/angular.js that referenced this pull request Jun 9, 2016
Deep-copying route definition objects can break specific custom implementations of `$sce` (used to
trust a `templateUrl` as RESOURCE_URL. The purpose of copying route definition objects was to guard
against the user's modifying the route definition object after route registration, while still
capturing inherited properties.
As suggested by @IgorMinar in angular#14699 (comment),
we can achieve both _and_ support custom `$sce` implementations, by shallow-copying instead.

This is an alternative implementation for angular#14699, which avoids the breaking change.

Fixes 14478
Closes 14699
gkalpak added a commit to gkalpak/angular.js that referenced this pull request Jun 9, 2016
Deep-copying route definition objects can break specific custom implementations of `$sce` (used to
trust a `templateUrl` as RESOURCE_URL). The purpose of copying route definition objects was to guard
against the user's modifying the route definition object after route registration, while still
capturing inherited properties.
As suggested by @IgorMinar in angular#14699 (comment),
we can achieve both _and_ support custom `$sce` implementations, by shallow-copying instead.

This is an alternative implementation for angular#14699, which avoids the breaking change.

Fixes 14478
Closes 14699
@gkalpak gkalpak closed this in 53ab8bc Jun 10, 2016
gkalpak added a commit that referenced this pull request Jun 10, 2016
Deep-copying route definition objects can break specific custom implementations of `$sce` (used to
trust a `templateUrl` as RESOURCE_URL). The purpose of copying route definition objects was to guard
against the user's modifying the route definition object after route registration, while still
capturing inherited properties.
As suggested by @IgorMinar in #14699 (comment),
we can achieve both _and_ support custom `$sce` implementations, by shallow-copying instead.

This is an alternative implementation for #14699, which avoids the breaking change.

Fixes #14478
Closes #14699

Closes #14750
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

$routeProvider deep-copies its route objects before using them, which is probably not necessary
5 participants