-
Notifications
You must be signed in to change notification settings - Fork 27.4k
fix($browser): normalize inputted URLs #16606
Conversation
So there's good news and bad news. 👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there. 😕 The bad news is that it appears that one or more commits were authored or co-authored by someone other than the pull request submitter. We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that here in the pull request. Note to project maintainer: This is a terminal state, meaning the |
So there's good news and bad news. 👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there. 😕 The bad news is that it appears that one or more commits were authored or co-authored by someone other than the pull request submitter. We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that here in the pull request. Note to project maintainer: This is a terminal state, meaning the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few minor things, but technically good to go
src/ng/browser.js
Outdated
@@ -131,6 +131,15 @@ function Browser(window, document, $log, $sniffer) { | |||
// setter | |||
if (url) { | |||
var sameState = lastHistoryState === state; | |||
var hasTrailingSlash = url[url.length - 1] === '/'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regex would look nicer and could be re-used below
Updated. Sorry I squashed/rebased everything so it might be hard to see the changes. I added a commit (21263c9) refactoring the mock Also, as @petebacondarwin pointed out, none of the tests in the first commit actually fail in master right now. So I'm tempted to just drop them. I swear I saw these fail at some point though. @dmartres can you confirm your tests (from #16098) did fail at some point? Any idea why they are not be failing? |
test/ng/browserSpecs.js
Outdated
browser.onUrlChange(callback); | ||
browser.url('http://server/abc?q=\''); | ||
|
||
browser.$$checkUrlChange(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we are testing a private API here, I feel like maybe we should test this in $location spec instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To avoid invoking the private API from tests? It really is testing logic only in browser.js though :/
src/ng/browser.js
Outdated
// Normalize the inputted URL ... | ||
url = urlResolve(url).href; | ||
|
||
// ... but keep the (lack of) trailing '/' consistent |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible that there was a slash initially and urlResolve
stripped it off?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess if a browser "normalizes" to have no slash at the end then yes, and I'd vote to handle that just in case. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can't hurt. Let's do it 😃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although now I'm wondering if trimming this is actually a problem 🤔 (originally I didn't trim anything, but we added this to avoid adding /
to many tests).
The whole point of this is to make the persisted lastBrowserUrl
normalized the same way document.location.href
is normalized. So the comparison below and maybe also the comparison in $location
would not fail due to the normalized value being different then the non-normalized lastBrowserUrl
. By removing this /
we are making lastBrowserUrl
different then the normalized value...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But we are normalizing all the time, so it shouldn't matter? Or if it does, we should be able to add a test that shows this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if we strip the slash here and assign to lastBrowserUrl
, then later we compare to $browser.url()
(which is location.href
, which has a slash), then maybe it will detect changes when it shouldn't?
browser.js#L148
browser.js#L231
I won't change anything unless I can prove it with a test though...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we already have a test that proves it actually (but I'll try to add more).
Notice when I updated the MockWindow
to use aElement.href
to normalize the window.location.href
mock... one test also had it's input changed otherwise it failed. I think the input shouldn't have to change and the fact that it failed shows what I'm talking about here... if we are comparing lastBrowserURL
to $browser.url()
then they must be normalized the same way. $browser.url()
is location.href
, so lastBrowserURL
should be normalized just like location.href
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds reasonable. So we have to remove the slash recreation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. I think we must keep the browser-normalized URL, slash or not.
See the new tests in the latest commit, 4 fail with the slash-removal logic (and they are run twice, so 8 failures total). Without the urlResolve
there are 14 failures.
test/ng/browserSpecs.js
Outdated
@@ -567,6 +568,30 @@ describe('browser', function() { | |||
expect(replaceState).not.toHaveBeenCalled(); | |||
expect(locationReplace).not.toHaveBeenCalled(); | |||
}); | |||
|
|||
it('should not do pushState with a URL only different in encoding', function() { | |||
//A URL from something such as window.location.href |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space after //
.
c117089
to
768105f
Compare
CLAs look good, thanks! |
1 similar comment
CLAs look good, thanks! |
Tests are currently failing in IE because IE is not normalizing the URLs like other browsers. Most likely the same IE bug that his block is solving: https://github.com/angular/angular.js/blob/v1.7.4/src/ng/urlUtils.js#L65-L71 |
Some tests are failing in IE, and I've realized those are failing for the same original issue #16098 was trying to fix. Also the reason I thought none of the tests from #16098 were "working" (failing before the fix) is because they probably only failed in IE and I wasn't trying IE... So this PR doesn't fully fix the bug. It does for some cases of URLs being normalized, but IE doesn't normalize For reference RFC1738 says: "only alphanumerics, the special characters "$-_.+!*'(),", and reserved characters used for their reserved purposes may be used unencoded within a URL" and it seems like IE doesn't respect that. Should we add specific handling for those chars the RFC lists? Or just respect what |
Tough one 😁 |
I think this could get ugly :| Chrome:
IE:
Firefox:
Everything else in I'm going to sleep on it :| |
URL handling is hard |
6188805
to
98b5b31
Compare
I've updated this to (I think) fix it better, although that makes the change bigger and potentially more questionable about merging vs wontfix. This still adds URL normalizing to There's a whole section in RFC3986 talking about normalization/comparison and defines the ABNF for the path, query and fragment. Those are the 3 parts of the URL this PR tries to normalize. (Note that this RFC3986 replaces the one I was previously referencing) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks very interesting. Can we get Travis green?
- Some linting issues https://travis-ci.org/angular/angular.js/jobs/441985047
- Lots of failed unit tests that look legit: https://travis-ci.org/angular/angular.js/jobs/441985048
- Possible failed e2e tests
But Chrome and FF did just fine :( |
Most of the failures were because all browsers except Chrome+FF add the Might require some manually trimming of |
For reference: here's a commit which attempts to normalize encoding in the pathname/search/hash: jbedard@5d33cee While this normalizes a lot of things it also introduces some ugliness and inconsistencies across browsers (appending blank |
2b6e6fa
to
e9e18f5
Compare
I've changed this back to the basic fix, just letting the browser do the normalizing with The added tests show some examples where invoking I think this is ready... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good but it'd be great if you could add more details in the final commit message...
@mgol the thing is... I'm not 100% sure what those cases are lol I think it would be: So I think if a user is at a url, then clicks a link to the same url with different encoding, it will no longer do |
Calls to `$browser.url` now normalize the inputted URL ensuring multiple calls only differing in formatting do not force a browser `pushState`. Normalization is done the same as the browser location URL and may differ per browser and may be changed by browsers. Today no browsers fully normalize URLs so this does not fix all instances of this issue. See angular#16100 Closes angular#16606
Calls to `$browser.url` now normalize the inputted URL ensuring multiple calls only differing in formatting do not force a browser `pushState`. Normalization is done the same as the browser location URL and may differ per browser and may be changed by browsers. Today no browsers fully normalize URLs so this does not fix all instances of this issue. See #16100 Closes #16606
What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)
fix
What is the current behavior? (You can also link to an open issue here)
What is the new behavior (if this is a feature change)?
Does this PR introduce a breaking change?
Please check if the PR fulfills these requirements
Other information: