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( ...@@ -566,7 +566,6 @@ DevToolsURLInterceptorRequestJob::DevToolsURLInterceptorRequestJob(
net::NetworkDelegate* original_network_delegate, net::NetworkDelegate* original_network_delegate,
const base::UnguessableToken& devtools_token, const base::UnguessableToken& devtools_token,
DevToolsNetworkInterceptor::RequestInterceptedCallback callback, DevToolsNetworkInterceptor::RequestInterceptedCallback callback,
bool is_redirect,
ResourceType resource_type, ResourceType resource_type,
InterceptionStage stage_to_intercept) InterceptionStage stage_to_intercept)
: net::URLRequestJob(original_request, original_network_delegate), : net::URLRequestJob(original_request, original_network_delegate),
...@@ -584,7 +583,6 @@ DevToolsURLInterceptorRequestJob::DevToolsURLInterceptorRequestJob( ...@@ -584,7 +583,6 @@ DevToolsURLInterceptorRequestJob::DevToolsURLInterceptorRequestJob(
owning_entry_id_(owning_entry_id), owning_entry_id_(owning_entry_id),
devtools_token_(devtools_token), devtools_token_(devtools_token),
callback_(callback), callback_(callback),
is_redirect_(is_redirect),
resource_type_(resource_type), resource_type_(resource_type),
stage_to_intercept_(stage_to_intercept), stage_to_intercept_(stage_to_intercept),
weak_ptr_factory_(this) { weak_ptr_factory_(this) {
...@@ -635,26 +633,6 @@ void DevToolsURLInterceptorRequestJob::StartWithCookies( ...@@ -635,26 +633,6 @@ void DevToolsURLInterceptorRequestJob::StartWithCookies(
return; 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) { if (stage_to_intercept_ == InterceptionStage::RESPONSE) {
// We are only a response interception, we go right to dispatching the // We are only a response interception, we go right to dispatching the
// request. // request.
...@@ -1045,7 +1023,6 @@ void DevToolsURLInterceptorRequestJob::ProcessRedirect( ...@@ -1045,7 +1023,6 @@ void DevToolsURLInterceptorRequestJob::ProcessRedirect(
base::MakeRefCounted<net::HttpResponseHeaders>(raw_headers), "", 0, base::MakeRefCounted<net::HttpResponseHeaders>(raw_headers), "", 0,
base::TimeTicks::Now())); base::TimeTicks::Now()));
interceptor_->ExpectRequestAfterRedirect(request(), interception_id_);
NotifyHeadersComplete(); NotifyHeadersComplete();
} }
...@@ -1124,11 +1101,6 @@ void DevToolsURLInterceptorRequestJob::ProcessInterceptionResponse( ...@@ -1124,11 +1101,6 @@ void DevToolsURLInterceptorRequestJob::ProcessInterceptionResponse(
mock_response_details_.reset(new MockResponseDetails( mock_response_details_.reset(new MockResponseDetails(
std::move(*modifications->raw_response), base::TimeTicks::Now())); 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. // Set cookies in the network stack.
net::CookieOptions options; net::CookieOptions options;
options.set_include_httponly(); options.set_include_httponly();
......
...@@ -37,7 +37,6 @@ class DevToolsURLInterceptorRequestJob : public net::URLRequestJob { ...@@ -37,7 +37,6 @@ class DevToolsURLInterceptorRequestJob : public net::URLRequestJob {
net::NetworkDelegate* original_network_delegate, net::NetworkDelegate* original_network_delegate,
const base::UnguessableToken& devtools_token, const base::UnguessableToken& devtools_token,
DevToolsNetworkInterceptor::RequestInterceptedCallback callback, DevToolsNetworkInterceptor::RequestInterceptedCallback callback,
bool is_redirect,
ResourceType resource_type, ResourceType resource_type,
DevToolsNetworkInterceptor::InterceptionStage stage_to_intercept); DevToolsNetworkInterceptor::InterceptionStage stage_to_intercept);
...@@ -157,7 +156,6 @@ class DevToolsURLInterceptorRequestJob : public net::URLRequestJob { ...@@ -157,7 +156,6 @@ class DevToolsURLInterceptorRequestJob : public net::URLRequestJob {
const intptr_t owning_entry_id_; const intptr_t owning_entry_id_;
const base::UnguessableToken devtools_token_; const base::UnguessableToken devtools_token_;
DevToolsNetworkInterceptor::RequestInterceptedCallback callback_; DevToolsNetworkInterceptor::RequestInterceptedCallback callback_;
const bool is_redirect_;
const ResourceType resource_type_; const ResourceType resource_type_;
InterceptionStage stage_to_intercept_; InterceptionStage stage_to_intercept_;
std::vector<std::unique_ptr<GetResponseBodyForInterceptionCallback>> std::vector<std::unique_ptr<GetResponseBodyForInterceptionCallback>>
......
...@@ -252,8 +252,9 @@ class InterceptionJob : public network::mojom::URLLoaderClient, ...@@ -252,8 +252,9 @@ class InterceptionJob : public network::mojom::URLLoaderClient,
void OnComplete(const network::URLLoaderCompletionStatus& status) override; void OnComplete(const network::URLLoaderCompletionStatus& status) override;
bool CanGetResponseBody(std::string* error_reason); bool CanGetResponseBody(std::string* error_reason);
void UpdateIdAndRegister();
const std::string id_; const std::string id_prefix_;
const GlobalRequestId global_req_id_; const GlobalRequestId global_req_id_;
const base::UnguessableToken frame_token_; const base::UnguessableToken frame_token_;
const base::TimeTicks start_ticks_; const base::TimeTicks start_ticks_;
...@@ -277,6 +278,7 @@ class InterceptionJob : public network::mojom::URLLoaderClient, ...@@ -277,6 +278,7 @@ class InterceptionJob : public network::mojom::URLLoaderClient,
kNotStarted, kNotStarted,
kRequestSent, kRequestSent,
kRedirectReceived, kRedirectReceived,
kFollowRedirect,
kAuthRequired, kAuthRequired,
kResponseReceived, kResponseReceived,
kResponseTaken, kResponseTaken,
...@@ -284,6 +286,8 @@ class InterceptionJob : public network::mojom::URLLoaderClient, ...@@ -284,6 +286,8 @@ class InterceptionJob : public network::mojom::URLLoaderClient,
State state_; State state_;
bool waiting_for_resolution_; bool waiting_for_resolution_;
int redirect_count_;
std::string current_id_;
std::unique_ptr<BodyReader> body_reader_; std::unique_ptr<BodyReader> body_reader_;
std::unique_ptr<ResponseMetadata> response_metadata_; std::unique_ptr<ResponseMetadata> response_metadata_;
...@@ -320,11 +324,11 @@ class DevToolsURLLoaderInterceptor::Impl ...@@ -320,11 +324,11 @@ class DevToolsURLLoaderInterceptor::Impl
static int last_id = 0; static int last_id = 0;
std::string id = base::StringPrintf("interception-job-%d", ++last_id); std::string id = base::StringPrintf("interception-job-%d", ++last_id);
InterceptionJob* job = new InterceptionJob( // This class will manage its own life time to match the loader client.
this, id, frame_token, process_id, std::move(create_params), new InterceptionJob(this, std::move(id), frame_token, process_id,
is_download, std::move(loader_request), std::move(client), std::move(create_params), is_download,
std::move(target_factory)); std::move(loader_request), std::move(client),
jobs_.emplace(std::move(id), job); std::move(target_factory));
} }
void SetPatterns(std::vector<DevToolsNetworkInterceptor::Pattern> patterns) { void SetPatterns(std::vector<DevToolsNetworkInterceptor::Pattern> patterns) {
...@@ -392,6 +396,9 @@ class DevToolsURLLoaderInterceptor::Impl ...@@ -392,6 +396,9 @@ class DevToolsURLLoaderInterceptor::Impl
} }
void RemoveJob(const std::string& id) { jobs_.erase(id); } 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_; std::map<std::string, InterceptionJob*> jobs_;
RequestInterceptedCallback request_intercepted_callback_; RequestInterceptedCallback request_intercepted_callback_;
...@@ -627,7 +634,7 @@ InterceptionJob::InterceptionJob( ...@@ -627,7 +634,7 @@ InterceptionJob::InterceptionJob(
network::mojom::URLLoaderRequest loader_request, network::mojom::URLLoaderRequest loader_request,
network::mojom::URLLoaderClientPtr client, network::mojom::URLLoaderClientPtr client,
network::mojom::URLLoaderFactoryPtr target_factory) network::mojom::URLLoaderFactoryPtr target_factory)
: id_(std::move(id)), : id_prefix_(id),
global_req_id_( global_req_id_(
std::make_tuple(process_id, std::make_tuple(process_id,
create_loader_params->request.render_frame_id, create_loader_params->request.render_frame_id,
...@@ -644,7 +651,9 @@ InterceptionJob::InterceptionJob( ...@@ -644,7 +651,9 @@ InterceptionJob::InterceptionJob(
client_(std::move(client)), client_(std::move(client)),
target_factory_(std::move(target_factory)), target_factory_(std::move(target_factory)),
state_(kNotStarted), state_(kNotStarted),
waiting_for_resolution_(false) { waiting_for_resolution_(false),
redirect_count_(0) {
UpdateIdAndRegister();
const network::ResourceRequest& request = create_loader_params_->request; const network::ResourceRequest& request = create_loader_params_->request;
stage_ = interceptor_->GetInterceptionStage( stage_ = interceptor_->GetInterceptionStage(
request.url, static_cast<ResourceType>(request.resource_type)); request.url, static_cast<ResourceType>(request.resource_type));
...@@ -665,6 +674,11 @@ InterceptionJob::InterceptionJob( ...@@ -665,6 +674,11 @@ InterceptionJob::InterceptionJob(
StartRequest(); 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) { bool InterceptionJob::CanGetResponseBody(std::string* error_reason) {
if (!(stage_ & InterceptionStage::RESPONSE)) { if (!(stage_ & InterceptionStage::RESPONSE)) {
*error_reason = *error_reason =
...@@ -786,6 +800,18 @@ Response InterceptionJob::InnerContinueRequest( ...@@ -786,6 +800,18 @@ Response InterceptionJob::InnerContinueRequest(
if (modifications->raw_response) if (modifications->raw_response)
return ProcessResponseOverride(*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) { if (state_ == State::kRedirectReceived) {
// TODO(caseq): report error if other modifications are present. // TODO(caseq): report error if other modifications are present.
if (modifications->modified_url.isJust()) { if (modifications->modified_url.isJust()) {
...@@ -1037,7 +1063,7 @@ void InterceptionJob::CancelRequest() { ...@@ -1037,7 +1063,7 @@ void InterceptionJob::CancelRequest() {
std::unique_ptr<InterceptedRequestInfo> InterceptionJob::BuildRequestInfo( std::unique_ptr<InterceptedRequestInfo> InterceptionJob::BuildRequestInfo(
const network::ResourceResponseHead* head) { const network::ResourceResponseHead* head) {
auto result = std::make_unique<InterceptedRequestInfo>(); auto result = std::make_unique<InterceptedRequestInfo>();
result->interception_id = id_; result->interception_id = current_id_;
result->network_request = result->network_request =
protocol::NetworkHandler::CreateRequestFromResourceRequest( protocol::NetworkHandler::CreateRequestFromResourceRequest(
create_loader_params_->request); create_loader_params_->request);
...@@ -1078,7 +1104,7 @@ void InterceptionJob::NotifyClient( ...@@ -1078,7 +1104,7 @@ void InterceptionJob::NotifyClient(
void InterceptionJob::Shutdown() { void InterceptionJob::Shutdown() {
if (interceptor_) if (interceptor_)
interceptor_->RemoveJob(id_); interceptor_->RemoveJob(current_id_);
delete this; delete this;
} }
...@@ -1100,9 +1126,24 @@ void InterceptionJob::FollowRedirect( ...@@ -1100,9 +1126,24 @@ void InterceptionJob::FollowRedirect(
request->referrer_policy = info.new_referrer_policy; request->referrer_policy = info.new_referrer_policy;
request->referrer = GURL(info.new_referrer); request->referrer = GURL(info.new_referrer);
response_metadata_.reset(); response_metadata_.reset();
if (interceptor_) { 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( stage_ = interceptor_->GetInterceptionStage(
request->url, static_cast<ResourceType>(request->resource_type)); 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) { if (state_ == State::kRedirectReceived) {
state_ = State::kRequestSent; state_ = State::kRequestSent;
......
...@@ -141,8 +141,7 @@ net::URLRequestJob* DevToolsURLRequestInterceptor::InnerMaybeInterceptRequest( ...@@ -141,8 +141,7 @@ net::URLRequestJob* DevToolsURLRequestInterceptor::InnerMaybeInterceptRequest(
return nullptr; return nullptr;
DCHECK(interception_stage != DONT_INTERCEPT); DCHECK(interception_stage != DONT_INTERCEPT);
bool is_redirect; std::string interception_id = base::StringPrintf("id-%zu", ++next_id_);
std::string interception_id = GetIdForRequest(request, &is_redirect);
if (IsNavigationRequest(resource_type)) { if (IsNavigationRequest(resource_type)) {
BrowserThread::PostTask( BrowserThread::PostTask(
...@@ -155,8 +154,7 @@ net::URLRequestJob* DevToolsURLRequestInterceptor::InnerMaybeInterceptRequest( ...@@ -155,8 +154,7 @@ net::URLRequestJob* DevToolsURLRequestInterceptor::InnerMaybeInterceptRequest(
DevToolsURLInterceptorRequestJob* job = new DevToolsURLInterceptorRequestJob( DevToolsURLInterceptorRequestJob* job = new DevToolsURLInterceptorRequestJob(
this, interception_id, reinterpret_cast<intptr_t>(entry), request, this, interception_id, reinterpret_cast<intptr_t>(entry), request,
network_delegate, target_info->devtools_token, entry->callback, network_delegate, target_info->devtools_token, entry->callback,
is_redirect, resource_request_info->GetResourceType(), resource_request_info->GetResourceType(), interception_stage);
interception_stage);
interception_id_to_job_map_[interception_id] = job; interception_id_to_job_map_[interception_id] = job;
return job; return job;
} }
...@@ -261,28 +259,6 @@ void DevToolsURLRequestInterceptor::UnregisterSubRequest( ...@@ -261,28 +259,6 @@ void DevToolsURLRequestInterceptor::UnregisterSubRequest(
sub_requests_.erase(sub_request); 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( DevToolsURLInterceptorRequestJob* DevToolsURLRequestInterceptor::GetJob(
const std::string& interception_id) const { const std::string& interception_id) const {
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
......
...@@ -66,10 +66,6 @@ class DevToolsURLRequestInterceptor : public net::URLRequestInterceptor, ...@@ -66,10 +66,6 @@ class DevToolsURLRequestInterceptor : public net::URLRequestInterceptor,
// Registers a |sub_request| that should not be intercepted. // Registers a |sub_request| that should not be intercepted.
void RegisterSubRequest(const net::URLRequest* sub_request); void RegisterSubRequest(const net::URLRequest* sub_request);
void UnregisterSubRequest(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); void JobFinished(const std::string& interception_id, bool is_navigation);
private: private:
...@@ -85,8 +81,6 @@ class DevToolsURLRequestInterceptor : public net::URLRequestInterceptor, ...@@ -85,8 +81,6 @@ class DevToolsURLRequestInterceptor : public net::URLRequestInterceptor,
const DevToolsTargetRegistry::TargetInfo* TargetInfoForRequestInfo( const DevToolsTargetRegistry::TargetInfo* TargetInfoForRequestInfo(
const ResourceRequestInfo* request_info) const; const ResourceRequestInfo* request_info) const;
std::string GetIdForRequest(const net::URLRequest* request,
bool* is_redirect);
// Returns a WeakPtr to the DevToolsURLInterceptorRequestJob corresponding // Returns a WeakPtr to the DevToolsURLInterceptorRequestJob corresponding
// to |interception_id|. // to |interception_id|.
DevToolsURLInterceptorRequestJob* GetJob( DevToolsURLInterceptorRequestJob* GetJob(
...@@ -107,9 +101,6 @@ class DevToolsURLRequestInterceptor : public net::URLRequestInterceptor, ...@@ -107,9 +101,6 @@ class DevToolsURLRequestInterceptor : public net::URLRequestInterceptor,
// requests. // requests.
base::flat_set<const net::URLRequest*> sub_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_; size_t next_id_;
base::WeakPtrFactory<DevToolsURLRequestInterceptor> weak_factory_; 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 ...@@ -11,8 +11,8 @@ Network.requestIntercepted ID 2 GET redirect1.pl type: Script
allowRequest ID 2 allowRequest ID 2
Network.requestIntercepted ID 2 307 redirect redirect1.pl -> redirect2.pl Network.requestIntercepted ID 2 307 redirect redirect1.pl -> redirect2.pl
allowRequest ID 2 allowRequest ID 2
Network.requestIntercepted ID 2 302 redirect redirect2.pl -> redirect3.pl Network.requestIntercepted ID 3 GET redirect2.pl type: Script
blockRequest ID 2 AddressUnreachable blockRequest ID 3 AddressUnreachable
Network.loadingFailed redirect2.pl net::ERR_ADDRESS_UNREACHABLE Network.loadingFailed redirect2.pl net::ERR_ADDRESS_UNREACHABLE
Page.frameStoppedLoading Page.frameStoppedLoading
...@@ -11,10 +11,16 @@ Network.requestIntercepted ID 2 GET redirect1.pl type: Script ...@@ -11,10 +11,16 @@ Network.requestIntercepted ID 2 GET redirect1.pl type: Script
allowRequest ID 2 allowRequest ID 2
Network.requestIntercepted ID 2 307 redirect redirect1.pl -> redirect2.pl Network.requestIntercepted ID 2 307 redirect redirect1.pl -> redirect2.pl
allowRequest ID 2 allowRequest ID 2
Network.requestIntercepted ID 2 302 redirect redirect2.pl -> redirect3.pl Network.requestIntercepted ID 3 GET redirect2.pl type: Script
allowRequest ID 2 allowRequest ID 3
Network.requestIntercepted ID 2 301 redirect redirect3.pl -> final.js Network.requestIntercepted ID 3 302 redirect redirect2.pl -> redirect3.pl
allowRequest ID 2 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 Network.responseReceived final.js 200 application/x-javascript
Page.frameStoppedLoading Page.frameStoppedLoading
Hello from final.js! Hello from final.js!
......
...@@ -11,10 +11,12 @@ Network.requestIntercepted ID 2 GET redirect1.pl type: Script ...@@ -11,10 +11,12 @@ Network.requestIntercepted ID 2 GET redirect1.pl type: Script
allowRequest ID 2 allowRequest ID 2
Network.requestIntercepted ID 2 307 redirect redirect1.pl -> redirect2.pl Network.requestIntercepted ID 2 307 redirect redirect1.pl -> redirect2.pl
allowRequest ID 2 allowRequest ID 2
Network.requestIntercepted ID 2 302 redirect redirect2.pl -> redirect3.pl Network.requestIntercepted ID 3 GET redirect2.pl type: Script
allowRequest ID 2 allowRequest ID 3
Network.requestIntercepted ID 2 301 redirect redirect3.pl -> final.js Network.requestIntercepted ID 3 302 redirect redirect2.pl -> redirect3.pl
mockResponse ID 2 allowRequest ID 3
Network.requestIntercepted ID 4 GET redirect3.pl type: Script
mockResponse ID 4
Network.responseReceived redirect3.pl 200 application/javascript Network.responseReceived redirect3.pl 200 application/javascript
Page.frameStoppedLoading Page.frameStoppedLoading
Hello from the mock resource Hello from the mock resource
......
...@@ -11,11 +11,13 @@ Network.requestIntercepted ID 2 GET redirect1.pl type: Script ...@@ -11,11 +11,13 @@ Network.requestIntercepted ID 2 GET redirect1.pl type: Script
allowRequest ID 2 allowRequest ID 2
Network.requestIntercepted ID 2 307 redirect redirect1.pl -> redirect2.pl Network.requestIntercepted ID 2 307 redirect redirect1.pl -> redirect2.pl
allowRequest ID 2 allowRequest ID 2
Network.requestIntercepted ID 2 302 redirect redirect2.pl -> redirect3.pl Network.requestIntercepted ID 3 GET redirect2.pl type: Script
allowRequest ID 2 allowRequest ID 3
Network.requestIntercepted ID 2 301 redirect redirect3.pl -> final.js Network.requestIntercepted ID 3 302 redirect redirect2.pl -> redirect3.pl
modifyRequest ID 2: url final.js -> alternative.js allowRequest ID 3
Network.responseReceived alternative.js 200 application/x-javascript 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 Page.frameStoppedLoading
Hello from alternative.js! Hello from alternative.js!
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
'redirect1.pl': event => helper.allowRequest(event), 'redirect1.pl': event => helper.allowRequest(event),
'redirect2.pl': event => helper.allowRequest(event), 'redirect2.pl': event => helper.allowRequest(event),
'redirect3.pl': event => helper.modifyRequest(event, {url: 'alternative.js'}), 'redirect3.pl': event => helper.modifyRequest(event, {url: 'alternative.js'}),
'alternative.js': event => helper.allowRequest(event)
}; };
await helper.startInterceptionTest(requestInterceptedDict, 1); await helper.startInterceptionTest(requestInterceptedDict, 1);
......
...@@ -9,6 +9,8 @@ allowRequest ID 1 ...@@ -9,6 +9,8 @@ allowRequest ID 1
Network.responseReceived redirect-iframe.html 200 text/html Network.responseReceived redirect-iframe.html 200 text/html
Network.requestIntercepted ID 2 GET redirect1.pl type: Script Network.requestIntercepted ID 2 GET redirect1.pl type: Script
mockResponse ID 2 mockResponse ID 2
Network.requestIntercepted ID 3 GET final.js type: Script
allowRequest ID 3
Network.responseReceived final.js 200 application/x-javascript Network.responseReceived final.js 200 application/x-javascript
Page.frameStoppedLoading Page.frameStoppedLoading
Hello from final.js! Hello from final.js!
......
...@@ -5,10 +5,9 @@ Request Intercepted: redirect1.php ...@@ -5,10 +5,9 @@ Request Intercepted: redirect1.php
responseErrorReason: undefined responseErrorReason: undefined
responseStatusCode: undefined responseStatusCode: undefined
responseHeaders: <None> responseHeaders: <None>
Continuing a request to http://127.0.0.1:8000/inspector-protocol/resources/redirect1.php
responseBody: responseBody:
Error<Can only get response body on requests captured after headers received.> Error<Can only get response body on requests captured after headers received.>
Continuing redirect1.php request.
Request Intercepted: redirect1.php Request Intercepted: redirect1.php
responseErrorReason: undefined responseErrorReason: undefined
responseStatusCode: 307 responseStatusCode: 307
...@@ -24,10 +23,16 @@ Request Intercepted: redirect1.php ...@@ -24,10 +23,16 @@ Request Intercepted: redirect1.php
Pragma: no-cache Pragma: no-cache
Server: <Masked> Server: <Masked>
redirectUrl: redirect2.php 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: responseBody:
Error<Can only get response body on requests captured after headers received.> 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 Request Intercepted: redirect2.php
responseErrorReason: undefined responseErrorReason: undefined
responseStatusCode: 307 responseStatusCode: 307
...@@ -43,25 +48,16 @@ Request Intercepted: redirect2.php ...@@ -43,25 +48,16 @@ Request Intercepted: redirect2.php
Pragma: no-cache Pragma: no-cache
Server: <Masked> Server: <Masked>
redirectUrl: final.html redirectUrl: final.html
Continuing a request to http://127.0.0.1:8000/inspector-protocol/resources/redirect2.php
responseBody: responseBody:
Error<Can only get response body on requests captured after headers received.> 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 Request Intercepted: final.html
responseErrorReason: undefined responseErrorReason: undefined
responseStatusCode: 200 responseStatusCode: undefined
responseHeaders: responseHeaders: <None>
Accept-Ranges: bytes Continuing a request to http://127.0.0.1:8000/inspector-protocol/resources/final.html
Connection: Keep-Alive
Content-Length: 56
Content-Type: text/html
Date: <Masked>
ETag: <Masked>
Keep-Alive: <Masked>
Last-Modified: <Masked>
Server: <Masked>
responseBody: 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 final.html's response after we receive response.
Modifying request with new body. Modifying request with new body.
......
...@@ -20,30 +20,17 @@ ...@@ -20,30 +20,17 @@
session.evaluate(`fetch('${testRunner.url('../resources/redirect1.php')}')`); session.evaluate(`fetch('${testRunner.url('../resources/redirect1.php')}')`);
// Should be redirect1.php as request. await waitForInterceptionEventAndContinue("/redirect1.php");
var interceptionEvent = await waitForInterceptionEvent(); await waitForInterceptionEventAndContinue("/redirect1.php");
await logInterceptionEvent(interceptionEvent);
testRunner.log('Continuing redirect1.php request.');
testRunner.log('');
session.protocol.Network.continueInterceptedRequest({interceptionId: interceptionEvent.params.interceptionId});
// 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. // Should be redirect2.php as redirecting to final.html.
interceptionEvent = await waitForInterceptionEvent(); await waitForInterceptionEventAndContinue("/redirect2.php");
await logInterceptionEvent(interceptionEvent); await waitForInterceptionEventAndContinue("/redirect2.php");
testRunner.log('Continuing redriect2.php and allow to redirect to final.html.');
testRunner.log('');
session.protocol.Network.continueInterceptedRequest({interceptionId: interceptionEvent.params.interceptionId});
// Should be final.html as response. // Should be final.html as request.
interceptionEvent = await waitForInterceptionEvent(); await waitForInterceptionEventAndContinue("/final.html");
await logInterceptionEvent(interceptionEvent); const interceptionEvent = await waitForInterceptionEvent("/final.html");
testRunner.log('Modifying final.html\'s response after we receive response.'); testRunner.log('Modifying final.html\'s response after we receive response.');
var body = '<html>\n<body>This content was rewritten!</body>\n</html>'; var body = '<html>\n<body>This content was rewritten!</body>\n</html>';
var dummyHeaders = [ var dummyHeaders = [
...@@ -91,14 +78,24 @@ ...@@ -91,14 +78,24 @@
}); });
} }
function waitForInterceptionEvent() { async function waitForInterceptionEvent(expectedUrlSuffix) {
return new Promise(resolve => { const event = await session.protocol.Network.onceRequestIntercepted();
session.protocol.Network.onRequestIntercepted(onInterception); const url = event.params.request.url;
function onInterception(event) { if (!url.endsWith(expectedUrlSuffix)) {
session.protocol.Network.removeEventListener(onInterception); testRunner.log(`FAIL: expected url ending with "${expectedUrlSuffix}", got "${url}"`);
resolve(event); 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) { function waitForResponseReceivedEvent(fileName) {
......
...@@ -79,7 +79,8 @@ ...@@ -79,7 +79,8 @@
this._log(id, 'Auth required for ' + id); this._log(id, 'Auth required for ' + id);
requestInterceptedDict[filename + '+Auth'](event); requestInterceptedDict[filename + '+Auth'](event);
return; return;
} else if (event.params.hasOwnProperty('redirectUrl')) { }
if (event.params.hasOwnProperty('redirectUrl')) {
var errorReason = ''; var errorReason = '';
if (event.params.responseErrorReason) if (event.params.responseErrorReason)
errorReason = 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