Commit a979fce6 authored by Andrey Kosyakov's avatar Andrey Kosyakov Committed by Commit Bot

DevTools: make interception work with multiple clients

This is network service-only.

Bug: 896924
Change-Id: I240d743089735c5a647112fb83c13081b55bd64b
Reviewed-on: https://chromium-review.googlesource.com/c/1289962
Commit-Queue: Andrey Kosyakov <caseq@chromium.org>
Reviewed-by: default avatarPavel Feldman <pfeldman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#601817}
parent 8bca0507
......@@ -206,8 +206,10 @@ class InterceptionJob : public network::mojom::URLLoaderClient,
}
~InterceptionJob() override {
size_t erased = GetInterceptionJobMap().erase(global_req_id_);
DCHECK_EQ(1lu, erased);
if (registered_in_global_request_map_) {
size_t erased = GetInterceptionJobMap().erase(global_req_id_);
DCHECK_EQ(1lu, erased);
}
}
Response InnerContinueRequest(std::unique_ptr<Modifications> modifications);
......@@ -311,6 +313,7 @@ class InterceptionJob : public network::mojom::URLLoaderClient,
std::unique_ptr<BodyReader> body_reader_;
std::unique_ptr<ResponseMetadata> response_metadata_;
bool registered_in_global_request_map_;
base::Optional<std::pair<net::RequestPriority, int32_t>> priority_;
DevToolsURLLoaderInterceptor::HandleAuthRequestCallback
......@@ -709,8 +712,10 @@ InterceptionJob::InterceptionJob(
base::BindOnce(&InterceptionJob::Shutdown, base::Unretained(this)));
auto& job_map = GetInterceptionJobMap();
bool inserted = job_map.emplace(global_req_id_, this).second;
DCHECK(inserted);
// TODO(caseq): for now, all auth requests will go to the top-level job.
// Figure out if we need anything smarter here.
registered_in_global_request_map_ =
job_map.emplace(global_req_id_, this).second;
if (stage_ & InterceptionStage::REQUEST) {
NotifyClient(BuildRequestInfo(nullptr));
......
......@@ -366,13 +366,17 @@ bool RenderFrameDevToolsAgentHost::WillCreateURLLoaderFactory(
return false;
int process_id = is_navigation ? 0 : rfh->GetProcess()->GetID();
DCHECK(!is_download || is_navigation);
for (auto* network : protocol::NetworkHandler::ForAgentHost(agent_host)) {
if (network->MaybeCreateProxyForInterception(
frame_token, process_id, is_download, target_factory_request)) {
return true;
}
}
return false;
bool had_interceptors = false;
const auto& network_handlers =
protocol::NetworkHandler::ForAgentHost(agent_host);
for (auto it = network_handlers.rbegin(); it != network_handlers.rend();
++it) {
had_interceptors =
(*it)->MaybeCreateProxyForInterception(
frame_token, process_id, is_download, target_factory_request) ||
had_interceptors;
}
return had_interceptors;
}
// static
......
......@@ -14,6 +14,7 @@ crbug.com/800898 external/wpt/FileAPI/url/url-in-tags-revoke.window.html [ Pass
crbug.com/800898 external/wpt/workers/worker-from-blob-url.window.html [ Pass ]
crbug.com/595993 external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Pass ]
crbug.com/862886 external/wpt/service-workers/service-worker/navigation-preload/broken-chunked-encoding.https.html [ Pass ]
crbug.com/896924 http/tests/inspector-protocol/network/interception-multiclient.js [ Pass ]
# Flaky on non-NetworkService (disabled), consistent failing on NetworkService. Probably due to DCHECK.
crbug.com/849670 http/tests/devtools/service-workers/service-worker-v8-cache.js [ Pass Failure ]
......
......@@ -5289,6 +5289,9 @@ crbug.com/869492 external/wpt/feature-policy/experimental-features/lazyload/lazy
crbug.com/869492 virtual/threaded/external/wpt/feature-policy/experimental-features/lazyload/lazyload-enabled-tentative.sub.html [ Failure ]
crbug.com/869492 virtual/video-surface-layer/external/wpt/feature-policy/experimental-features/lazyload/lazyload-disabled-tentative.sub.html [ Failure ]
# The below is only supported with network service.
crbug.com/896924 http/tests/inspector-protocol/network/interception-multiclient.js [ Skip ]
# Sheriff 2018-09-13
crbug.com/883591 [ Android ] fullscreen/full-screen-inline-split-crash.html [ Pass Crash ]
......
Tests that interception works with multiple clients.
-- request stage for client 1 and client 2
client 2: intercepted request to http://127.0.0.1:8000/devtools/network/resources/resource.php
client 1: intercepted request to http://127.0.0.1:8000/devtools/network/resources/resource.php
-- request stage for client 1, both stages for client 2
client 2: intercepted request to http://127.0.0.1:8000/devtools/network/resources/resource.php
client 1: intercepted request to http://127.0.0.1:8000/devtools/network/resources/resource.php
client 2: intercepted response 200 from http://127.0.0.1:8000/devtools/network/resources/resource.php
-- both stages for client 1 and client 2
client 2: intercepted request to http://127.0.0.1:8000/devtools/network/resources/resource.php
client 1: intercepted request to http://127.0.0.1:8000/devtools/network/resources/resource.php
client 1: intercepted response 200 from http://127.0.0.1:8000/devtools/network/resources/resource.php
client 2: intercepted response 200 from http://127.0.0.1:8000/devtools/network/resources/resource.php
-- mock response from client 1
client 2: intercepted request to http://127.0.0.1:8000/devtools/network/resources/resource.php
client 1: rejecting request to http://127.0.0.1:8000/devtools/network/resources/resource.php
client 2: intercepted response 418 from http://127.0.0.1:8000/devtools/network/resources/resource.php
-- mock response from client 3
client 3: resolving response to http://127.0.0.1:8000/devtools/network/resources/resource.php
response: Hello, world!
-- url rewrite from client 3
client 3: overriding URL from http://127.0.0.1:8000/devtools/network/resources/resource.php to http://127.0.0.1:8000/devtools/network/resources/resource.php?jscontent=1
client 2: intercepted request to http://127.0.0.1:8000/devtools/network/resources/resource.php?jscontent=1
client 1: rejecting request to http://127.0.0.1:8000/devtools/network/resources/resource.php?jscontent=1
client 2: intercepted response 418 from http://127.0.0.1:8000/devtools/network/resources/resource.php?jscontent=1
(async function(testRunner) {
var {page, session, dp} = await testRunner.startBlank('Tests that interception works with multiple clients.');
const dp2 = (await page.createSession()).protocol;
await dp.Network.clearBrowserCache();
await dp.Network.clearBrowserCookies();
await dp.Network.setCacheDisabled({cacheDisabled: true});
await dp.Network.enable();
await dp.Runtime.enable();
await dp2.Network.enable();
testRunner.log('-- request stage for client 1 and client 2');
await dp2.Network.setRequestInterception({patterns: [{}]});
await dp.Network.setRequestInterception({patterns: [{}]});
function continueInterceptedRequest(protocol, clientName, event) {
const params = event.params;
const url = params.request.url;
const is_response = !!params.responseHeaders;
if (is_response) {
testRunner.log(`${clientName}: intercepted response ${params.responseStatusCode} from ${url}`);
} else {
testRunner.log(`${clientName}: intercepted request to ${url}`);
}
protocol.Network.continueInterceptedRequest({interceptionId : params.interceptionId});
}
const listener1 = continueInterceptedRequest.bind(this, dp, "client 1");
dp.Network.onRequestIntercepted(listener1);
dp2.Network.onRequestIntercepted(continueInterceptedRequest.bind(this, dp2, "client 2"));
await session.evaluateAsync(`fetch("/devtools/network/resources/resource.php").then(r => r.text())`);
testRunner.log('-- request stage for client 1, both stages for client 2');
await dp2.Network.setRequestInterception({patterns: [
{urlPattern: '*', interceptionStage: 'Request'},
{urlPattern: '*', interceptionStage: 'HeadersReceived'}
]});
await session.evaluateAsync(`fetch("/devtools/network/resources/resource.php").then(r => r.text())`);
testRunner.log('-- both stages for client 1 and client 2');
await dp.Network.setRequestInterception({patterns: [
{urlPattern: '*', interceptionStage: 'Request'},
{urlPattern: '*', interceptionStage: 'HeadersReceived'}
]});
await session.evaluateAsync(`fetch("/devtools/network/resources/resource.php").then(r => r.text())`);
testRunner.log('-- mock response from client 1');
dp.Network.offRequestIntercepted(listener1);
dp.Network.onRequestIntercepted(event => {
const params = event.params;
testRunner.log(`client 1: rejecting request to ${params.request.url}`);
dp.Network.continueInterceptedRequest({interceptionId: params.interceptionId, rawResponse: btoa("HTTP/1.1 418 I'm a teapot\r\n\r\n")});
});
await session.evaluateAsync(`fetch("/devtools/network/resources/resource.php").then(r => r.text())`);
testRunner.log('-- mock response from client 3');
const dp3 = (await page.createSession()).protocol;
await dp3.Network.setRequestInterception({patterns: [{}]});
dp3.Network.onceRequestIntercepted().then(event => {
const params = event.params;
testRunner.log(`client 3: resolving response to ${params.request.url}`);
dp3.Network.continueInterceptedRequest({interceptionId: params.interceptionId, rawResponse: btoa("HTTP/1.1 200\r\n\r\nHello, world!")});
});
const body = await session.evaluateAsync(`fetch("/devtools/network/resources/resource.php").then(r => r.text())`);
testRunner.log(`response: ${body}`);
testRunner.log('-- url rewrite from client 3');
dp3.Network.onceRequestIntercepted().then(event => {
const params = event.params;
const newURL = `${params.request.url}?jscontent=1`;
testRunner.log(`client 3: overriding URL from ${params.request.url} to ${newURL}`);
dp3.Network.continueInterceptedRequest({interceptionId: params.interceptionId, url: newURL});
});
await session.evaluateAsync(`fetch("/devtools/network/resources/resource.php").then(r => r.text())`);
testRunner.completeTest();
})
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment