-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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
core: remove dependency on devtools-frontend NetworkRequest #5451
Conversation
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.
title speaks for itself
is it more removing dependency on devtools-frontend to create network records?
_isLinkPreload?: boolean; | ||
initiatorRequest(): NetworkRequest | null; | ||
redirects?: NetworkRequest[]; | ||
} |
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.
shouldn't we be able to get rid of this and use the class definition?
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.
yes, that jump seemed a bit bigger in the same go since I'm using this to typecheck the other class, but we definitely will be able to
@@ -317,5 +317,7 @@ module.exports = (function() { | |||
// Restore setImmediate, see comment at top. | |||
global.setImmediate = _setImmediate; | |||
|
|||
// TODO(phulce): replace client requires to not need this | |||
WebInspector.resourceTypes = require('../../third-party/devtools/ResourceType').TYPES; |
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.
can more be removed from this file?
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.
eventually yes!
er, yes! depends on what we're calling a network record, I guess that's somewhat ambiguous |
@@ -1,11 +1,11 @@ | |||
{ | |||
"33097.1:redirected.0": { |
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.
open question if we want to match exactly the old policy 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.
i dun care. this wfm.
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.
can we remove some of the requires from lib/web-inspector now?
@@ -165,6 +166,7 @@ class UnusedBytes extends Audit { | |||
const networkNode = /** @type {NetworkNode} */ (node); | |||
const originalTransferSize = originalTransferSizes.get(networkNode.record.requestId); | |||
if (originalTransferSize === undefined) return; | |||
networkNode.record.transferSize = originalTransferSize; | |||
networkNode.record._transferSize = originalTransferSize; |
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.
should we just use one of these? this PR is switching to use the other already.
Also happy to fix the _prop
use in a followup to minimize the diff.
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 eliminated _transferSize
, the dance was necessary for transferSize since the weird way the getter interacts with our simulation but the rest will be followup 👍
@@ -90,7 +91,7 @@ class UsesRelPreconnectAudit extends Audit { | |||
// filter out all resources where timing info was invalid | |||
!UsesRelPreconnectAudit.hasValidTiming(record) || | |||
// filter out all resources that are loaded by the document | |||
record.initiatorRequest() === mainResource || | |||
record._initiator.url === mainResource.url || |
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.
these aren't totally equivalent, fwiw. but the difference may not matter. And I suppose devtools was making this assumption previously. :p
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 was kinda shocked that the whole initiatorRequest logic is literally just first one with matching URL and manager 😮
@@ -34,6 +38,10 @@ class NetworkRecorder extends EventEmitter { | |||
); | |||
} | |||
|
|||
getRecords() { | |||
return this._records.slice(); |
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.
Array.from() ?
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.
haha, man between you and dgozman I'm gonna lose myself! 😆
done
this._records = []; | ||
/** @type {Map<string, NetworkRequest>} */ | ||
this._recordsById = new Map(); | ||
|
||
this.networkManager = NetworkManager.createWithFakeTarget(); |
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.
do we still need this around? followup?
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.
that one's totally safe to go right now actually 👍
recordsByURL.set(record.url, record); | ||
} | ||
|
||
// set the initiator and redirects array |
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.
at first glance, it seems odd that this happens only when we're hydrating the records from logs. what about when records are created via this._networkStatusMonitor.dispatch(event);
in driver?
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 it's a bit weird, AFAICT we actually only ever use the ones created by the recordsFromLogs, the ones created incrementally are just for the status notifications
const networkRecords = NetworkRecorder.recordsFromLogs(devtoolsLog); |
(and obvs the computed artifact uses this)
long-term though I hope to eliminate the initiatorRequest logic here entirely and move it to the page-dependency-graph since it's just CRC-based ones that need it right now
redirects can also move to direct usage of source/destination which I think becomes more explicit and clear
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 there a way to do this incrementally as (presumably) NetworkManager or whatever does? If the same thing is available in the page dependency graph I guess that's fine too, but at that point do we need NetworkRecords...
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 really, really want to nix these entirely so network request can be trivially serializable. Because of that, I don't really want to do unnecessary work to make them nice only to remove them
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 it's a bit weird, AFAICT we actually only ever use the ones created by the recordsFromLogs, the ones created incrementally are just for the status notifications
ha, I think it was in anticipation of exactly this sort of situation. Since audits can only access network records created by recordsFromLogs(devtoolsLogs)
, we wanted to make sure gatherers also saw exactly the same thing (in afterPass()
) and so switched everything to using it.
So this impl and then migration from it sounds good. Nothing should be able to observe the difference since driver never actually inspects the records while listening to the quiet events
/** | ||
* @param {LH.Crdp.Network.ResourceTiming} timing | ||
*/ | ||
_recomputeTimesWithResourceTiming(timing) { |
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.
add a comment referencing SDK.NetworkRequest.timing
setter and link to https://github.com/ChromeDevTools/devtools-frontend/blob/56a99365197\/front_end/sdk/NetworkRequest.js#L485-L502
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.
done
@@ -1,11 +1,11 @@ | |||
{ | |||
"33097.1:redirected.0": { |
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 dun care. this wfm.
case 'Network.loadingFailed': return this.onLoadingFailed(event.params); | ||
case 'Network.resourceChangedPriority': return this.onResourceChangedPriority(event.params); | ||
default: return; | ||
case 'Network.requestWillBeSent': |
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.
revert the ws change
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.
done
* @param {LH.Crdp.Network.Headers} headersMap | ||
* @return {Array<LH.WebInspector.HeaderValue>} | ||
*/ | ||
static _headersMapToHeadersArray(headersMap) { |
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.
headersDict or headersObj or headersHash seem fine..
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.
done
static _headersMapToHeadersArray(headersMap) { | ||
const result = []; | ||
for (const name of Object.keys(headersMap)) { | ||
const values = headersMap[name].split('\n'); |
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.
which method in sdk.networkrequest is this disguised as? _computeHeaderValue
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.
Not even disguised verbatim s/in/of/ ;)
https://github.com/ChromeDevTools/devtools-frontend/blob/3415ee28e86a3f4bcc2e15b652d22069938df3a6/front_end/sdk/NetworkManager.js#L285-L297
added a comment
Alright I think I'm comfortable taking this out of WIP, tests look good, Paul's initial feedback addressed, added some better coverage around the redirect cases I'm still going to put this through the lantern wringer before being 100% cool to merge 👍 |
so more fun discoveries as part of this, mixed-content has been broken for some time :) #5127 removed the URL gatherer, so the mixed content config tried to treat the on the plus side it seems that chrome changes to interception also broke it (it seems to think example.com is not upgradeable?) so we didn't break anything very useful? 🤷♀️ |
lol we really needed an integration test on that one... |
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.
Some initial comments. This seems pretty nice, and considering how long it's been since we've updated our frontend and it still (mostly) works, I'm not too concerned about maintaining our own version :)
@@ -0,0 +1,326 @@ | |||
/* |
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.
should add a LICENSE
file (maybe this one?) in devtools/
as well
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.
sure done
@@ -96,8 +93,11 @@ class NetworkRecorder extends EventEmitter { | |||
* @return {boolean} | |||
*/ | |||
static _isQUICAndFinished(record) { | |||
const isQUIC = record._responseHeaders && record._responseHeaders | |||
.some(header => header.name.toLowerCase() === 'alt-svc' && /quic/.test(header.value)); | |||
const isQUIC = |
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.
revert?
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.
done
data.timestamp, data.wallTime, data.initiator, data.redirectResponse, | ||
data.type); | ||
const originalRequest = this._findRealRequest(data.requestId); | ||
if (originalRequest) { |
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.
a comment on what this case is would be 👍👍
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.
done
return; | ||
} | ||
|
||
const request = new NetworkRequest(); |
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.
maybe move this case to the early return as it's so much simpler/shorter?
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.
done
@@ -270,18 +294,66 @@ class NetworkRecorder extends EventEmitter { | |||
} | |||
} | |||
|
|||
/** | |||
* @param {string} requestId |
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.
comment on what a "real" request is?
For my own confusion, the IDs of a chain of redirected requests are all the same? Hence the redirectDestination
chain traversal? And the assumption is that if there's more data for a request it can only be the last in the redirect chain because the rest are finished?
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.
For my own confusion, the IDs of a chain of redirected requests are all the same?
Yup
And the assumption is that if there's more data for a request it can only be the last in the redirect chain because the rest are finished?
Yup, after another requestWillBeSent
is issued signaling a redirect, that is the final message of the original request and the rest are about the redirected request.
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.
added a comment basically saying this 👍
recordsByURL.set(record.url, record); | ||
} | ||
|
||
// set the initiator and redirects array |
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 there a way to do this incrementally as (presumably) NetworkManager or whatever does? If the same thing is available in the page dependency graph I guess that's fine too, but at that point do we need NetworkRecords...
@@ -100,67 +100,13 @@ module.exports = (function() { | |||
return this._moduleSettings[settingName]; | |||
}; | |||
|
|||
// Enum from chromium//src/third_party/WebKit/Source/core/loader/MixedContentChecker.h | |||
global.NetworkAgent = { |
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.
🎉 🎈 🎉
/** @type {number} */ | ||
this._responseReceivedTime = -1; | ||
|
||
this.transferSize = 0; |
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.
if you just went with this._transferSize
I feel like this PR would shrink by 30%, but presumable there was a reason :)
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.
well transferSize is the only one we have to standardize in the middle of this PR to get everything to work thanks to the way that the old network requests worked, since we want to end up on transferSize
in the end, makes more sense to just go straight to it :)
@brendankenny would you be able to give some post-initial thoughts? :) |
alright I'm pretty confident in this at this point, I've run it against the lantern expectations, found 2 more subtle places where we weren't matching DT behavior (though arguably we could've left it as is), and the only 8 sites that changed were small ordering differences that should be eliminated by #5362 the actual network record objects that were created were identical across all critical properties on all 100 sites |
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.
ok, big feedback this time, but almost all clarification/style stuff, I think. Overall this looks great
@@ -17,7 +17,6 @@ describe('Web Inspector lib', function() { | |||
assert.ok(WebInspector.FilmStripModel); | |||
assert.ok(WebInspector.TimelineProfileTree); | |||
assert.ok(WebInspector.TimelineAggregator); | |||
assert.ok(WebInspector.NetworkManager); |
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.
lol this test
typings/web-inspector.d.ts
Outdated
@@ -6,8 +6,8 @@ | |||
|
|||
declare global { | |||
module LH.WebInspector { | |||
// TODO(bckenny): standardize on underscored internal API | |||
// externs for chrome-devtools-frontend/front_end/sdk/NetworkRequest.js | |||
// TODO(phulce): standardize on non-underscored property names |
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.
switch this to "TODO(phulce): migrate to using network-request.js
"?
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.
done
} | ||
redirectSource?: {url: string;}; | ||
redirectDestination?: {url: string;}; | ||
redirects?: NetworkRequest[]; |
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.
can you add a /** ... */
comment to these? e.g. request that redirected to this request, if it exists, request this request redirected to, in order redirect chain to this request (if those are correct)
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.
though maybe these comments should live in network-request.js
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.
done over there 👍
typings/web-inspector.d.ts
Outdated
@@ -62,16 +65,10 @@ declare global { | |||
} | |||
|
|||
export interface ResourceType { |
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.
drop this and import ResourceType.js
for the type?
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.
done
third-party/devtools/ResourceType.js
Outdated
}; | ||
|
||
/** | ||
* Keep these in sync with WebCore::InspectorPageAgent::resourceTypeJson |
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.
you could maybe type this with Record<LH.Crdp.Page.ResourceType, ResourceType>
to make sure they stay in sync (at least with our types for the protocol)
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.
hmm, but this has more keys than that. I would have expected them to match. The types in the protocol repo have more of them (I should update us to use that), but still missing SourceMapScript
and SourceMapStyleSheet
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.
FWIW that was a devtools comment I didn't add that :)
we only need those ones that match so I'm cool with that, and honestly this entire file can be deleted after we stop that WebInspector.resourceTypes ===
nonsense :D
/** | ||
* @return {NetworkRequest} | ||
*/ | ||
clone() { |
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.
used anywhere?
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.
nah just testing, I'll remove
* @param {LH.Crdp.Network.LoadingFinishedEvent} data | ||
*/ | ||
onLoadingFinished(data) { | ||
if (this.finished) return; |
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.
when does this happen and is that bad or just expected?
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 seems to be expected for a certain class of request failures (aborted redirected requests)
not sure how to best comment it...maybe?
// On cancelled requests, DevTools can send duplicate erroneous events, prefer the first one for best timing data
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 that's 👍
this.endTime = data.timestamp; | ||
|
||
this.failed = true; | ||
this._resourceType = data.type && resourceTypes[data.type]; |
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.
why updated here?
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 it's because resourceTypes can always lie, so you can always get more information when the response comes back, also probably has to do with signed-exchanges and some corner cases we don't really care about
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.
ah, yeah, good to mirror the real deal. I was also wondering because onLoadingFinished
doesn't do the same
// Take startTime and responseReceivedTime from timing data for better accuracy. | ||
// Timing's requestTime is a baseline in seconds, rest of the numbers there are ticks in millis. | ||
this.startTime = timing.requestTime; | ||
const headersReceivedTime = timing.requestTime + timing.receiveHeadersEnd / 1000.0; |
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.
1000
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.
done
this.endTime = Math.max(this.endTime, this._responseReceivedTime); | ||
} | ||
|
||
_updateResponseReceivedTimeIfNecessary() { |
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.
add a comment for what this is doing/when it's "necessary"?
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.
done
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.
some last comment suggestions, but otherwise LGTM! Let's do this
const redirectRequest = new NetworkRequest(); | ||
|
||
redirectRequest.onRequestWillBeSent(modifiedData); | ||
originalRequest.onRedirectResponse(data); |
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.
maybe add a comment so that anyone rearranging in the future won't accidentally do that?
this._timing = /** @type {LH.Crdp.Network.ResourceTiming|undefined} */ (undefined); | ||
this._resourceType = /** @type {LH.WebInspector.ResourceType|undefined} */ (undefined); | ||
this._mimeType = ''; | ||
this.priority = () => /** @type {LH.Crdp.Network.ResourcePriority} */ ('Low'); |
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.
yes, don't want to add machinery for things I immediately want to get rid of :)
ha, oh right. SG
* @param {LH.Crdp.Network.LoadingFinishedEvent} data | ||
*/ | ||
onLoadingFinished(data) { | ||
if (this.finished) return; |
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 that's 👍
this.endTime = data.timestamp; | ||
|
||
this.failed = true; | ||
this._resourceType = data.type && resourceTypes[data.type]; |
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.
ah, yeah, good to mirror the real deal. I was also wondering because onLoadingFinished
doesn't do the same
typings/web-inspector.d.ts
Outdated
export interface ResourceCategory { | ||
title: string; | ||
} | ||
export type ResourceType = _ResourceType; |
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 doesn't seem like anything is referring to this type except the NetworkRequest
interface, so can drop this declaration?
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.
done
title speaks for itself, big change :)
part of the broader goal of removing our dependency on devtools-frontend
tests should be passing now! 🎉 I want to do more comparisons with my lantern traces and land our safety checks before this one