-
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(oopif): collect network requests from iframes #6922
Changes from all commits
35de9e9
d6e8aea
52e1640
1734ee0
f546378
3a10248
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>Where is my iframe?</title> | ||
</head> | ||
<body> | ||
<h1>Hello frames</h1> | ||
<iframe name="oopif" src="https://airhorner.com"></iframe> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/** | ||
* @license Copyright 2019 Google Inc. All Rights Reserved. | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. | ||
*/ | ||
'use strict'; | ||
|
||
/** | ||
* Config file for running the OOPIF tests | ||
*/ | ||
module.exports = { | ||
extends: 'lighthouse:default', | ||
settings: { | ||
onlyAudits: [ | ||
'network-requests', | ||
], | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/** | ||
* @license Copyright 2019 Google Inc. All Rights Reserved. | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. | ||
*/ | ||
'use strict'; | ||
|
||
/** | ||
* Expected Lighthouse audit values for sites with OOPIFS. | ||
*/ | ||
module.exports = [ | ||
{ | ||
requestedUrl: 'http://localhost:10200/oopif.html', | ||
finalUrl: 'http://localhost:10200/oopif.html', | ||
audits: { | ||
'network-requests': { | ||
details: { | ||
items: { | ||
// The page itself only makes a few requests. | ||
// We want to make sure we are finding the iframe's requests (airhorner) while being flexible enough | ||
// to allow changes to the live site. | ||
length: '>10', | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
]; |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -47,8 +47,8 @@ class Driver { | |||||
*/ | ||||||
this._eventEmitter = /** @type {CrdpEventEmitter} */ (new EventEmitter()); | ||||||
this._connection = connection; | ||||||
// currently only used by WPT where just Page and Network are needed | ||||||
this._devtoolsLog = new DevtoolsLog(/^(Page|Network)\./); | ||||||
// Used to save network and lifecycle protocol traffic. Just Page, Network, and Target are needed. | ||||||
this._devtoolsLog = new DevtoolsLog(/^(Page|Network|Target)\./); | ||||||
this.online = true; | ||||||
/** @type {Map<string, number>} */ | ||||||
this._domainEnabledCounts = new Map(); | ||||||
|
@@ -69,6 +69,20 @@ class Driver { | |||||
*/ | ||||||
this._monitoredUrl = null; | ||||||
|
||||||
let targetProxyMessageId = 0; | ||||||
this.on('Target.attachedToTarget', event => { | ||||||
targetProxyMessageId++; | ||||||
// We're only interested in network requests from iframes for now as those are "part of the page". | ||||||
if (event.targetInfo.type !== 'iframe') return; | ||||||
|
||||||
// We want to receive information about network requests from iframes, so enable the Network domain. | ||||||
// Network events from subtargets will be stringified and sent back on `Target.receivedMessageFromTarget`. | ||||||
this.sendCommand('Target.sendMessageToTarget', { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
This kind of thing could be possible with the flattened protocol... See https://github.com/GoogleChrome/puppeteer/pull/3827/files We'd also add The I tried this out, but it adds a bunch of complication around our typing for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
+1, the direction that method started taking me seemed far more complicated given our existing setup than this approach. As long as it's not disappearing from protocol tomorrow, I think this is better for us :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
maybe we can work on this so we aren't straightjacketed by our type checker |
||||||
message: JSON.stringify({id: targetProxyMessageId, method: 'Network.enable'}), | ||||||
sessionId: event.sessionId, | ||||||
}); | ||||||
}); | ||||||
|
||||||
connection.on('protocolevent', event => { | ||||||
this._devtoolsLog.record(event); | ||||||
if (this._networkStatusMonitor) { | ||||||
|
@@ -1015,6 +1029,12 @@ class Driver { | |||||
await this._beginNetworkStatusMonitoring(url); | ||||||
await this._clearIsolatedContextId(); | ||||||
|
||||||
// Enable auto-attaching to subtargets so we receive iframe information | ||||||
await this.sendCommand('Target.setAutoAttach', { | ||||||
autoAttach: true, | ||||||
waitForDebuggerOnStart: false, | ||||||
}); | ||||||
|
||||||
await this.sendCommand('Page.enable'); | ||||||
await this.sendCommand('Page.setLifecycleEventsEnabled', {enabled: true}); | ||||||
await this.sendCommand('Emulation.setScriptExecutionDisabled', {value: disableJS}); | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -303,15 +303,26 @@ class NetworkRecorder extends EventEmitter { | |
request.onResourceChangedPriority(data); | ||
} | ||
|
||
/** | ||
* Events from targets other than the main frame are proxied through `Target.receivedMessageFromTarget`. | ||
* Their payloads are JSON-stringified into the `.message` property | ||
* @param {LH.Crdp.Target.ReceivedMessageFromTargetEvent} data | ||
*/ | ||
onReceivedMessageFromTarget(data) { | ||
/** @type {LH.Protocol.RawMessage} */ | ||
const protocolMessage = JSON.parse(data.message); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you add a comment (jsdoc or inline) about where these messages come from and the expected form? (basically, I assume, stringified protocol responses in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
|
||
// Message was a response to some command, not an event, so we'll ignore it. | ||
if ('id' in protocolMessage) return; | ||
// Message was an event, replay it through our normal dispatch process. | ||
this.dispatch(protocolMessage); | ||
} | ||
|
||
/** | ||
* Routes network events to their handlers, so we can construct networkRecords | ||
* @param {LH.Protocol.RawEventMessage} event | ||
*/ | ||
dispatch(event) { | ||
if (!event.method.startsWith('Network.')) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in case you're curious like me if this was saving us anytime, it looks like it wasn't just a switch is ~10x faster |
||
return; | ||
} | ||
|
||
switch (event.method) { | ||
case 'Network.requestWillBeSent': return this.onRequestWillBeSent(event.params); | ||
case 'Network.requestServedFromCache': return this.onRequestServedFromCache(event.params); | ||
|
@@ -320,6 +331,7 @@ class NetworkRecorder extends EventEmitter { | |
case 'Network.loadingFinished': return this.onLoadingFinished(event.params); | ||
case 'Network.loadingFailed': return this.onLoadingFailed(event.params); | ||
case 'Network.resourceChangedPriority': return this.onResourceChangedPriority(event.params); | ||
case 'Target.receivedMessageFromTarget': return this.onReceivedMessageFromTarget(event.params); // eslint-disable-line max-len | ||
default: 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.
maybe add a comment why this is a good bounds
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