Skip to content

Commit 0751fa9

Browse files
fix: associate preflight network request with context (#3572)
Addressing #3570
1 parent 511e57e commit 0751fa9

File tree

5 files changed

+149
-28
lines changed

5 files changed

+149
-28
lines changed

src/bidiMapper/modules/network/NetworkModuleMocks.spec.ts

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ export class MockCdpNetworkEvents {
3535
requestId: string;
3636
fetchId: string;
3737
private loaderId: string;
38-
private frameId: string;
38+
private frameId: string | undefined;
3939
private type: Protocol.Network.ResourceType;
40+
private initiator: Protocol.Network.Initiator;
4041

4142
constructor(
4243
cdpClient: CdpClient,
@@ -47,13 +48,15 @@ export class MockCdpNetworkEvents {
4748
url,
4849
frameId,
4950
type,
51+
initiator,
5052
}: Partial<{
5153
requestId: string;
5254
fetchId: string;
5355
loaderId: string;
5456
url: string;
55-
frameId: string;
57+
frameId: string | null;
5658
type: Protocol.Network.ResourceType;
59+
initiator: Protocol.Network.Initiator;
5760
}> = {},
5861
) {
5962
this.cdpClient = cdpClient;
@@ -62,8 +65,23 @@ export class MockCdpNetworkEvents {
6265
this.fetchId = fetchId ?? 'interception-job-1.0';
6366
this.loaderId = loaderId ?? '7760711DEFCFA23132D98ABA6B4E175C';
6467
this.url = url ?? MockCdpNetworkEvents.defaultUrl;
65-
this.frameId = frameId ?? MockCdpNetworkEvents.defaultFrameId;
68+
this.frameId =
69+
frameId === null ? undefined : MockCdpNetworkEvents.defaultFrameId;
6670
this.type = type ?? 'XHR';
71+
this.initiator = initiator ?? {
72+
type: 'script',
73+
stack: {
74+
callFrames: [
75+
{
76+
functionName: '',
77+
scriptId: '5',
78+
url: '',
79+
lineNumber: 0,
80+
columnNumber: 0,
81+
},
82+
],
83+
},
84+
};
6785
}
6886

6987
requestWillBeSent() {
@@ -89,20 +107,7 @@ export class MockCdpNetworkEvents {
89107
},
90108
timestamp: 2111.55635,
91109
wallTime: 1637315638.473634,
92-
initiator: {
93-
type: 'script',
94-
stack: {
95-
callFrames: [
96-
{
97-
functionName: '',
98-
scriptId: '5',
99-
url: '',
100-
lineNumber: 0,
101-
columnNumber: 0,
102-
},
103-
],
104-
},
105-
},
110+
initiator: this.initiator,
106111
redirectHasExtraInfo: false,
107112
type: this.type,
108113
frameId: this.frameId,
@@ -342,7 +347,8 @@ export class MockCdpNetworkEvents {
342347
initialPriority: 'High',
343348
referrerPolicy: 'strict-origin-when-cross-origin',
344349
},
345-
frameId: this.frameId,
350+
// FrameId is required in fetch.
351+
frameId: this.frameId ?? MockCdpNetworkEvents.defaultFrameId,
346352
resourceType: this.type,
347353
networkId: this.requestId,
348354
});
@@ -362,7 +368,8 @@ export class MockCdpNetworkEvents {
362368
responseStatusCode: 200,
363369
responseStatusText: '',
364370
responseHeaders: [],
365-
frameId: this.frameId,
371+
// FrameId is required in fetch.
372+
frameId: this.frameId ?? MockCdpNetworkEvents.defaultFrameId,
366373
resourceType: this.type,
367374
networkId: this.requestId,
368375
});
@@ -386,7 +393,8 @@ export class MockCdpNetworkEvents {
386393
initialPriority: 'High',
387394
referrerPolicy: 'strict-origin-when-cross-origin',
388395
},
389-
frameId: this.frameId,
396+
// FrameId is required in fetch.
397+
frameId: this.frameId ?? MockCdpNetworkEvents.defaultFrameId,
390398
resourceType: this.type,
391399
authChallenge: {
392400
source: 'Server',

src/bidiMapper/modules/network/NetworkRequest.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -237,14 +237,33 @@ export class NetworkRequest {
237237
return bodySize;
238238
}
239239

240-
get #context() {
241-
return (
240+
get #context(): string | null {
241+
const result =
242242
this.#response.paused?.frameId ??
243243
this.#request.info?.frameId ??
244244
this.#request.paused?.frameId ??
245-
this.#request.auth?.frameId ??
246-
null
247-
);
245+
this.#request.auth?.frameId;
246+
247+
if (result !== undefined) {
248+
return result;
249+
}
250+
251+
// Heuristic for associating a preflight request with context via it's initiator
252+
// request. Useful for preflight requests.
253+
// https://github.com/GoogleChromeLabs/chromium-bidi/issues/3570
254+
if (
255+
this.#request?.info?.initiator.type === 'preflight' &&
256+
this.#request?.info?.initiator.requestId !== undefined
257+
) {
258+
const maybeInitiator = this.#networkStorage.getRequestById(
259+
this.#request?.info?.initiator.requestId,
260+
);
261+
if (maybeInitiator !== undefined) {
262+
return maybeInitiator.#request.info?.frameId ?? null;
263+
}
264+
}
265+
266+
return null;
248267
}
249268

250269
/** Returns the HTTP status code associated with this request if any. */

src/bidiMapper/modules/network/NetworkStorage.spec.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,30 @@ describe('NetworkStorage', () => {
242242
const event = await getEvent('network.beforeRequestSent');
243243
expect(event).to.exist;
244244
});
245+
246+
it('should report right context for preflight requests', async () => {
247+
const initialRequest = new MockCdpNetworkEvents(cdpClient);
248+
initialRequest.requestWillBeSent();
249+
250+
const preflightRrequest = new MockCdpNetworkEvents(cdpClient, {
251+
requestId: 'ANOTHER_REQUEST_ID',
252+
// Preflight requests don't have `frameId`.
253+
frameId: null,
254+
initiator: {
255+
type: 'preflight',
256+
url: initialRequest.url,
257+
requestId: initialRequest.requestId,
258+
},
259+
});
260+
preflightRrequest.requestWillBeSent();
261+
preflightRrequest.requestWillBeSentExtraInfo();
262+
263+
const event = await getEvent('network.beforeRequestSent');
264+
expect(event).to.exist;
265+
expect((event as Network.BeforeRequestSentParameters).context).to.equal(
266+
MockCdpNetworkEvents.defaultFrameId,
267+
);
268+
});
245269
});
246270

247271
describe('network.responseStarted', () => {

tests/conftest.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -613,11 +613,14 @@ def url_hang_forever_download(local_server_http):
613613
@pytest.fixture
614614
def html(local_server_http, local_server_http_another_host):
615615
"""Return a factory for URL with the given content."""
616-
def html(content="", same_origin=True):
616+
def html(content="",
617+
same_origin=True,
618+
headers: dict[str, str] | None = None):
617619
if same_origin:
618-
return local_server_http.url_200(content=content)
620+
return local_server_http.url_200(content=content, headers=headers)
619621
else:
620-
return local_server_http_another_host.url_200(content=content)
622+
return local_server_http_another_host.url_200(content=content,
623+
headers=headers)
621624

622625
return html
623626

tests/network/test_network.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,3 +523,70 @@ async def test_network_should_not_block_queue_shared_workers_with_data_url(
523523
"timestamp": ANY_TIMESTAMP
524524
}
525525
})
526+
527+
528+
@pytest.mark.asyncio
529+
async def test_network_preflight(websocket, context_id, html, url_example,
530+
read_messages):
531+
""" https://github.com/GoogleChromeLabs/chromium-bidi/issues/3570 """
532+
url = html("hello world!",
533+
same_origin=False,
534+
headers={
535+
"Access-Control-Allow-Origin": "*",
536+
"Access-Control-Allow-Headers": "x-ping"
537+
})
538+
539+
await goto_url(websocket, context_id, url)
540+
541+
await subscribe(websocket, ["network.beforeRequestSent"])
542+
543+
# Initiate a non-trivial CORS request.
544+
await send_JSON_command(
545+
websocket, {
546+
"method": "script.evaluate",
547+
"params": {
548+
"expression": f"""
549+
fetch('{url_example}', {{
550+
method: 'PUT',
551+
}})
552+
""",
553+
"target": {
554+
"context": context_id
555+
},
556+
"awaitPromise": False,
557+
}
558+
})
559+
560+
[_, preflight_request, post_request] = await read_messages(3, sort=True)
561+
562+
assert preflight_request == AnyExtending({
563+
'method': 'network.beforeRequestSent',
564+
'params': {
565+
'context': context_id,
566+
'initiator': {
567+
'request': ANY_STR,
568+
'type': 'preflight',
569+
},
570+
'request': {
571+
'method': 'OPTIONS',
572+
'request': ANY_STR,
573+
'url': url_example,
574+
},
575+
},
576+
'type': 'event',
577+
})
578+
initiator_request_id = preflight_request['params']['initiator']['request']
579+
580+
assert post_request == AnyExtending({
581+
'method': 'network.beforeRequestSent',
582+
'params': {
583+
'context': context_id,
584+
'request': {
585+
'initiatorType': 'fetch',
586+
'method': 'PUT',
587+
'request': initiator_request_id,
588+
'url': url_example,
589+
},
590+
},
591+
'type': 'event',
592+
})

0 commit comments

Comments
 (0)