Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(requestinterception): fix font loading issue #7060

Merged
merged 8 commits into from May 6, 2021
Merged

fix(requestinterception): fix font loading issue #7060

merged 8 commits into from May 6, 2021

Conversation

Androbin
Copy link
Contributor

@Androbin Androbin commented Apr 6, 2021

Fixes #7038 @starrify

See #6996 (comment) and #6996 (comment) for context

@google-cla google-cla bot added the cla: yes label Apr 6, 2021
@mathiasbynens mathiasbynens requested a review from OrKoN April 6, 2021 05:53
@starrify
Copy link
Contributor

starrify commented Apr 6, 2021

Thanks @Androbin for the updates!

A quick question please: are you sure that the test case you added does trigger the very issue as earlier reported issue in #7038 ? Asking because I recall having the highly similar tests as well and the very test case just won't cause anything wrong.

It shall be easy to confirm, though: Just keep the test case and drop the newly added fixes to see whether the issue is triggered.

Or maybe you could check your fix towards https://github.com/ because this page stably reproduces the issue, at least for me.

I have indeed got some further checks regarding this very issue and have it reported here: https://bugs.chromium.org/p/chromium/issues/detail?id=1196004
In the issue report here I stated the very conditions that I think could trigger this issue, together with several minimal test cases I created.

@Androbin
Copy link
Contributor Author

Androbin commented Apr 6, 2021

I have tested every combination of { without the fix, with the fix } and { https://github.com, minimal example included in PR }

@Androbin
Copy link
Contributor Author

Androbin commented Apr 7, 2021

Turns out that for redirect requests, we receive multiple calls to to _onRequestWillBeSent with the same requestId and the current changeset might lead to _onRequestPaused calling _onRequest with a previous _onRequestWillBeSent event. I'm already working on a solution.

requestId
);

this._requestIdToRequestWillBeSentEvent.set(requestId, event);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In theory, the condition for this line could be stricter:
!requestPausedEvent || (!this._cacheDisabled() && event.type === 'Font')
But we don't know for sure if that would cover all cases.

@OrKoN OrKoN requested a review from jschfflr April 8, 2021 11:08
@OrKoN
Copy link
Collaborator

OrKoN commented Apr 8, 2021

Jan, could you please take a look as well?

@OrKoN
Copy link
Collaborator

OrKoN commented Apr 13, 2021

In general, it looks good to me but let's wait for a review for Jan since he should know more about the request interception.

@jschfflr
Copy link
Contributor

Yes, sure!
This patch looks good to me too from a technical side. But I'm not sure if this is the best way to fix the problem as it seems like this might be better fixed on the chromium side to get a more coherent flow of events.
Do you know about some documentation that specify in which order we can expect the events to arrive?

@Androbin
Copy link
Contributor Author

Androbin commented Apr 14, 2021

The documentation for Fetch.requestPaused suggests that it's supposed to fire after Network.requestWillBeSent.
Experiments show that with the cache disabled, this holds true, but enabled, the order of those events is reversed.
And in the case of fonts, Fetch.requestPaused fires both before AND after Network.requestWillBeSent.
The current code anticipates the order to be reversed but it does not anticipate multiple Fetch.requestPaused events.

@Androbin
Copy link
Contributor Author

There are three commits in this PR: testing, refactoring, fixing
The fixing commit consists of storing the requestWillBeSent event unconditionally and a fix for redirects.
For redirect requests, Chromium sends multiple requestWillBeSent events with the same requestId.
That means if we just check the requestId, we might now pair requestPaused with the wrong one.
A redirect might change either the url, the method or both, so we compare the values for both events.

if (requestPausedEvent) {
const interceptionId = requestPausedEvent.requestId;
this._onRequest(event, interceptionId);
this._requestIdToRequestPausedEvent.delete(requestId);
} else {
this._requestIdToRequestWillBeSentEvent.set(requestId, event);
Copy link
Contributor Author

@Androbin Androbin Apr 14, 2021

Choose a reason for hiding this comment

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

@jschfflr Making this line run unconditionally is the only "workaround" introduced, the rest is just refactoring.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And the value is cleared anyway. I really don't see why we wouldn't do this regardless of Chomium changes.

@Androbin
Copy link
Contributor Author

The real issue is that the user interception code is called twice (once per requestPaused event).
This PR does not attempt to work around that, that's why we still need a fix to land in Chromium.

* There are four possible orders of events:
* A. `_onRequestWillBeSent`
* B. `_onRequestWillBeSent`, `_onRequestPaused`
* C. `_onRequestPaused`, `_onRequestWillBeSent`
Copy link
Collaborator

Choose a reason for hiding this comment

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

when does the C sequence happen? So A is when there is no interception and B is the normal interception flow?

Copy link
Contributor Author

@Androbin Androbin Apr 26, 2021

Choose a reason for hiding this comment

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

Yes, that is correct. The difference between B and C is undocumented.
Seems to depend on whether the cache is enabled and whether the cache is hit or missed: #7038 (comment)

Copy link
Contributor Author

@Androbin Androbin Apr 26, 2021

Choose a reason for hiding this comment

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

This module has always been explicitly anticipating both B and C but it previously failed for D.
D is trivially fixed by preserving the entry in _requestIdToRequestWillBeSentEvent until _onLoadingFinished (and adding a guard clause for redirect requests as they have the same requestId): 5f183e6#r613342144

Copy link
Contributor

@jschfflr jschfflr left a comment

Choose a reason for hiding this comment

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

This change looks good to me from a technical standpoint.
But could you add some documentation around the expected order of events for redirects?

@Androbin
Copy link
Contributor Author

@OrKoN Here's a remark from upstream: https://bugs.chromium.org/p/chromium/issues/detail?id=1196004#c10

There's no guaranteed order between Fetch.requestPaused and Network.requestWillBeSent, these are inherently racy because they come from different processes.

@OrKoN
Copy link
Collaborator

OrKoN commented Apr 29, 2021

@jschfflr Have you looked into this Firefox test failure already?

@jschfflr
Copy link
Contributor

@OrKoN Yes, I'm investigating in #7182

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Request interception with caching (rev 8695759) fails when loading stylesheet-initiated fonts (?)
4 participants