| Index: content/browser/devtools/devtools_url_request_interceptor.cc
|
| diff --git a/content/browser/devtools/devtools_url_request_interceptor.cc b/content/browser/devtools/devtools_url_request_interceptor.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..138737ce4c0afaab1e552879d28db6804065589e
|
| --- /dev/null
|
| +++ b/content/browser/devtools/devtools_url_request_interceptor.cc
|
| @@ -0,0 +1,269 @@
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "content/browser/devtools/devtools_url_request_interceptor.h"
|
| +
|
| +#include "base/memory/ptr_util.h"
|
| +#include "base/strings/stringprintf.h"
|
| +#include "base/supports_user_data.h"
|
| +#include "content/browser/devtools/devtools_agent_host_impl.h"
|
| +#include "content/browser/devtools/devtools_url_interceptor_request_job.h"
|
| +#include "content/browser/devtools/protocol/network_handler.h"
|
| +#include "content/public/browser/browser_context.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| +#include "content/public/browser/devtools_agent_host.h"
|
| +#include "content/public/browser/resource_request_info.h"
|
| +#include "net/http/http_request_headers.h"
|
| +#include "net/url_request/url_request.h"
|
| +
|
| +namespace content {
|
| +
|
| +namespace {
|
| +const char kDevToolsURLRequestInterceptorKeyName[] =
|
| + "DevToolsURLRequestInterceptor";
|
| +
|
| +class DevToolsURLRequestInterceptorUserData
|
| + : public base::SupportsUserData::Data {
|
| + public:
|
| + explicit DevToolsURLRequestInterceptorUserData(
|
| + DevToolsURLRequestInterceptor* devtools_url_request_interceptor)
|
| + : devtools_url_request_interceptor_(devtools_url_request_interceptor) {}
|
| +
|
| + DevToolsURLRequestInterceptor* devtools_url_request_interceptor() const {
|
| + return devtools_url_request_interceptor_;
|
| + }
|
| +
|
| + private:
|
| + DevToolsURLRequestInterceptor* devtools_url_request_interceptor_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(DevToolsURLRequestInterceptorUserData);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +DevToolsURLRequestInterceptor::DevToolsURLRequestInterceptor(
|
| + BrowserContext* browser_context)
|
| + : browser_context_(browser_context), weak_ptr_factory_(this) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| + browser_context_->SetUserData(
|
| + kDevToolsURLRequestInterceptorKeyName,
|
| + base::MakeUnique<DevToolsURLRequestInterceptorUserData>(this));
|
| +
|
| + // The State object needs to be created on the IO thread or we can't use
|
| + // WeakPtr when posing tasks to run on the IO thread.
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO, FROM_HERE,
|
| + base::BindOnce(&DevToolsURLRequestInterceptor::CreateStateOnIoThread,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| +}
|
| +
|
| +DevToolsURLRequestInterceptor::~DevToolsURLRequestInterceptor() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + // The BrowserContext owns us, so we don't need to unregister
|
| + // DevToolsURLRequestInterceptorUserData explicitly.
|
| +}
|
| +
|
| +net::URLRequestJob* DevToolsURLRequestInterceptor::MaybeInterceptRequest(
|
| + net::URLRequest* request,
|
| + net::NetworkDelegate* network_delegate) const {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + base::WeakPtr<protocol::NetworkHandler> network_handler;
|
| + if (!state().ShouldInterceptRequest(request, &network_handler))
|
| + return nullptr;
|
| +
|
| + bool is_redirect;
|
| + return new DevToolsURLInterceptorRequestJob(
|
| + state().GetWeakPtr(), state().GetIdForRequest(request, &is_redirect),
|
| + request, network_delegate, network_handler, is_redirect);
|
| +}
|
| +
|
| +net::URLRequestJob* DevToolsURLRequestInterceptor::MaybeInterceptRedirect(
|
| + net::URLRequest* request,
|
| + net::NetworkDelegate* network_delegate,
|
| + const GURL& location) const {
|
| + return nullptr;
|
| +}
|
| +
|
| +net::URLRequestJob* DevToolsURLRequestInterceptor::MaybeInterceptResponse(
|
| + net::URLRequest* request,
|
| + net::NetworkDelegate* network_delegate) const {
|
| + return nullptr;
|
| +}
|
| +
|
| +void DevToolsURLRequestInterceptor::State::AllowRequest(
|
| + protocol::String interception_id,
|
| + CommandCallback callback) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + DevToolsURLInterceptorRequestJob* job = GetJob(interception_id);
|
| + if (!job) {
|
| + std::move(callback).Run(CommandStatus::UnknownInterceptionId);
|
| + } else {
|
| + std::move(callback).Run(job->AllowRequest());
|
| + }
|
| +}
|
| +
|
| +void DevToolsURLRequestInterceptor::State::BlockRequest(
|
| + protocol::String interception_id,
|
| + net::Error error_reason,
|
| + CommandCallback callback) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + DevToolsURLInterceptorRequestJob* job = GetJob(interception_id);
|
| + if (!job) {
|
| + std::move(callback).Run(CommandStatus::UnknownInterceptionId);
|
| + } else {
|
| + std::move(callback).Run(job->BlockRequest(error_reason));
|
| + }
|
| +}
|
| +
|
| +void DevToolsURLRequestInterceptor::State::ModifyRequest(
|
| + protocol::String interception_id,
|
| + std::unique_ptr<Modifications> modifications,
|
| + CommandCallback callback) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + DevToolsURLInterceptorRequestJob* job = GetJob(interception_id);
|
| + if (!job) {
|
| + std::move(callback).Run(CommandStatus::UnknownInterceptionId);
|
| + } else {
|
| + std::move(callback).Run(job->ModifyRequest(std::move(modifications)));
|
| + }
|
| +}
|
| +
|
| +void DevToolsURLRequestInterceptor::State::MockResponse(
|
| + protocol::String interception_id,
|
| + protocol::String raw_response,
|
| + CommandCallback callback) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + DevToolsURLInterceptorRequestJob* job = GetJob(interception_id);
|
| + if (!job) {
|
| + std::move(callback).Run(CommandStatus::UnknownInterceptionId);
|
| + } else {
|
| + std::move(callback).Run(job->MockResponse(std::move(raw_response)));
|
| + }
|
| +}
|
| +
|
| +DevToolsURLRequestInterceptor::State::State()
|
| + : next_id_(0), weak_ptr_factory_(this) {}
|
| +
|
| +DevToolsURLRequestInterceptor::State::~State() {}
|
| +
|
| +bool DevToolsURLRequestInterceptor::State::ShouldInterceptRequest(
|
| + const net::URLRequest* request,
|
| + base::WeakPtr<protocol::NetworkHandler>* network_handler) const {
|
| + const ResourceRequestInfo* resource_request_info =
|
| + ResourceRequestInfo::ForRequest(request);
|
| + if (!resource_request_info)
|
| + return false;
|
| + int frame_tree_node_id = resource_request_info->GetFrameTreeNodeId();
|
| + if (frame_tree_node_id == -1) {
|
| + // |frame_tree_node_id| is not set for renderer side requests, fall back to
|
| + // the RenderFrameID.
|
| + int render_frame_id = resource_request_info->GetRenderFrameID();
|
| + const auto find_it = intercepted_render_frames_.find(render_frame_id);
|
| + if (find_it == intercepted_render_frames_.end())
|
| + return false;
|
| + *network_handler = find_it->second;
|
| + } else {
|
| + // |frame_tree_node_id| is set for browser side navigations, so use that
|
| + // because the RenderFrameID isn't known.
|
| + const auto find_it = intercepted_frame_tree_nodes_.find(frame_tree_node_id);
|
| + if (find_it == intercepted_frame_tree_nodes_.end())
|
| + return false;
|
| + *network_handler = find_it->second;
|
| + }
|
| +
|
| + // We don't want to intercept our own sub requests.
|
| + return sub_requests_.find(request) == sub_requests_.end();
|
| +}
|
| +
|
| +void DevToolsURLRequestInterceptor::State::StartInterceptingRequestsFrom(
|
| + int render_frame_id,
|
| + int frame_tree_node_id,
|
| + base::WeakPtr<protocol::NetworkHandler> network_handler) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + intercepted_render_frames_[render_frame_id] = network_handler;
|
| + intercepted_frame_tree_nodes_[frame_tree_node_id] = network_handler;
|
| +}
|
| +
|
| +void DevToolsURLRequestInterceptor::State::StopInterceptingRequestsFrom(
|
| + int render_frame_id,
|
| + int frame_tree_node_id) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + intercepted_render_frames_.erase(render_frame_id);
|
| + intercepted_frame_tree_nodes_.erase(frame_tree_node_id);
|
| +}
|
| +
|
| +void DevToolsURLRequestInterceptor::State::RegisterSubRequest(
|
| + const net::URLRequest* sub_request) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + DCHECK(sub_requests_.find(sub_request) == sub_requests_.end());
|
| + sub_requests_.insert(sub_request);
|
| +}
|
| +
|
| +void DevToolsURLRequestInterceptor::State::UnregisterSubRequest(
|
| + const net::URLRequest* sub_request) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + DCHECK(sub_requests_.find(sub_request) != sub_requests_.end());
|
| + sub_requests_.erase(sub_request);
|
| +}
|
| +
|
| +void DevToolsURLRequestInterceptor::State::ExpectRequestAfterRedirect(
|
| + const net::URLRequest* request,
|
| + std::string id) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + expected_redirects_[request] = id;
|
| +}
|
| +
|
| +std::string DevToolsURLRequestInterceptor::State::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::State::GetJob(
|
| + const std::string& interception_id) const {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + const auto it = interception_id_to_job_map_.find(interception_id);
|
| + if (it == interception_id_to_job_map_.end())
|
| + return nullptr;
|
| + return it->second;
|
| +}
|
| +
|
| +void DevToolsURLRequestInterceptor::State::RegisterJob(
|
| + DevToolsURLInterceptorRequestJob* job,
|
| + const std::string& interception_id) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + interception_id_to_job_map_[interception_id] = job;
|
| +}
|
| +
|
| +void DevToolsURLRequestInterceptor::State::UnregisterJob(
|
| + const std::string& interception_id) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + interception_id_to_job_map_.erase(interception_id);
|
| +}
|
| +
|
| +// static
|
| +DevToolsURLRequestInterceptor*
|
| +DevToolsURLRequestInterceptor::FromBrowserContext(BrowserContext* context) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| + return static_cast<DevToolsURLRequestInterceptorUserData*>(
|
| + context->GetUserData(kDevToolsURLRequestInterceptorKeyName))
|
| + ->devtools_url_request_interceptor();
|
| +}
|
| +
|
| +void DevToolsURLRequestInterceptor::CreateStateOnIoThread() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + state_.reset(new State());
|
| +}
|
| +
|
| +} // namespace content
|
|
|