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

DevTools: intercept requests resulting from redirects

This introduces additional interception step into DevTools network
interception logic -- we now pause and report intercepted requests
after browser decided to follow the redirect, but before the request
is sent.

Change-Id: I228e6898d3a28abf80b8b6cc72ff61fac3884279
Reviewed-on: https://chromium-review.googlesource.com/1145946
Commit-Queue: Andrey Kosyakov <caseq@chromium.org>
Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577212}
parent d63a2e68
......@@ -566,7 +566,6 @@ DevToolsURLInterceptorRequestJob::DevToolsURLInterceptorRequestJob(
net::NetworkDelegate* original_network_delegate,
const base::UnguessableToken& devtools_token,
DevToolsNetworkInterceptor::RequestInterceptedCallback callback,
bool is_redirect,
ResourceType resource_type,
InterceptionStage stage_to_intercept)
: net::URLRequestJob(original_request, original_network_delegate),
......@@ -584,7 +583,6 @@ DevToolsURLInterceptorRequestJob::DevToolsURLInterceptorRequestJob(
owning_entry_id_(owning_entry_id),
devtools_token_(devtools_token),
callback_(callback),
is_redirect_(is_redirect),
resource_type_(resource_type),
stage_to_intercept_(stage_to_intercept),
weak_ptr_factory_(this) {
......@@ -635,26 +633,6 @@ void DevToolsURLInterceptorRequestJob::StartWithCookies(
return;
}
if (is_redirect_) {
if (stage_to_intercept_ == InterceptionStage::REQUEST) {
// If we are a redirect and we do not plan on grabbing the response we are
// done. If we are here this means we must have already sent an
// intercepted event to front-end for this redirect and the front-end
// allowed it. Since we have already allowed the redirect and we are only
// intercepting the request, we only need to catch it again if it's
// another redirect, which SubRequest will send the
// OnSubRequestRedirectReceived event.
sub_request_.reset(new SubRequest(request_details_, this, interceptor_));
} else {
// Otherwise we have already issued the request interception and had a
// continue and now we must issue a response interception for the
// redirect.
sub_request_.reset(
new InterceptedRequest(request_details_, this, interceptor_));
}
return;
}
if (stage_to_intercept_ == InterceptionStage::RESPONSE) {
// We are only a response interception, we go right to dispatching the
// request.
......@@ -1045,7 +1023,6 @@ void DevToolsURLInterceptorRequestJob::ProcessRedirect(
base::MakeRefCounted<net::HttpResponseHeaders>(raw_headers), "", 0,
base::TimeTicks::Now()));
interceptor_->ExpectRequestAfterRedirect(request(), interception_id_);
NotifyHeadersComplete();
}
......@@ -1124,11 +1101,6 @@ void DevToolsURLInterceptorRequestJob::ProcessInterceptionResponse(
mock_response_details_.reset(new MockResponseDetails(
std::move(*modifications->raw_response), base::TimeTicks::Now()));
std::string value;
if (mock_response_details_->response_headers()->IsRedirect(&value)) {
interceptor_->ExpectRequestAfterRedirect(request(), interception_id_);
}
// Set cookies in the network stack.
net::CookieOptions options;
options.set_include_httponly();
......
......@@ -37,7 +37,6 @@ class DevToolsURLInterceptorRequestJob : public net::URLRequestJob {
net::NetworkDelegate* original_network_delegate,
const base::UnguessableToken& devtools_token,
DevToolsNetworkInterceptor::RequestInterceptedCallback callback,
bool is_redirect,
ResourceType resource_type,
DevToolsNetworkInterceptor::InterceptionStage stage_to_intercept);
......@@ -157,7 +156,6 @@ class DevToolsURLInterceptorRequestJob : public net::URLRequestJob {
const intptr_t owning_entry_id_;
const base::UnguessableToken devtools_token_;
DevToolsNetworkInterceptor::RequestInterceptedCallback callback_;
const bool is_redirect_;
const ResourceType resource_type_;
InterceptionStage stage_to_intercept_;
std::vector<std::unique_ptr<GetResponseBodyForInterceptionCallback>>
......
......@@ -252,8 +252,9 @@ class InterceptionJob : public network::mojom::URLLoaderClient,
void OnComplete(const network::URLLoaderCompletionStatus& status) override;
bool CanGetResponseBody(std::string* error_reason);
void UpdateIdAndRegister();
const std::string id_;
const std::string id_prefix_;
const GlobalRequestId global_req_id_;
const base::UnguessableToken frame_token_;
const base::TimeTicks start_ticks_;
......@@ -277,6 +278,7 @@ class InterceptionJob : public network::mojom::URLLoaderClient,
kNotStarted,
kRequestSent,
kRedirectReceived,
kFollowRedirect,
kAuthRequired,
kResponseReceived,
kResponseTaken,
......@@ -284,6 +286,8 @@ class InterceptionJob : public network::mojom::URLLoaderClient,
State state_;
bool waiting_for_resolution_;
int redirect_count_;
std::string current_id_;
std::unique_ptr<BodyReader> body_reader_;
std::unique_ptr<ResponseMetadata> response_metadata_;
......@@ -320,11 +324,11 @@ class DevToolsURLLoaderInterceptor::Impl
static int last_id = 0;
std::string id = base::StringPrintf("interception-job-%d", ++last_id);
InterceptionJob* job = new InterceptionJob(
this, id, frame_token, process_id, std::move(create_params),
is_download, std::move(loader_request), std::move(client),
std::move(target_factory));
jobs_.emplace(std::move(id), job);
// This class will manage its own life time to match the loader client.
new InterceptionJob(this, std::move(id), frame_token, process_id,
std::move(create_params), is_download,
std::move(loader_request), std::move(client),
std::move(target_factory));
}
void SetPatterns(std::vector<DevToolsNetworkInterceptor::Pattern> patterns) {
......@@ -392,6 +396,9 @@ class DevToolsURLLoaderInterceptor::Impl
}
void RemoveJob(const std::string& id) { jobs_.erase(id); }
void AddJob(const std::string& id, InterceptionJob* job) {
jobs_.emplace(id, job);
}
std::map<std::string, InterceptionJob*> jobs_;
RequestInterceptedCallback request_intercepted_callback_;
......@@ -627,7 +634,7 @@ InterceptionJob::InterceptionJob(
network::mojom::URLLoaderRequest loader_request,
network::mojom::URLLoaderClientPtr client,
network::mojom::URLLoaderFactoryPtr target_factory)
: id_(std::move(id)),
: id_prefix_(id),
global_req_id_(
std::make_tuple(process_id,
create_loader_params->request.render_frame_id,
......@@ -644,7 +651,9 @@ InterceptionJob::InterceptionJob(
client_(std::move(client)),
target_factory_(std::move(target_factory)),
state_(kNotStarted),
waiting_for_resolution_(false) {
waiting_for_resolution_(false),
redirect_count_(0) {
UpdateIdAndRegister();
const network::ResourceRequest& request = create_loader_params_->request;
stage_ = interceptor_->GetInterceptionStage(
request.url, static_cast<ResourceType>(request.resource_type));
......@@ -665,6 +674,11 @@ InterceptionJob::InterceptionJob(
StartRequest();
}
void InterceptionJob::UpdateIdAndRegister() {
current_id_ = id_prefix_ + base::StringPrintf(".%d", redirect_count_);
interceptor_->AddJob(current_id_, this);
}
bool InterceptionJob::CanGetResponseBody(std::string* error_reason) {
if (!(stage_ & InterceptionStage::RESPONSE)) {
*error_reason =
......@@ -786,6 +800,18 @@ Response InterceptionJob::InnerContinueRequest(
if (modifications->raw_response)
return ProcessResponseOverride(*modifications->raw_response);
if (state_ == State::kFollowRedirect) {
if (modifications->modified_url.isJust()) {
CancelRequest();
// Fall through to the generic logic of re-starting the request
// at the bottom of the method.
} else {
// TODO(caseq): report error if other modifications are present.
state_ = State::kRequestSent;
loader_->FollowRedirect(base::nullopt, base::nullopt);
return Response::OK();
}
}
if (state_ == State::kRedirectReceived) {
// TODO(caseq): report error if other modifications are present.
if (modifications->modified_url.isJust()) {
......@@ -1037,7 +1063,7 @@ void InterceptionJob::CancelRequest() {
std::unique_ptr<InterceptedRequestInfo> InterceptionJob::BuildRequestInfo(
const network::ResourceResponseHead* head) {
auto result = std::make_unique<InterceptedRequestInfo>();
result->interception_id = id_;
result->interception_id = current_id_;
result->network_request =
protocol::NetworkHandler::CreateRequestFromResourceRequest(
create_loader_params_->request);
......@@ -1078,7 +1104,7 @@ void InterceptionJob::NotifyClient(
void InterceptionJob::Shutdown() {
if (interceptor_)
interceptor_->RemoveJob(id_);
interceptor_->RemoveJob(current_id_);
delete this;
}
......@@ -1100,9 +1126,24 @@ void InterceptionJob::FollowRedirect(
request->referrer_policy = info.new_referrer_policy;
request->referrer = GURL(info.new_referrer);
response_metadata_.reset();
if (interceptor_) {
// Pretend that each redirect hop is a new request -- this is for
// compatibilty with URLRequestJob-based interception implementation.
interceptor_->RemoveJob(current_id_);
redirect_count_++;
UpdateIdAndRegister();
stage_ = interceptor_->GetInterceptionStage(
request->url, static_cast<ResourceType>(request->resource_type));
if (stage_ & InterceptionStage::REQUEST) {
if (state_ == State::kRedirectReceived)
state_ = State::kFollowRedirect;
else
DCHECK_EQ(State::kNotStarted, state_);
NotifyClient(BuildRequestInfo(nullptr));
return;
}
}
if (state_ == State::kRedirectReceived) {
state_ = State::kRequestSent;
......
......@@ -141,8 +141,7 @@ net::URLRequestJob* DevToolsURLRequestInterceptor::InnerMaybeInterceptRequest(
return nullptr;
DCHECK(interception_stage != DONT_INTERCEPT);
bool is_redirect;
std::string interception_id = GetIdForRequest(request, &is_redirect);
std::string interception_id = base::StringPrintf("id-%zu", ++next_id_);
if (IsNavigationRequest(resource_type)) {
BrowserThread::PostTask(
......@@ -155,8 +154,7 @@ net::URLRequestJob* DevToolsURLRequestInterceptor::InnerMaybeInterceptRequest(
DevToolsURLInterceptorRequestJob* job = new DevToolsURLInterceptorRequestJob(
this, interception_id, reinterpret_cast<intptr_t>(entry), request,
network_delegate, target_info->devtools_token, entry->callback,
is_redirect, resource_request_info->GetResourceType(),
interception_stage);
resource_request_info->GetResourceType(), interception_stage);
interception_id_to_job_map_[interception_id] = job;
return job;
}
......@@ -261,28 +259,6 @@ void DevToolsURLRequestInterceptor::UnregisterSubRequest(
sub_requests_.erase(sub_request);
}
void DevToolsURLRequestInterceptor::ExpectRequestAfterRedirect(
const net::URLRequest* request,
std::string id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
expected_redirects_[request] = id;
}
std::string DevToolsURLRequestInterceptor::GetIdForRequest(
const net::URLRequest* request,
bool* is_redirect) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
auto find_it = expected_redirects_.find(request);
if (find_it == expected_redirects_.end()) {
*is_redirect = false;
return base::StringPrintf("id-%zu", ++next_id_);
}
*is_redirect = true;
std::string id = find_it->second;
expected_redirects_.erase(find_it);
return id;
}
DevToolsURLInterceptorRequestJob* DevToolsURLRequestInterceptor::GetJob(
const std::string& interception_id) const {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
......
......@@ -66,10 +66,6 @@ class DevToolsURLRequestInterceptor : public net::URLRequestInterceptor,
// Registers a |sub_request| that should not be intercepted.
void RegisterSubRequest(const net::URLRequest* sub_request);
void UnregisterSubRequest(const net::URLRequest* sub_request);
// To make the user's life easier we make sure requests in a redirect chain
// all have the same id.
void ExpectRequestAfterRedirect(const net::URLRequest* request,
std::string id);
void JobFinished(const std::string& interception_id, bool is_navigation);
private:
......@@ -85,8 +81,6 @@ class DevToolsURLRequestInterceptor : public net::URLRequestInterceptor,
const DevToolsTargetRegistry::TargetInfo* TargetInfoForRequestInfo(
const ResourceRequestInfo* request_info) const;
std::string GetIdForRequest(const net::URLRequest* request,
bool* is_redirect);
// Returns a WeakPtr to the DevToolsURLInterceptorRequestJob corresponding
// to |interception_id|.
DevToolsURLInterceptorRequestJob* GetJob(
......@@ -107,9 +101,6 @@ class DevToolsURLRequestInterceptor : public net::URLRequestInterceptor,
// requests.
base::flat_set<const net::URLRequest*> sub_requests_;
// To simplify handling of redirect chains for the end user, we arrange for
// all requests in the chain to have the same interception id.
base::flat_map<const net::URLRequest*, std::string> expected_redirects_;
size_t next_id_;
base::WeakPtrFactory<DevToolsURLRequestInterceptor> weak_factory_;
......
Tests that requests produced by redirects injected via mocked response are intercepted when followed.
Intercepted: http://test-url/
Redirecting to http://test-url/redirect1
Intercepted: http://test-url/redirect1
Redirecting to http://test-url/redirect2
Intercepted: http://test-url/redirect2
Redirecting to http://test-url/final
Intercepted: http://test-url/final
Response body: Hello, world!
(async function(testRunner) {
var {page, session, dp} = await testRunner.startBlank(
`Tests that requests produced by redirects injected via mocked response are intercepted when followed.`);
await session.protocol.Network.clearBrowserCache();
await session.protocol.Network.setCacheDisabled({cacheDisabled: true});
await session.protocol.Network.enable();
await session.protocol.Page.enable();
await dp.Page.setLifecycleEventsEnabled({enabled: true});
await dp.Network.setRequestInterception({patterns: [{}]});
// Automatically proceed with redirect interceptions.
dp.Network.onRequestIntercepted(event => {
if (event.params.request.redirectUrl)
dp.Network.continueInterceptedRequest({interceptionId: event.params.interceptionId});
});
session.navigate('http://test-url/');
let params = (await dp.Network.onceRequestIntercepted()).params;
testRunner.log(`Intercepted: ${params.request.url}`);
respondWithRedirct(params, 'http://test-url/redirect1');
params = (await dp.Network.onceRequestIntercepted()).params;
testRunner.log(`Intercepted: ${params.request.url}`);
respondWithRedirct(params, 'http://test-url/redirect2');
params = (await dp.Network.onceRequestIntercepted()).params;
testRunner.log(`Intercepted: ${params.request.url}`);
respondWithRedirct(params, 'http://test-url/final');
params = (await dp.Network.onceRequestIntercepted()).params;
testRunner.log(`Intercepted: ${params.request.url}`);
respond(params, ['HTTP/1.1 200 OK', 'Content-Type: text/html'], '<body>Hello, world!</body>');
await dp.Page.onceLifecycleEvent(event => event.params.name === 'load');
const body = await session.evaluate('document.body.textContent');
testRunner.log(`Response body: ${body}`);
testRunner.completeTest();
function respond(params, headers, body) {
const headersText = headers.join("\r\n");
const response = headersText + "\r\n\r\n" + (body || "");
dp.Network.continueInterceptedRequest({interceptionId: params.interceptionId, rawResponse: btoa(response)});
}
function respondWithRedirct(params, url) {
testRunner.log(`Redirecting to ${url}`);
respond(params, ['HTTP/1.1 302 Moved', `Location: ${url}`], null);
}
})
......@@ -11,8 +11,8 @@ Network.requestIntercepted ID 2 GET redirect1.pl type: Script
allowRequest ID 2
Network.requestIntercepted ID 2 307 redirect redirect1.pl -> redirect2.pl
allowRequest ID 2
Network.requestIntercepted ID 2 302 redirect redirect2.pl -> redirect3.pl
blockRequest ID 2 AddressUnreachable
Network.requestIntercepted ID 3 GET redirect2.pl type: Script
blockRequest ID 3 AddressUnreachable
Network.loadingFailed redirect2.pl net::ERR_ADDRESS_UNREACHABLE
Page.frameStoppedLoading
......@@ -11,10 +11,16 @@ Network.requestIntercepted ID 2 GET redirect1.pl type: Script
allowRequest ID 2
Network.requestIntercepted ID 2 307 redirect redirect1.pl -> redirect2.pl
allowRequest ID 2
Network.requestIntercepted ID 2 302 redirect redirect2.pl -> redirect3.pl
allowRequest ID 2
Network.requestIntercepted ID 2 301 redirect redirect3.pl -> final.js
allowRequest ID 2
Network.requestIntercepted ID 3 GET redirect2.pl type: Script
allowRequest ID 3
Network.requestIntercepted ID 3 302 redirect redirect2.pl -> redirect3.pl
allowRequest ID 3
Network.requestIntercepted ID 4 GET redirect3.pl type: Script
allowRequest ID 4
Network.requestIntercepted ID 4 301 redirect redirect3.pl -> final.js
allowRequest ID 4
Network.requestIntercepted ID 5 GET final.js type: Script
allowRequest ID 5
Network.responseReceived final.js 200 application/x-javascript
Page.frameStoppedLoading
Hello from final.js!
......
......@@ -11,10 +11,12 @@ Network.requestIntercepted ID 2 GET redirect1.pl type: Script
allowRequest ID 2
Network.requestIntercepted ID 2 307 redirect redirect1.pl -> redirect2.pl
allowRequest ID 2
Network.requestIntercepted ID 2 302 redirect redirect2.pl -> redirect3.pl
allowRequest ID 2
Network.requestIntercepted ID 2 301 redirect redirect3.pl -> final.js
mockResponse ID 2
Network.requestIntercepted ID 3 GET redirect2.pl type: Script
allowRequest ID 3
Network.requestIntercepted ID 3 302 redirect redirect2.pl -> redirect3.pl
allowRequest ID 3
Network.requestIntercepted ID 4 GET redirect3.pl type: Script
mockResponse ID 4
Network.responseReceived redirect3.pl 200 application/javascript
Page.frameStoppedLoading
Hello from the mock resource
......
......@@ -11,11 +11,13 @@ Network.requestIntercepted ID 2 GET redirect1.pl type: Script
allowRequest ID 2
Network.requestIntercepted ID 2 307 redirect redirect1.pl -> redirect2.pl
allowRequest ID 2
Network.requestIntercepted ID 2 302 redirect redirect2.pl -> redirect3.pl
allowRequest ID 2
Network.requestIntercepted ID 2 301 redirect redirect3.pl -> final.js
modifyRequest ID 2: url final.js -> alternative.js
Network.responseReceived alternative.js 200 application/x-javascript
Network.requestIntercepted ID 3 GET redirect2.pl type: Script
allowRequest ID 3
Network.requestIntercepted ID 3 302 redirect redirect2.pl -> redirect3.pl
allowRequest ID 3
Network.requestIntercepted ID 4 GET redirect3.pl type: Script
modifyRequest ID 4: url redirect3.pl -> alternative.js
Network.responseReceived redirect3.pl 200 application/x-javascript
Page.frameStoppedLoading
Hello from alternative.js!
......@@ -10,6 +10,7 @@
'redirect1.pl': event => helper.allowRequest(event),
'redirect2.pl': event => helper.allowRequest(event),
'redirect3.pl': event => helper.modifyRequest(event, {url: 'alternative.js'}),
'alternative.js': event => helper.allowRequest(event)
};
await helper.startInterceptionTest(requestInterceptedDict, 1);
......
......@@ -9,6 +9,8 @@ allowRequest ID 1
Network.responseReceived redirect-iframe.html 200 text/html
Network.requestIntercepted ID 2 GET redirect1.pl type: Script
mockResponse ID 2
Network.requestIntercepted ID 3 GET final.js type: Script
allowRequest ID 3
Network.responseReceived final.js 200 application/x-javascript
Page.frameStoppedLoading
Hello from final.js!
......
......@@ -5,10 +5,9 @@ Request Intercepted: redirect1.php
responseErrorReason: undefined
responseStatusCode: undefined
responseHeaders: <None>
Continuing a request to http://127.0.0.1:8000/inspector-protocol/resources/redirect1.php
responseBody:
Error<Can only get response body on requests captured after headers received.>
Continuing redirect1.php request.
Request Intercepted: redirect1.php
responseErrorReason: undefined
responseStatusCode: 307
......@@ -24,10 +23,16 @@ Request Intercepted: redirect1.php
Pragma: no-cache
Server: <Masked>
redirectUrl: redirect2.php
Continuing a request to http://127.0.0.1:8000/inspector-protocol/resources/redirect1.php
responseBody:
Error<Can only get response body on requests captured after headers received.>
Request Intercepted: redirect2.php
responseErrorReason: undefined
responseStatusCode: undefined
responseHeaders: <None>
Continuing a request to http://127.0.0.1:8000/inspector-protocol/resources/redirect2.php
responseBody:
Error<Can only get response body on requests captured after headers received.>
Continuing redirect1.php and allow to redirect to redirect2.php.
Request Intercepted: redirect2.php
responseErrorReason: undefined
responseStatusCode: 307
......@@ -43,25 +48,16 @@ Request Intercepted: redirect2.php
Pragma: no-cache
Server: <Masked>
redirectUrl: final.html
Continuing a request to http://127.0.0.1:8000/inspector-protocol/resources/redirect2.php
responseBody:
Error<Can only get response body on requests captured after headers received.>
Continuing redriect2.php and allow to redirect to final.html.
Request Intercepted: final.html
responseErrorReason: undefined
responseStatusCode: 200
responseHeaders:
Accept-Ranges: bytes
Connection: Keep-Alive
Content-Length: 56
Content-Type: text/html
Date: <Masked>
ETag: <Masked>
Keep-Alive: <Masked>
Last-Modified: <Masked>
Server: <Masked>
responseStatusCode: undefined
responseHeaders: <None>
Continuing a request to http://127.0.0.1:8000/inspector-protocol/resources/final.html
responseBody:
<html><body>This is the final destination.</body></html>
Error<Can only get response body on requests captured after headers received.>
Modifying final.html's response after we receive response.
Modifying request with new body.
......
......@@ -20,30 +20,17 @@
session.evaluate(`fetch('${testRunner.url('../resources/redirect1.php')}')`);
// Should be redirect1.php as request.
var interceptionEvent = await waitForInterceptionEvent();
await logInterceptionEvent(interceptionEvent);
testRunner.log('Continuing redirect1.php request.');
testRunner.log('');
session.protocol.Network.continueInterceptedRequest({interceptionId: interceptionEvent.params.interceptionId});
await waitForInterceptionEventAndContinue("/redirect1.php");
await waitForInterceptionEventAndContinue("/redirect1.php");
// Should be redirect1.php as redirect going to redirect2.php.
interceptionEvent = await waitForInterceptionEvent();
await logInterceptionEvent(interceptionEvent);
testRunner.log('Continuing redirect1.php and allow to redirect to redirect2.php.');
testRunner.log('');
session.protocol.Network.continueInterceptedRequest({interceptionId: interceptionEvent.params.interceptionId});
// Should be redirect2.php as redirecting to final.html.
interceptionEvent = await waitForInterceptionEvent();
await logInterceptionEvent(interceptionEvent);
testRunner.log('Continuing redriect2.php and allow to redirect to final.html.');
testRunner.log('');
session.protocol.Network.continueInterceptedRequest({interceptionId: interceptionEvent.params.interceptionId});
await waitForInterceptionEventAndContinue("/redirect2.php");
await waitForInterceptionEventAndContinue("/redirect2.php");
// Should be final.html as response.
interceptionEvent = await waitForInterceptionEvent();
await logInterceptionEvent(interceptionEvent);
// Should be final.html as request.
await waitForInterceptionEventAndContinue("/final.html");
const interceptionEvent = await waitForInterceptionEvent("/final.html");
testRunner.log('Modifying final.html\'s response after we receive response.');
var body = '<html>\n<body>This content was rewritten!</body>\n</html>';
var dummyHeaders = [
......@@ -91,14 +78,24 @@
});
}
function waitForInterceptionEvent() {
return new Promise(resolve => {
session.protocol.Network.onRequestIntercepted(onInterception);
function onInterception(event) {
session.protocol.Network.removeEventListener(onInterception);
resolve(event);
}
});
async function waitForInterceptionEvent(expectedUrlSuffix) {
const event = await session.protocol.Network.onceRequestIntercepted();
const url = event.params.request.url;
if (!url.endsWith(expectedUrlSuffix)) {
testRunner.log(`FAIL: expected url ending with "${expectedUrlSuffix}", got "${url}"`);
testRunner.completeTest();
return null;
}
return event;
}
async function waitForInterceptionEventAndContinue(expectedUrlSuffix) {
const event = await waitForInterceptionEvent(expectedUrlSuffix);
if (!event)
return;
logInterceptionEvent(event);
testRunner.log(`Continuing a request to ${event.params.request.url}`);
session.protocol.Network.continueInterceptedRequest({interceptionId: event.params.interceptionId});
}
function waitForResponseReceivedEvent(fileName) {
......
......@@ -79,7 +79,8 @@
this._log(id, 'Auth required for ' + id);
requestInterceptedDict[filename + '+Auth'](event);
return;
} else if (event.params.hasOwnProperty('redirectUrl')) {
}
if (event.params.hasOwnProperty('redirectUrl')) {
var errorReason = '';
if (event.params.responseErrorReason)
errorReason = event.params.responseErrorReason + ' ';
......
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