summaryrefslogtreecommitdiff
path: root/chromium/content/browser/devtools
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/browser/devtools')
-rw-r--r--chromium/content/browser/devtools/BUILD.gn19
-rw-r--r--chromium/content/browser/devtools/browser_devtools_agent_host.cc16
-rw-r--r--chromium/content/browser/devtools/browser_devtools_agent_host.h2
-rw-r--r--chromium/content/browser/devtools/devtools_agent_host_impl.cc56
-rw-r--r--chromium/content/browser/devtools/devtools_agent_host_impl.h11
-rw-r--r--chromium/content/browser/devtools/devtools_frame_trace_recorder_for_viz.cc118
-rw-r--r--chromium/content/browser/devtools/devtools_frame_trace_recorder_for_viz.h49
-rw-r--r--chromium/content/browser/devtools/devtools_frontend_host_impl.cc2
-rw-r--r--chromium/content/browser/devtools/devtools_frontend_host_impl.h2
-rw-r--r--chromium/content/browser/devtools/devtools_http_handler.cc9
-rw-r--r--chromium/content/browser/devtools/devtools_interceptor_controller.cc2
-rw-r--r--chromium/content/browser/devtools/devtools_io_context.cc1
-rw-r--r--chromium/content/browser/devtools/devtools_manager.cc1
-rw-r--r--chromium/content/browser/devtools/devtools_network_interceptor.cc49
-rw-r--r--chromium/content/browser/devtools/devtools_network_interceptor.h24
-rw-r--r--chromium/content/browser/devtools/devtools_pipe_handler.cc1
-rw-r--r--chromium/content/browser/devtools/devtools_session.cc14
-rw-r--r--chromium/content/browser/devtools/devtools_session.h9
-rw-r--r--chromium/content/browser/devtools/devtools_target_registry.cc1
-rw-r--r--chromium/content/browser/devtools/devtools_traceable_screenshot.h4
-rw-r--r--chromium/content/browser/devtools/devtools_url_interceptor_request_job.cc69
-rw-r--r--chromium/content/browser/devtools/devtools_url_interceptor_request_job.h4
-rw-r--r--chromium/content/browser/devtools/devtools_url_loader_interceptor.cc1170
-rw-r--r--chromium/content/browser/devtools/devtools_url_loader_interceptor.h68
-rw-r--r--chromium/content/browser/devtools/devtools_url_request_interceptor.cc36
-rw-r--r--chromium/content/browser/devtools/devtools_video_consumer.cc169
-rw-r--r--chromium/content/browser/devtools/devtools_video_consumer.h104
-rw-r--r--chromium/content/browser/devtools/devtools_video_consumer_browsertest.cc128
-rw-r--r--chromium/content/browser/devtools/devtools_video_consumer_unittest.cc394
-rw-r--r--chromium/content/browser/devtools/protocol/browser_handler.cc2
-rw-r--r--chromium/content/browser/devtools/protocol/browser_handler.h2
-rw-r--r--chromium/content/browser/devtools/protocol/devtools_download_manager_delegate.cc2
-rw-r--r--chromium/content/browser/devtools/protocol/devtools_protocol_browsertest.cc158
-rw-r--r--chromium/content/browser/devtools/protocol/emulation_handler.cc32
-rw-r--r--chromium/content/browser/devtools/protocol/emulation_handler.h2
-rw-r--r--chromium/content/browser/devtools/protocol/input_handler.cc6
-rw-r--r--chromium/content/browser/devtools/protocol/input_handler.h9
-rw-r--r--chromium/content/browser/devtools/protocol/native_input_event_builder_mac.mm2
-rw-r--r--chromium/content/browser/devtools/protocol/network_handler.cc846
-rw-r--r--chromium/content/browser/devtools/protocol/network_handler.h13
-rw-r--r--chromium/content/browser/devtools/protocol/page_handler.cc7
-rw-r--r--chromium/content/browser/devtools/protocol/page_handler.h4
-rw-r--r--chromium/content/browser/devtools/protocol/security_handler.cc8
-rw-r--r--chromium/content/browser/devtools/protocol/service_worker_handler.cc10
-rw-r--r--chromium/content/browser/devtools/protocol/storage_handler.cc6
-rw-r--r--chromium/content/browser/devtools/protocol/system_info_handler.cc1
-rw-r--r--chromium/content/browser/devtools/protocol/target_auto_attacher.cc5
-rw-r--r--chromium/content/browser/devtools/protocol/tethering_handler.cc3
-rw-r--r--chromium/content/browser/devtools/protocol/tracing_handler.cc178
-rw-r--r--chromium/content/browser/devtools/protocol/tracing_handler.h23
-rw-r--r--chromium/content/browser/devtools/protocol/tracing_handler_unittest.cc3
-rw-r--r--chromium/content/browser/devtools/protocol_config.json2
-rw-r--r--chromium/content/browser/devtools/render_frame_devtools_agent_host.cc88
-rw-r--r--chromium/content/browser/devtools/render_frame_devtools_agent_host.h12
-rw-r--r--chromium/content/browser/devtools/service_worker_devtools_agent_host.cc3
-rw-r--r--chromium/content/browser/devtools/service_worker_devtools_agent_host.h4
-rw-r--r--chromium/content/browser/devtools/service_worker_devtools_manager.h2
-rw-r--r--chromium/content/browser/devtools/shared_worker_devtools_agent_host.cc3
-rw-r--r--chromium/content/browser/devtools/shared_worker_devtools_agent_host.h4
59 files changed, 3223 insertions, 749 deletions
diff --git a/chromium/content/browser/devtools/BUILD.gn b/chromium/content/browser/devtools/BUILD.gn
index 611d0281158..2e5ef6a415e 100644
--- a/chromium/content/browser/devtools/BUILD.gn
+++ b/chromium/content/browser/devtools/BUILD.gn
@@ -15,13 +15,14 @@ group("resources") {
}
compressed_protocol_file =
- "$root_gen_dir/blink/core/inspector/protocol.json.bro"
+ "$root_gen_dir/third_party/blink/renderer/core/inspector/protocol.json.bro"
compress_file_brotli("compressed_protocol_json") {
- input_file = "$root_gen_dir/blink/core/inspector/protocol.json"
+ input_file =
+ "$root_gen_dir/third_party/blink/renderer/core/inspector/protocol.json"
output_file = compressed_protocol_file
deps = [
- "//third_party/WebKit/Source/core/inspector:protocol_version",
+ "//third_party/blink/renderer/core/inspector:protocol_version",
]
}
@@ -49,18 +50,18 @@ grit("devtools_resources") {
":compressed_protocol_json",
# This is the action that generates out .grd input file.
- "//third_party/WebKit/public:blink_generate_devtools_grd",
+ "//third_party/blink/public:blink_generate_devtools_grd",
]
}
inspector_protocol_generate("protocol_sources") {
visibility = [ "//content/browser" ]
deps = [
- "//third_party/WebKit/Source/core/inspector:protocol_version",
+ "//third_party/blink/renderer/core/inspector:protocol_version",
]
- _blink_protocol_path =
- rebase_path("$root_gen_dir/blink/core/inspector/protocol.json",
- root_build_dir)
+ _blink_protocol_path = rebase_path(
+ "$root_gen_dir/third_party/blink/renderer/core/inspector/protocol.json",
+ root_build_dir)
inspector_protocol_dir = "//third_party/inspector_protocol"
out_dir = target_gen_dir
@@ -68,7 +69,7 @@ inspector_protocol_generate("protocol_sources") {
config_values = [ "protocol.path=$_blink_protocol_path" ]
inputs = [
- "$root_gen_dir/blink/core/inspector/protocol.json",
+ "$root_gen_dir/third_party/blink/renderer/core/inspector/protocol.json",
config_file,
]
diff --git a/chromium/content/browser/devtools/browser_devtools_agent_host.cc b/chromium/content/browser/devtools/browser_devtools_agent_host.cc
index 6475584ed6b..bd0c4705380 100644
--- a/chromium/content/browser/devtools/browser_devtools_agent_host.cc
+++ b/chromium/content/browser/devtools/browser_devtools_agent_host.cc
@@ -31,7 +31,7 @@ scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::CreateForBrowser(
scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::CreateForDiscovery() {
CreateServerSocketCallback null_callback;
- return new BrowserDevToolsAgentHost(nullptr, null_callback, true);
+ return new BrowserDevToolsAgentHost(nullptr, std::move(null_callback), true);
}
BrowserDevToolsAgentHost::BrowserDevToolsAgentHost(
@@ -48,12 +48,15 @@ BrowserDevToolsAgentHost::BrowserDevToolsAgentHost(
BrowserDevToolsAgentHost::~BrowserDevToolsAgentHost() {
}
-void BrowserDevToolsAgentHost::AttachSession(DevToolsSession* session) {
+bool BrowserDevToolsAgentHost::AttachSession(DevToolsSession* session) {
+ if (session->restricted())
+ return false;
+
session->SetBrowserOnly(true);
session->AddHandler(
base::WrapUnique(new protocol::TargetHandler(true /* browser_only */)));
if (only_discovery_)
- return;
+ return true;
session->AddHandler(base::WrapUnique(new protocol::BrowserHandler()));
session->AddHandler(base::WrapUnique(new protocol::IOHandler(
@@ -63,10 +66,9 @@ void BrowserDevToolsAgentHost::AttachSession(DevToolsSession* session) {
session->AddHandler(base::WrapUnique(new protocol::SystemInfoHandler()));
session->AddHandler(base::WrapUnique(new protocol::TetheringHandler(
socket_callback_, tethering_task_runner_)));
- session->AddHandler(base::WrapUnique(new protocol::TracingHandler(
- protocol::TracingHandler::Browser,
- FrameTreeNode::kFrameTreeNodeInvalidId,
- GetIOContext())));
+ session->AddHandler(
+ base::WrapUnique(new protocol::TracingHandler(nullptr, GetIOContext())));
+ return true;
}
void BrowserDevToolsAgentHost::DetachSession(DevToolsSession* session) {}
diff --git a/chromium/content/browser/devtools/browser_devtools_agent_host.h b/chromium/content/browser/devtools/browser_devtools_agent_host.h
index b7576135a7c..7022e2d167c 100644
--- a/chromium/content/browser/devtools/browser_devtools_agent_host.h
+++ b/chromium/content/browser/devtools/browser_devtools_agent_host.h
@@ -19,7 +19,7 @@ class BrowserDevToolsAgentHost : public DevToolsAgentHostImpl {
~BrowserDevToolsAgentHost() override;
// DevToolsAgentHostImpl implementation.
- void AttachSession(DevToolsSession* session) override;
+ bool AttachSession(DevToolsSession* session) override;
void DetachSession(DevToolsSession* session) override;
void DispatchProtocolMessage(DevToolsSession* session,
const std::string& message) override;
diff --git a/chromium/content/browser/devtools/devtools_agent_host_impl.cc b/chromium/content/browser/devtools/devtools_agent_host_impl.cc
index 775bec85a36..7c9b58aa5e1 100644
--- a/chromium/content/browser/devtools/devtools_agent_host_impl.cc
+++ b/chromium/content/browser/devtools/devtools_agent_host_impl.cc
@@ -176,23 +176,37 @@ DevToolsSession* DevToolsAgentHostImpl::SessionByClient(
return it == session_by_client_.end() ? nullptr : it->second.get();
}
-void DevToolsAgentHostImpl::InnerAttachClient(DevToolsAgentHostClient* client) {
+bool DevToolsAgentHostImpl::InnerAttachClient(DevToolsAgentHostClient* client,
+ bool restricted) {
scoped_refptr<DevToolsAgentHostImpl> protect(this);
- DevToolsSession* session = new DevToolsSession(this, client);
+ DevToolsSession* session = new DevToolsSession(this, client, restricted);
sessions_.insert(session);
session_by_client_[client].reset(session);
- AttachSession(session);
+ if (!AttachSession(session)) {
+ sessions_.erase(session);
+ session_by_client_.erase(client);
+ return false;
+ }
+
if (sessions_.size() == 1)
NotifyAttached();
DevToolsManager* manager = DevToolsManager::GetInstance();
if (manager->delegate())
manager->delegate()->ClientAttached(this, client);
+ return true;
}
void DevToolsAgentHostImpl::AttachClient(DevToolsAgentHostClient* client) {
if (SessionByClient(client))
return;
- InnerAttachClient(client);
+ InnerAttachClient(client, false /* restricted */);
+}
+
+bool DevToolsAgentHostImpl::AttachRestrictedClient(
+ DevToolsAgentHostClient* client) {
+ if (SessionByClient(client))
+ return false;
+ return InnerAttachClient(client, true /* restricted */);
}
void DevToolsAgentHostImpl::ForceAttachClient(DevToolsAgentHostClient* client) {
@@ -200,9 +214,9 @@ void DevToolsAgentHostImpl::ForceAttachClient(DevToolsAgentHostClient* client) {
return;
scoped_refptr<DevToolsAgentHostImpl> protect(this);
if (!sessions_.empty())
- ForceDetachAllClients();
+ ForceDetachAllSessions();
DCHECK(sessions_.empty());
- InnerAttachClient(client);
+ InnerAttachClient(client, false /* restricted */);
}
bool DevToolsAgentHostImpl::DetachClient(DevToolsAgentHostClient* client) {
@@ -298,16 +312,34 @@ bool DevToolsAgentHostImpl::Inspect() {
return false;
}
-void DevToolsAgentHostImpl::ForceDetachAllClients() {
+void DevToolsAgentHostImpl::ForceDetachAllSessions() {
scoped_refptr<DevToolsAgentHostImpl> protect(this);
- while (!session_by_client_.empty()) {
- DevToolsAgentHostClient* client = session_by_client_.begin()->first;
- InnerDetachClient(client);
+ while (!sessions_.empty()) {
+ DevToolsAgentHostClient* client = (*sessions_.begin())->client();
+ DetachClient(client);
client->AgentHostClosed(this);
}
}
-void DevToolsAgentHostImpl::AttachSession(DevToolsSession* session) {}
+void DevToolsAgentHostImpl::ForceDetachRestrictedSessions() {
+ if (sessions_.empty())
+ return;
+ scoped_refptr<DevToolsAgentHostImpl> protect(this);
+ std::vector<DevToolsSession*> restricted;
+ for (DevToolsSession* session : sessions_) {
+ if (session->restricted())
+ restricted.push_back(session);
+ }
+ for (DevToolsSession* session : restricted) {
+ DevToolsAgentHostClient* client = session->client();
+ DetachClient(client);
+ client->AgentHostClosed(this);
+ }
+}
+
+bool DevToolsAgentHostImpl::AttachSession(DevToolsSession* session) {
+ return false;
+}
void DevToolsAgentHostImpl::DetachSession(DevToolsSession* session) {}
@@ -325,7 +357,7 @@ void DevToolsAgentHost::DetachAllClients() {
DevToolsMap copy = g_devtools_instances.Get();
for (DevToolsMap::iterator it(copy.begin()); it != copy.end(); ++it) {
DevToolsAgentHostImpl* agent_host = it->second;
- agent_host->ForceDetachAllClients();
+ agent_host->ForceDetachAllSessions();
}
}
diff --git a/chromium/content/browser/devtools/devtools_agent_host_impl.h b/chromium/content/browser/devtools/devtools_agent_host_impl.h
index 20178938a01..c69bf5a70f2 100644
--- a/chromium/content/browser/devtools/devtools_agent_host_impl.h
+++ b/chromium/content/browser/devtools/devtools_agent_host_impl.h
@@ -16,7 +16,7 @@
#include "content/common/content_export.h"
#include "content/public/browser/certificate_request_result_type.h"
#include "content/public/browser/devtools_agent_host.h"
-#include "third_party/WebKit/public/web/devtools_agent.mojom.h"
+#include "third_party/blink/public/web/devtools_agent.mojom.h"
namespace content {
@@ -37,6 +37,7 @@ class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost {
// DevToolsAgentHost implementation.
void AttachClient(DevToolsAgentHostClient* client) override;
+ bool AttachRestrictedClient(DevToolsAgentHostClient* client) override;
void ForceAttachClient(DevToolsAgentHostClient* client) override;
bool DetachClient(DevToolsAgentHostClient* client) override;
bool DispatchProtocolMessage(DevToolsAgentHostClient* client,
@@ -63,14 +64,16 @@ class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost {
static bool ShouldForceCreation();
- virtual void AttachSession(DevToolsSession* session);
+ // Returning |false| will block the attach.
+ virtual bool AttachSession(DevToolsSession* session);
virtual void DetachSession(DevToolsSession* session);
virtual void DispatchProtocolMessage(DevToolsSession* session,
const std::string& message);
void NotifyCreated();
void NotifyNavigated();
- void ForceDetachAllClients();
+ void ForceDetachAllSessions();
+ void ForceDetachRestrictedSessions();
DevToolsIOContext* GetIOContext() { return &io_context_; }
base::flat_set<DevToolsSession*>& sessions() { return sessions_; }
@@ -78,7 +81,7 @@ class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost {
private:
friend class DevToolsAgentHost; // for static methods
friend class DevToolsSession;
- void InnerAttachClient(DevToolsAgentHostClient* client);
+ bool InnerAttachClient(DevToolsAgentHostClient* client, bool restricted);
void InnerDetachClient(DevToolsAgentHostClient* client);
void NotifyAttached();
void NotifyDetached();
diff --git a/chromium/content/browser/devtools/devtools_frame_trace_recorder_for_viz.cc b/chromium/content/browser/devtools/devtools_frame_trace_recorder_for_viz.cc
deleted file mode 100644
index ab433746a7e..00000000000
--- a/chromium/content/browser/devtools/devtools_frame_trace_recorder_for_viz.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright 2018 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_frame_trace_recorder_for_viz.h"
-
-#include "cc/paint/skia_paint_canvas.h"
-#include "components/viz/host/host_frame_sink_manager.h"
-#include "content/browser/compositor/surface_utils.h"
-#include "content/browser/devtools/devtools_frame_trace_recorder.h"
-#include "content/browser/devtools/devtools_traceable_screenshot.h"
-#include "media/renderers/paint_canvas_video_renderer.h"
-
-namespace content {
-
-namespace {
-
-static constexpr gfx::Size kMaxFrameSize = gfx::Size(500, 500);
-
-} // namespace
-
-DevToolsFrameTraceRecorderForViz::DevToolsFrameTraceRecorderForViz()
- : binding_(this) {}
-
-DevToolsFrameTraceRecorderForViz::~DevToolsFrameTraceRecorderForViz() = default;
-
-void DevToolsFrameTraceRecorderForViz::StartCapture() {
- // Early out if we're already capturing,
- if (video_capturer_)
- return;
- GetHostFrameSinkManager()->CreateVideoCapturer(
- mojo::MakeRequest(&video_capturer_));
- video_capturer_->SetResolutionConstraints(gfx::Size(1, 1), kMaxFrameSize,
- false);
- video_capturer_->SetMinCapturePeriod(base::TimeDelta::FromMilliseconds(10));
- viz::mojom::FrameSinkVideoConsumerPtr consumer;
- binding_.Bind(mojo::MakeRequest(&consumer));
- video_capturer_->ChangeTarget(frame_sink_id_);
- video_capturer_->Start(std::move(consumer));
- number_of_screenshots_ = 0;
-}
-
-void DevToolsFrameTraceRecorderForViz::StopCapture() {
- if (!video_capturer_)
- return;
- binding_.Close();
- video_capturer_->Stop();
- video_capturer_.reset();
-}
-
-void DevToolsFrameTraceRecorderForViz::SetFrameSinkId(
- const viz::FrameSinkId& frame_sink_id) {
- frame_sink_id_ = frame_sink_id;
- if (video_capturer_)
- video_capturer_->ChangeTarget(frame_sink_id_);
-}
-
-void DevToolsFrameTraceRecorderForViz::OnFrameCaptured(
- mojo::ScopedSharedBufferHandle buffer,
- uint32_t buffer_size,
- ::media::mojom::VideoFrameInfoPtr info,
- const gfx::Rect& update_rect,
- const gfx::Rect& content_rect,
- viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) {
- if (!buffer.is_valid()) {
- callbacks->Done();
- return;
- }
-
- mojo::ScopedSharedBufferMapping mapping = buffer->Map(buffer_size);
- if (!mapping) {
- DLOG(ERROR) << "Shared memory mapping failed.";
- return;
- }
-
- scoped_refptr<media::VideoFrame> frame;
- frame = media::VideoFrame::WrapExternalData(
- info->pixel_format, info->coded_size, info->visible_rect,
- info->visible_rect.size(), static_cast<uint8_t*>(mapping.get()),
- buffer_size, info->timestamp);
- if (!frame)
- return;
- frame->AddDestructionObserver(base::BindOnce(
- [](mojo::ScopedSharedBufferMapping mapping) {}, std::move(mapping)));
-
- media::PaintCanvasVideoRenderer renderer;
- SkBitmap skbitmap;
- skbitmap.allocN32Pixels(info->visible_rect.width(),
- info->visible_rect.height());
- cc::SkiaPaintCanvas canvas(skbitmap);
- renderer.Copy(frame, &canvas, media::Context3D());
- callbacks->Done();
-
- DCHECK(info->metadata);
- frame->metadata()->MergeInternalValuesFrom(*info->metadata);
- base::TimeTicks reference_time;
- const bool had_reference_time = frame->metadata()->GetTimeTicks(
- media::VideoFrameMetadata::REFERENCE_TIME, &reference_time);
- DCHECK(had_reference_time);
-
- TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID_AND_TIMESTAMP(
- TRACE_DISABLED_BY_DEFAULT("devtools.screenshot"), "Screenshot", 1,
- reference_time,
- std::unique_ptr<base::trace_event::ConvertableToTraceFormat>(
- new DevToolsTraceableScreenshot(skbitmap)));
-
- ++number_of_screenshots_;
- if (number_of_screenshots_ >=
- DevToolsFrameTraceRecorder::kMaximumNumberOfScreenshots)
- StopCapture();
-}
-
-void DevToolsFrameTraceRecorderForViz::OnTargetLost(
- const viz::FrameSinkId& frame_sink_id) {}
-
-void DevToolsFrameTraceRecorderForViz::OnStopped() {}
-
-} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_frame_trace_recorder_for_viz.h b/chromium/content/browser/devtools/devtools_frame_trace_recorder_for_viz.h
deleted file mode 100644
index d459e1c139d..00000000000
--- a/chromium/content/browser/devtools/devtools_frame_trace_recorder_for_viz.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2018 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.
-
-#ifndef CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_FRAME_TRACE_RECORDER_FOR_VIZ_H_
-#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_FRAME_TRACE_RECORDER_FOR_VIZ_H_
-
-#include "mojo/public/cpp/bindings/binding.h"
-#include "services/viz/privileged/interfaces/compositing/frame_sink_video_capture.mojom.h"
-
-namespace content {
-
-// Captures snapshots of the page being traced. Used when the
-// VizDisplayCompositor feature is enabled.
-// TODO(https://crbug.com/813929): Use this class everywhere even if viz is not
-// enabled and remove DevToolsFrameTraceRecorder.
-class DevToolsFrameTraceRecorderForViz
- : public viz::mojom::FrameSinkVideoConsumer {
- public:
- DevToolsFrameTraceRecorderForViz();
- ~DevToolsFrameTraceRecorderForViz() override;
-
- void StartCapture();
- void StopCapture();
- void SetFrameSinkId(const viz::FrameSinkId& frame_sink_id);
-
- // viz::mojom::FrameSinkVideoConsumer implementation.
- void OnFrameCaptured(
- mojo::ScopedSharedBufferHandle buffer,
- uint32_t buffer_size,
- ::media::mojom::VideoFrameInfoPtr info,
- const gfx::Rect& update_rect,
- const gfx::Rect& content_rect,
- viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) override;
- void OnTargetLost(const viz::FrameSinkId& frame_sink_id) override;
- void OnStopped() override;
-
- private:
- viz::mojom::FrameSinkVideoCapturerPtr video_capturer_;
- mojo::Binding<viz::mojom::FrameSinkVideoConsumer> binding_;
- viz::FrameSinkId frame_sink_id_;
- int number_of_screenshots_ = 0;
-
- DISALLOW_COPY_AND_ASSIGN(DevToolsFrameTraceRecorderForViz);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_FRAME_TRACE_RECORDER_FOR_VIZ_H_
diff --git a/chromium/content/browser/devtools/devtools_frontend_host_impl.cc b/chromium/content/browser/devtools/devtools_frontend_host_impl.cc
index eacded0190a..8fe9445564e 100644
--- a/chromium/content/browser/devtools/devtools_frontend_host_impl.cc
+++ b/chromium/content/browser/devtools/devtools_frontend_host_impl.cc
@@ -12,7 +12,7 @@
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_client.h"
-#include "third_party/WebKit/public/common/associated_interfaces/associated_interface_provider.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
namespace content {
diff --git a/chromium/content/browser/devtools/devtools_frontend_host_impl.h b/chromium/content/browser/devtools/devtools_frontend_host_impl.h
index 0b4275e577e..43f03d2dfb3 100644
--- a/chromium/content/browser/devtools/devtools_frontend_host_impl.h
+++ b/chromium/content/browser/devtools/devtools_frontend_host_impl.h
@@ -8,7 +8,7 @@
#include "base/macros.h"
#include "content/public/browser/devtools_frontend_host.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
-#include "third_party/WebKit/public/web/devtools_frontend.mojom.h"
+#include "third_party/blink/public/web/devtools_frontend.mojom.h"
namespace content {
diff --git a/chromium/content/browser/devtools/devtools_http_handler.cc b/chromium/content/browser/devtools/devtools_http_handler.cc
index 26c4f50fad5..cae7c566146 100644
--- a/chromium/content/browser/devtools/devtools_http_handler.cc
+++ b/chromium/content/browser/devtools/devtools_http_handler.cc
@@ -369,6 +369,10 @@ static bool TimeComparator(scoped_refptr<DevToolsAgentHost> host1,
// DevToolsHttpHandler -------------------------------------------------------
DevToolsHttpHandler::~DevToolsHttpHandler() {
+ // Disconnecting sessions might lead to the last minute messages generated
+ // by the targets. It is essential that this happens before we issue delete
+ // soon for the server wrapper.
+ connection_to_client_.clear();
TerminateOnUI(std::move(thread_), std::move(server_wrapper_),
std::move(socket_factory_));
}
@@ -568,8 +572,9 @@ void DevToolsHttpHandler::OnJsonRequest(
kTargetWebSocketDebuggerUrlField,
base::StringPrintf("ws://%s%s", host.c_str(), browser_guid_.c_str()));
#if defined(OS_ANDROID)
- version.SetString("Android-Package",
- base::android::BuildInfo::GetInstance()->package_name());
+ version.SetString(
+ "Android-Package",
+ base::android::BuildInfo::GetInstance()->host_package_name());
#endif
SendJson(connection_id, net::HTTP_OK, &version, std::string());
return;
diff --git a/chromium/content/browser/devtools/devtools_interceptor_controller.cc b/chromium/content/browser/devtools/devtools_interceptor_controller.cc
index 77de8fe584f..a2c27cba5df 100644
--- a/chromium/content/browser/devtools/devtools_interceptor_controller.cc
+++ b/chromium/content/browser/devtools/devtools_interceptor_controller.cc
@@ -4,11 +4,11 @@
#include "content/browser/devtools/devtools_interceptor_controller.h"
-#include "base/memory/ptr_util.h"
#include "base/supports_user_data.h"
#include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
namespace content {
diff --git a/chromium/content/browser/devtools/devtools_io_context.cc b/chromium/content/browser/devtools/devtools_io_context.cc
index 24a756c05ad..1e0ae3d9eee 100644
--- a/chromium/content/browser/devtools/devtools_io_context.cc
+++ b/chromium/content/browser/devtools/devtools_io_context.cc
@@ -8,7 +8,6 @@
#include "base/containers/queue.h"
#include "base/files/file.h"
#include "base/files/file_util.h"
-#include "base/memory/ptr_util.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
diff --git a/chromium/content/browser/devtools/devtools_manager.cc b/chromium/content/browser/devtools/devtools_manager.cc
index 6336ea21da7..241e5039fa9 100644
--- a/chromium/content/browser/devtools/devtools_manager.cc
+++ b/chromium/content/browser/devtools/devtools_manager.cc
@@ -5,7 +5,6 @@
#include "content/browser/devtools/devtools_manager.h"
#include "base/bind.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "content/browser/devtools/devtools_agent_host_impl.h"
#include "content/browser/devtools/devtools_http_handler.h"
diff --git a/chromium/content/browser/devtools/devtools_network_interceptor.cc b/chromium/content/browser/devtools/devtools_network_interceptor.cc
index 812f543da2a..8213acf5d97 100644
--- a/chromium/content/browser/devtools/devtools_network_interceptor.cc
+++ b/chromium/content/browser/devtools/devtools_network_interceptor.cc
@@ -3,6 +3,9 @@
// found in the LICENSE file.
#include "content/browser/devtools/devtools_network_interceptor.h"
+#include "base/strings/pattern.h"
+#include "content/browser/devtools/protocol/network_handler.h"
+#include "url/gurl.h"
namespace content {
@@ -22,4 +25,50 @@ DevToolsNetworkInterceptor::FilterEntry::FilterEntry(
DevToolsNetworkInterceptor::FilterEntry::FilterEntry(FilterEntry&&) {}
DevToolsNetworkInterceptor::FilterEntry::~FilterEntry() {}
+DevToolsNetworkInterceptor::Modifications::Modifications()
+ : mark_as_canceled(false) {}
+
+DevToolsNetworkInterceptor::Modifications::Modifications(
+ base::Optional<net::Error> error_reason,
+ base::Optional<std::string> raw_response,
+ protocol::Maybe<std::string> modified_url,
+ protocol::Maybe<std::string> modified_method,
+ protocol::Maybe<std::string> modified_post_data,
+ protocol::Maybe<protocol::Network::Headers> modified_headers,
+ protocol::Maybe<protocol::Network::AuthChallengeResponse>
+ auth_challenge_response,
+ bool mark_as_canceled)
+ : error_reason(std::move(error_reason)),
+ raw_response(std::move(raw_response)),
+ modified_url(std::move(modified_url)),
+ modified_method(std::move(modified_method)),
+ modified_post_data(std::move(modified_post_data)),
+ modified_headers(std::move(modified_headers)),
+ auth_challenge_response(std::move(auth_challenge_response)),
+ mark_as_canceled(mark_as_canceled) {}
+
+DevToolsNetworkInterceptor::Modifications::~Modifications() {}
+
+DevToolsNetworkInterceptor::Pattern::~Pattern() = default;
+
+DevToolsNetworkInterceptor::Pattern::Pattern(const Pattern& other) = default;
+
+DevToolsNetworkInterceptor::Pattern::Pattern(
+ const std::string& url_pattern,
+ base::flat_set<ResourceType> resource_types,
+ InterceptionStage interception_stage)
+ : url_pattern(url_pattern),
+ resource_types(std::move(resource_types)),
+ interception_stage(interception_stage) {}
+
+bool DevToolsNetworkInterceptor::Pattern::Matches(
+ const std::string& url,
+ ResourceType resource_type) const {
+ if (!resource_types.empty() &&
+ resource_types.find(resource_type) == resource_types.end()) {
+ return false;
+ }
+ return base::MatchPattern(url, url_pattern);
+}
+
} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_network_interceptor.h b/chromium/content/browser/devtools/devtools_network_interceptor.h
index 59769bf7e01..97c64bc6257 100644
--- a/chromium/content/browser/devtools/devtools_network_interceptor.h
+++ b/chromium/content/browser/devtools/devtools_network_interceptor.h
@@ -35,6 +35,8 @@ struct InterceptedRequestInfo {
class DevToolsNetworkInterceptor {
public:
+ virtual ~DevToolsNetworkInterceptor() = default;
+
using RequestInterceptedCallback =
base::RepeatingCallback<void(std::unique_ptr<InterceptedRequestInfo>)>;
using ContinueInterceptedRequestCallback =
@@ -43,6 +45,7 @@ class DevToolsNetworkInterceptor {
protocol::Network::Backend::GetResponseBodyForInterceptionCallback;
struct Modifications {
+ Modifications();
Modifications(base::Optional<net::Error> error_reason,
base::Optional<std::string> raw_response,
protocol::Maybe<std::string> modified_url,
@@ -73,25 +76,27 @@ class DevToolsNetworkInterceptor {
};
enum InterceptionStage {
- REQUEST,
- RESPONSE,
+ DONT_INTERCEPT = 0,
+ REQUEST = (1 << 0),
+ RESPONSE = (1 << 1),
// Note: Both is not sent from front-end. It is used if both Request
// and HeadersReceived was found it upgrades it to Both.
- BOTH,
- DONT_INTERCEPT
+ BOTH = (REQUEST | RESPONSE),
};
struct Pattern {
public:
- Pattern();
~Pattern();
Pattern(const Pattern& other);
Pattern(const std::string& url_pattern,
base::flat_set<ResourceType> resource_types,
InterceptionStage interception_stage);
+
+ bool Matches(const std::string& url, ResourceType resource_type) const;
+
const std::string url_pattern;
const base::flat_set<ResourceType> resource_types;
- InterceptionStage interception_stage;
+ const InterceptionStage interception_stage;
};
struct FilterEntry {
@@ -121,6 +126,13 @@ class DevToolsNetworkInterceptor {
std::unique_ptr<ContinueInterceptedRequestCallback> callback) = 0;
};
+inline DevToolsNetworkInterceptor::InterceptionStage& operator|=(
+ DevToolsNetworkInterceptor::InterceptionStage& a,
+ const DevToolsNetworkInterceptor::InterceptionStage& b) {
+ a = static_cast<DevToolsNetworkInterceptor::InterceptionStage>(a | b);
+ return a;
+}
+
} // namespace content
#endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_INTERCEPTOR_H_
diff --git a/chromium/content/browser/devtools/devtools_pipe_handler.cc b/chromium/content/browser/devtools/devtools_pipe_handler.cc
index dce8d284663..4fbea246102 100644
--- a/chromium/content/browser/devtools/devtools_pipe_handler.cc
+++ b/chromium/content/browser/devtools/devtools_pipe_handler.cc
@@ -16,7 +16,6 @@
#include <string>
#include "base/bind.h"
#include "base/files/file_util.h"
-#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted_memory.h"
#include "base/message_loop/message_loop.h"
#include "base/sequenced_task_runner.h"
diff --git a/chromium/content/browser/devtools/devtools_session.cc b/chromium/content/browser/devtools/devtools_session.cc
index 61d9b790cbc..b31ca0ada8b 100644
--- a/chromium/content/browser/devtools/devtools_session.cc
+++ b/chromium/content/browser/devtools/devtools_session.cc
@@ -24,16 +24,20 @@ bool ShouldSendOnIO(const std::string& method) {
method == "Debugger.setBreakpointByUrl" ||
method == "Debugger.removeBreakpoint" ||
method == "Debugger.setBreakpointsActive" ||
- method == "Performance.getMetrics" || method == "Page.crash";
+ method == "Performance.getMetrics" || method == "Page.crash" ||
+ method == "Runtime.terminateExecution" ||
+ method == "Emulation.setScriptExecutionDisabled";
}
} // namespace
DevToolsSession::DevToolsSession(DevToolsAgentHostImpl* agent_host,
- DevToolsAgentHostClient* client)
+ DevToolsAgentHostClient* client,
+ bool restricted)
: binding_(this),
agent_host_(agent_host),
client_(client),
+ restricted_(restricted),
process_host_id_(ChildProcessHost::kInvalidUniqueID),
host_(nullptr),
dispatcher_(new protocol::UberDispatcher(this)),
@@ -123,12 +127,6 @@ void DevToolsSession::DispatchProtocolMessage(const std::string& message) {
if (delegate->HandleCommand(agent_host_, client_, dict_value))
return;
-
- if (delegate->HandleAsyncCommand(agent_host_, client_, dict_value,
- base::Bind(&DevToolsSession::SendResponse,
- weak_factory_.GetWeakPtr()))) {
- return;
- }
}
int call_id;
diff --git a/chromium/content/browser/devtools/devtools_session.h b/chromium/content/browser/devtools/devtools_session.h
index d7dd60140c4..ea900e26bb3 100644
--- a/chromium/content/browser/devtools/devtools_session.h
+++ b/chromium/content/browser/devtools/devtools_session.h
@@ -14,7 +14,7 @@
#include "content/browser/devtools/devtools_agent_host_impl.h"
#include "content/browser/devtools/protocol/devtools_domain_handler.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
-#include "third_party/WebKit/public/web/devtools_agent.mojom.h"
+#include "third_party/blink/public/web/devtools_agent.mojom.h"
namespace content {
@@ -25,9 +25,13 @@ class DevToolsSession : public protocol::FrontendChannel,
public blink::mojom::DevToolsSessionHost {
public:
DevToolsSession(DevToolsAgentHostImpl* agent_host,
- DevToolsAgentHostClient* client);
+ DevToolsAgentHostClient* client,
+ bool restricted);
~DevToolsSession() override;
+ bool restricted() { return restricted_; }
+ DevToolsAgentHostClient* client() { return client_; };
+
// Browser-only sessions do not talk to mojom::DevToolsAgent, but instead
// handle all protocol messages locally in the browser process.
void SetBrowserOnly(bool browser_only);
@@ -83,6 +87,7 @@ class DevToolsSession : public protocol::FrontendChannel,
blink::mojom::DevToolsSessionPtr io_session_ptr_;
DevToolsAgentHostImpl* agent_host_;
DevToolsAgentHostClient* client_;
+ bool restricted_;
bool browser_only_ = false;
base::flat_map<std::string, std::unique_ptr<protocol::DevToolsDomainHandler>>
handlers_;
diff --git a/chromium/content/browser/devtools/devtools_target_registry.cc b/chromium/content/browser/devtools/devtools_target_registry.cc
index eefc74d8d0a..a426d9e1924 100644
--- a/chromium/content/browser/devtools/devtools_target_registry.cc
+++ b/chromium/content/browser/devtools/devtools_target_registry.cc
@@ -9,6 +9,7 @@
#include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents_observer.h"
namespace content {
diff --git a/chromium/content/browser/devtools/devtools_traceable_screenshot.h b/chromium/content/browser/devtools/devtools_traceable_screenshot.h
index b9f9605379c..bd6afd2271b 100644
--- a/chromium/content/browser/devtools/devtools_traceable_screenshot.h
+++ b/chromium/content/browser/devtools/devtools_traceable_screenshot.h
@@ -19,14 +19,14 @@ class DevToolsTraceableScreenshot
DevToolsTraceableScreenshot(const SkBitmap& bitmap);
+ ~DevToolsTraceableScreenshot() override;
+
// base::trace_event::ConvertableToTraceFormat implementation.
void AppendAsTraceFormat(std::string* out) const override;
private:
static base::subtle::Atomic32 number_of_instances_;
- ~DevToolsTraceableScreenshot() override;
-
SkBitmap frame_;
DISALLOW_COPY_AND_ASSIGN(DevToolsTraceableScreenshot);
diff --git a/chromium/content/browser/devtools/devtools_url_interceptor_request_job.cc b/chromium/content/browser/devtools/devtools_url_interceptor_request_job.cc
index 91a151c75ea..3c9d31b784b 100644
--- a/chromium/content/browser/devtools/devtools_url_interceptor_request_job.cc
+++ b/chromium/content/browser/devtools/devtools_url_interceptor_request_job.cc
@@ -5,7 +5,6 @@
#include "content/browser/devtools/devtools_url_interceptor_request_job.h"
#include "base/base64.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/devtools/protocol/network_handler.h"
@@ -448,6 +447,8 @@ int DevToolsURLInterceptorRequestJob::MockResponseDetails::ReadRawData(
namespace {
+using DevToolsStatus = ResourceRequestInfoImpl::DevToolsStatus;
+
void SendPendingBodyRequestsOnUiThread(
std::vector<std::unique_ptr<
protocol::Network::Backend::GetResponseBodyForInterceptionCallback>>
@@ -522,6 +523,14 @@ std::unique_ptr<net::UploadDataStream> GetUploadData(net::URLRequest* request) {
std::move(proxy_readers), 0);
}
+void SetDevToolsStatus(net::URLRequest* request,
+ DevToolsStatus devtools_status) {
+ ResourceRequestInfoImpl* resource_request_info =
+ ResourceRequestInfoImpl::ForRequest(request);
+ DCHECK(resource_request_info);
+ resource_request_info->set_devtools_status(devtools_status);
+}
+
} // namespace
DevToolsURLInterceptorRequestJob::DevToolsURLInterceptorRequestJob(
@@ -660,10 +669,14 @@ DevToolsURLInterceptorRequestJob::GetHttpResponseHeaders() const {
bool DevToolsURLInterceptorRequestJob::GetMimeType(
std::string* mime_type) const {
+ if (sub_request_) {
+ sub_request_->request()->GetMimeType(mime_type);
+ return true;
+ }
const net::HttpResponseHeaders* response_headers = GetHttpResponseHeaders();
- if (!response_headers)
- return false;
- return response_headers->GetMimeType(mime_type);
+ if (response_headers)
+ return response_headers->GetMimeType(mime_type);
+ return false;
}
bool DevToolsURLInterceptorRequestJob::GetCharset(std::string* charset) {
@@ -711,7 +724,7 @@ void DevToolsURLInterceptorRequestJob::OnSubRequestAuthRequired(
if (stage_to_intercept_ == InterceptionStage::DONT_INTERCEPT) {
// This should trigger default auth behavior.
- // See comment in ProcessAuthRespose.
+ // See comment in ProcessAuthResponse.
NotifyHeadersComplete();
return;
}
@@ -756,6 +769,8 @@ void DevToolsURLInterceptorRequestJob::OnSubRequestRedirectReceived(
bool* defer_redirect) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(sub_request_);
+ SetDevToolsStatus(sub_request_->request(),
+ DevToolsStatus::kCanceledAsRedirect);
// If we're not intercepting results or are a response then cancel this
// redirect and tell the parent request it was redirected through |redirect_|.
@@ -799,8 +814,10 @@ void DevToolsURLInterceptorRequestJob::OnInterceptedRequestResponseStarted(
const net::Error& net_error) {
DCHECK_NE(waiting_for_user_response_,
WaitingForUserResponse::WAITING_FOR_RESPONSE_ACK);
- if (stage_to_intercept_ == InterceptionStage::DONT_INTERCEPT)
+ if (stage_to_intercept_ == InterceptionStage::DONT_INTERCEPT) {
+ static_cast<InterceptedRequest*>(sub_request_.get())->FetchResponseBody();
return;
+ }
waiting_for_user_response_ = WaitingForUserResponse::WAITING_FOR_RESPONSE_ACK;
std::unique_ptr<InterceptedRequestInfo> request_info = BuildRequestInfo();
@@ -873,7 +890,7 @@ void DevToolsURLInterceptorRequestJob::StopIntercepting() {
case WaitingForUserResponse::WAITING_FOR_RESPONSE_ACK:
// Fallthough.
case WaitingForUserResponse::WAITING_FOR_REQUEST_ACK:
- ProcessInterceptionRespose(
+ ProcessInterceptionResponse(
std::make_unique<DevToolsNetworkInterceptor::Modifications>(
base::nullopt, base::nullopt, protocol::Maybe<std::string>(),
protocol::Maybe<std::string>(), protocol::Maybe<std::string>(),
@@ -887,7 +904,7 @@ void DevToolsURLInterceptorRequestJob::StopIntercepting() {
.SetResponse(protocol::Network::AuthChallengeResponse::
ResponseEnum::Default)
.Build();
- ProcessAuthRespose(
+ ProcessAuthResponse(
std::make_unique<DevToolsNetworkInterceptor::Modifications>(
base::nullopt, base::nullopt, protocol::Maybe<std::string>(),
protocol::Maybe<std::string>(), protocol::Maybe<std::string>(),
@@ -928,7 +945,7 @@ void DevToolsURLInterceptorRequestJob::ContinueInterceptedRequest(
"authChallengeResponse not expected.")));
break;
}
- ProcessInterceptionRespose(std::move(modifications));
+ ProcessInterceptionResponse(std::move(modifications));
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::BindOnce(&ContinueInterceptedRequestCallback::sendSuccess,
@@ -945,7 +962,7 @@ void DevToolsURLInterceptorRequestJob::ContinueInterceptedRequest(
"authChallengeResponse required.")));
break;
}
- if (ProcessAuthRespose(std::move(modifications))) {
+ if (ProcessAuthResponse(std::move(modifications))) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::BindOnce(&ContinueInterceptedRequestCallback::sendSuccess,
@@ -1025,18 +1042,14 @@ DevToolsURLInterceptorRequestJob::BuildRequestInfo() {
return result;
}
-void DevToolsURLInterceptorRequestJob::ProcessInterceptionRespose(
+void DevToolsURLInterceptorRequestJob::ProcessInterceptionResponse(
std::unique_ptr<DevToolsNetworkInterceptor::Modifications> modifications) {
bool is_response_ack = waiting_for_user_response_ ==
WaitingForUserResponse::WAITING_FOR_RESPONSE_ACK;
waiting_for_user_response_ = WaitingForUserResponse::NOT_WAITING;
- if (modifications->mark_as_canceled) {
- ResourceRequestInfoImpl* resource_request_info =
- ResourceRequestInfoImpl::ForRequest(request());
- DCHECK(resource_request_info);
- resource_request_info->set_canceled_by_devtools(true);
- }
+ if (modifications->mark_as_canceled)
+ SetDevToolsStatus(request(), DevToolsStatus::kCanceled);
if (modifications->error_reason) {
if (sub_request_) {
@@ -1061,6 +1074,10 @@ void DevToolsURLInterceptorRequestJob::ProcessInterceptionRespose(
sub_request_->Cancel();
sub_request_.reset();
}
+ if (response_headers_callback_) {
+ response_headers_callback_.Run(
+ mock_response_details_->response_headers());
+ }
NotifyHeadersComplete();
return;
}
@@ -1118,11 +1135,17 @@ void DevToolsURLInterceptorRequestJob::ProcessInterceptionRespose(
// The reason we start a sub request is because we are in full control of it
// and can choose to ignore it if, for example, the fetch encounters a
// redirect that the user chooses to replace with a mock response.
- sub_request_.reset(new SubRequest(request_details_, this, interceptor_));
+ DCHECK(stage_to_intercept_ != InterceptionStage::RESPONSE);
+ if (stage_to_intercept_ == InterceptionStage::BOTH) {
+ sub_request_.reset(
+ new InterceptedRequest(request_details_, this, interceptor_));
+ } else {
+ sub_request_.reset(new SubRequest(request_details_, this, interceptor_));
+ }
}
}
-bool DevToolsURLInterceptorRequestJob::ProcessAuthRespose(
+bool DevToolsURLInterceptorRequestJob::ProcessAuthResponse(
std::unique_ptr<DevToolsNetworkInterceptor::Modifications> modifications) {
waiting_for_user_response_ = WaitingForUserResponse::NOT_WAITING;
@@ -1150,8 +1173,8 @@ bool DevToolsURLInterceptorRequestJob::ProcessAuthRespose(
protocol::Network::AuthChallengeResponse::ResponseEnum::
ProvideCredentials) {
SetAuth(net::AuthCredentials(
- base::UTF8ToUTF16(auth_challenge_response->GetUsername("").c_str()),
- base::UTF8ToUTF16(auth_challenge_response->GetPassword("").c_str())));
+ base::UTF8ToUTF16(auth_challenge_response->GetUsername("")),
+ base::UTF8ToUTF16(auth_challenge_response->GetPassword(""))));
return true;
}
@@ -1160,12 +1183,12 @@ bool DevToolsURLInterceptorRequestJob::ProcessAuthRespose(
void DevToolsURLInterceptorRequestJob::SetRequestHeadersCallback(
net::RequestHeadersCallback callback) {
- request_headers_callback_ = callback;
+ request_headers_callback_ = std::move(callback);
}
void DevToolsURLInterceptorRequestJob::SetResponseHeadersCallback(
net::ResponseHeadersCallback callback) {
- response_headers_callback_ = callback;
+ response_headers_callback_ = std::move(callback);
}
DevToolsURLInterceptorRequestJob::RequestDetails::RequestDetails(
diff --git a/chromium/content/browser/devtools/devtools_url_interceptor_request_job.h b/chromium/content/browser/devtools/devtools_url_interceptor_request_job.h
index 961cf901c6b..48e7a7bde39 100644
--- a/chromium/content/browser/devtools/devtools_url_interceptor_request_job.h
+++ b/chromium/content/browser/devtools/devtools_url_interceptor_request_job.h
@@ -128,10 +128,10 @@ class DevToolsURLInterceptorRequestJob : public net::URLRequestJob {
const net::HttpResponseHeaders* GetHttpResponseHeaders() const;
void ProcessRedirect(int status_code, const std::string& new_url);
- void ProcessInterceptionRespose(
+ void ProcessInterceptionResponse(
std::unique_ptr<DevToolsNetworkInterceptor::Modifications> modification);
- bool ProcessAuthRespose(
+ bool ProcessAuthResponse(
std::unique_ptr<DevToolsNetworkInterceptor::Modifications> modification);
enum class WaitingForUserResponse {
diff --git a/chromium/content/browser/devtools/devtools_url_loader_interceptor.cc b/chromium/content/browser/devtools/devtools_url_loader_interceptor.cc
new file mode 100644
index 00000000000..ced25eb9169
--- /dev/null
+++ b/chromium/content/browser/devtools/devtools_url_loader_interceptor.cc
@@ -0,0 +1,1170 @@
+// Copyright 2018 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_loader_interceptor.h"
+#include "base/base64.h"
+#include "base/no_destructor.h"
+#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
+#include "base/unguessable_token.h"
+#include "content/browser/devtools/protocol/network_handler.h"
+#include "content/browser/frame_host/frame_tree_node.h"
+#include "content/public/browser/browser_thread.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/system/data_pipe_drainer.h"
+#include "net/base/mime_sniffer.h"
+#include "net/http/http_util.h"
+#include "net/url_request/url_request.h"
+#include "services/network/public/cpp/resource_request_body.h"
+
+namespace content {
+
+namespace {
+
+using RequestInterceptedCallback =
+ DevToolsNetworkInterceptor::RequestInterceptedCallback;
+using ContinueInterceptedRequestCallback =
+ DevToolsNetworkInterceptor::ContinueInterceptedRequestCallback;
+using GetResponseBodyForInterceptionCallback =
+ DevToolsNetworkInterceptor::GetResponseBodyForInterceptionCallback;
+using Modifications = DevToolsNetworkInterceptor::Modifications;
+using InterceptionStage = DevToolsNetworkInterceptor::InterceptionStage;
+using protocol::Response;
+using protocol::Network::AuthChallengeResponse;
+using GlobalRequestId = std::tuple<int32_t, int32_t, int32_t>;
+
+struct CreateLoaderParameters {
+ CreateLoaderParameters(
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ network::ResourceRequest request,
+ net::MutableNetworkTrafficAnnotationTag traffic_annotation)
+ : routing_id(routing_id),
+ request_id(request_id),
+ options(options),
+ request(request),
+ traffic_annotation(traffic_annotation) {}
+
+ const int32_t routing_id;
+ const int32_t request_id;
+ const uint32_t options;
+ network::ResourceRequest request;
+ const net::MutableNetworkTrafficAnnotationTag traffic_annotation;
+};
+
+class BodyReader : public mojo::DataPipeDrainer::Client {
+ public:
+ explicit BodyReader(base::OnceClosure download_complete_callback)
+ : download_complete_callback_(std::move(download_complete_callback)) {}
+
+ void StartReading(mojo::ScopedDataPipeConsumerHandle body);
+
+ void AddCallback(
+ std::unique_ptr<GetResponseBodyForInterceptionCallback> callback) {
+ callbacks_.push_back(std::move(callback));
+ if (data_complete_) {
+ DCHECK_EQ(1UL, callbacks_.size());
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&BodyReader::DispatchBodyOnUI, std::move(callbacks_),
+ encoded_body_));
+ }
+ }
+
+ bool data_complete() const { return data_complete_; }
+ const std::string& body() const { return body_; }
+
+ void CancelWithError(std::string error) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&BodyReader::DispatchErrorOnUI, std::move(callbacks_),
+ std::move(error)));
+ }
+
+ private:
+ using CallbackVector =
+ std::vector<std::unique_ptr<GetResponseBodyForInterceptionCallback>>;
+ static void DispatchBodyOnUI(const CallbackVector& callbacks,
+ const std::string& body);
+ static void DispatchErrorOnUI(const CallbackVector& callbacks,
+ const std::string& error);
+
+ void OnDataAvailable(const void* data, size_t num_bytes) override {
+ DCHECK(!data_complete_);
+ body_.append(std::string(static_cast<const char*>(data), num_bytes));
+ }
+
+ void OnDataComplete() override;
+
+ std::unique_ptr<mojo::DataPipeDrainer> body_pipe_drainer_;
+ CallbackVector callbacks_;
+ base::OnceClosure download_complete_callback_;
+ std::string body_;
+ std::string encoded_body_;
+ bool data_complete_ = false;
+};
+
+void BodyReader::StartReading(mojo::ScopedDataPipeConsumerHandle body) {
+ DCHECK(!callbacks_.empty());
+ DCHECK(!body_pipe_drainer_);
+ DCHECK(!data_complete_);
+
+ body_pipe_drainer_.reset(new mojo::DataPipeDrainer(this, std::move(body)));
+}
+
+void BodyReader::OnDataComplete() {
+ DCHECK(!data_complete_);
+ data_complete_ = true;
+ body_pipe_drainer_.reset();
+ // TODO(caseq): only encode if necessary.
+ base::Base64Encode(body_, &encoded_body_);
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&BodyReader::DispatchBodyOnUI,
+ std::move(callbacks_), encoded_body_));
+ std::move(download_complete_callback_).Run();
+}
+
+// static
+void BodyReader::DispatchBodyOnUI(const CallbackVector& callbacks,
+ const std::string& encoded_body) {
+ for (const auto& cb : callbacks)
+ cb->sendSuccess(encoded_body, true);
+}
+
+// static
+void BodyReader::DispatchErrorOnUI(const CallbackVector& callbacks,
+ const std::string& error) {
+ for (const auto& cb : callbacks)
+ cb->sendFailure(Response::Error(error));
+}
+
+struct ResponseMetadata {
+ ResponseMetadata() = default;
+ explicit ResponseMetadata(const network::ResourceResponseHead& head)
+ : head(head) {}
+
+ network::ResourceResponseHead head;
+ std::unique_ptr<net::RedirectInfo> redirect_info;
+ network::mojom::DownloadedTempFilePtr downloaded_file;
+ std::vector<uint8_t> cached_metadata;
+ size_t encoded_length = 0;
+ size_t transfer_size = 0;
+ network::URLLoaderCompletionStatus status;
+};
+
+class InterceptionJob : public network::mojom::URLLoaderClient,
+ public network::mojom::URLLoader {
+ public:
+ static InterceptionJob* FindByRequestId(
+ const GlobalRequestId& global_req_id) {
+ const auto& map = GetInterceptionJobMap();
+ auto it = map.find(global_req_id);
+ return it == map.end() ? nullptr : it->second;
+ }
+
+ InterceptionJob(DevToolsURLLoaderInterceptor::Impl* interceptor,
+ const std::string& id,
+ const base::UnguessableToken& frame_token,
+ int32_t process_id,
+ std::unique_ptr<CreateLoaderParameters> create_loader_params,
+ network::mojom::URLLoaderRequest loader_request,
+ network::mojom::URLLoaderClientPtr client,
+ network::mojom::URLLoaderFactoryPtr target_factory);
+
+ void GetResponseBody(
+ std::unique_ptr<GetResponseBodyForInterceptionCallback> callback);
+ void ContinueInterceptedRequest(
+ std::unique_ptr<Modifications> modifications,
+ std::unique_ptr<ContinueInterceptedRequestCallback> callback);
+ void Detach();
+
+ void OnAuthRequest(
+ const scoped_refptr<net::AuthChallengeInfo>& auth_info,
+ DevToolsURLLoaderInterceptor::HandleAuthRequestCallback callback);
+
+ private:
+ static std::map<GlobalRequestId, InterceptionJob*>& GetInterceptionJobMap() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ static base::NoDestructor<std::map<GlobalRequestId, InterceptionJob*>> inst;
+ return *inst;
+ }
+
+ ~InterceptionJob() override {
+ size_t erased = GetInterceptionJobMap().erase(global_req_id_);
+ DCHECK_EQ(1lu, erased);
+ }
+
+ Response InnerContinueRequest(std::unique_ptr<Modifications> modifications);
+ Response ProcessAuthResponse(AuthChallengeResponse* auth_challenge_response);
+ Response ProcessResponseOverride(const std::string& response);
+ Response ProcessRedirectByClient(const std::string& location);
+ void SendResponse(const base::StringPiece& body);
+ void ApplyModificationsToRequest(
+ std::unique_ptr<Modifications> modifications);
+
+ void StartRequest();
+ void CancelRequest();
+ void Shutdown();
+
+ std::unique_ptr<InterceptedRequestInfo> BuildRequestInfo(
+ const network::ResourceResponseHead* head);
+ void NotifyClient(std::unique_ptr<InterceptedRequestInfo> request_info);
+
+ void ResponseBodyComplete();
+
+ bool ShouldBypassForResponse() const {
+ DCHECK_EQ(!!response_metadata_, !!body_reader_);
+ DCHECK_EQ(state_, State::kResponseReceived);
+ return !response_metadata_;
+ }
+
+ // network::mojom::URLLoader methods
+ void FollowRedirect() override;
+ void ProceedWithResponse() override;
+ void SetPriority(net::RequestPriority priority,
+ int32_t intra_priority_value) override;
+ void PauseReadingBodyFromNet() override;
+ void ResumeReadingBodyFromNet() override;
+
+ // network::mojom::URLLoaderClient methods
+ void OnReceiveResponse(
+ const network::ResourceResponseHead& head,
+ network::mojom::DownloadedTempFilePtr downloaded_file) override;
+ void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
+ const network::ResourceResponseHead& head) override;
+ void OnDataDownloaded(int64_t data_length, int64_t encoded_length) override;
+ void OnUploadProgress(int64_t current_position,
+ int64_t total_size,
+ OnUploadProgressCallback callback) override;
+ void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override;
+ void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
+ void OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body) override;
+ void OnComplete(const network::URLLoaderCompletionStatus& status) override;
+
+ const std::string id_;
+ const GlobalRequestId global_req_id_;
+ const base::UnguessableToken frame_token_;
+ const base::TimeTicks start_ticks_;
+ const base::Time start_time_;
+ const bool report_upload_;
+
+ DevToolsURLLoaderInterceptor::Impl* interceptor_;
+ InterceptionStage stage_;
+
+ std::unique_ptr<CreateLoaderParameters> create_loader_params_;
+
+ mojo::Binding<network::mojom::URLLoaderClient> client_binding_;
+ mojo::Binding<network::mojom::URLLoader> loader_binding_;
+
+ network::mojom::URLLoaderClientPtr client_;
+ network::mojom::URLLoaderPtr loader_;
+ network::mojom::URLLoaderFactoryPtr target_factory_;
+
+ enum State {
+ kNotStarted,
+ kRequestSent,
+ kRedirectReceived,
+ kAuthRequired,
+ kResponseReceived,
+ };
+
+ State state_;
+ bool waiting_for_resolution_;
+
+ std::unique_ptr<BodyReader> body_reader_;
+ std::unique_ptr<ResponseMetadata> response_metadata_;
+
+ base::Optional<std::pair<net::RequestPriority, int32_t>> priority_;
+ DevToolsURLLoaderInterceptor::HandleAuthRequestCallback
+ pending_auth_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(InterceptionJob);
+};
+
+} // namespace
+
+class DevToolsURLLoaderInterceptor::Impl
+ : public base::SupportsWeakPtr<DevToolsURLLoaderInterceptor::Impl> {
+ public:
+ explicit Impl(RequestInterceptedCallback callback)
+ : request_intercepted_callback_(callback) {}
+ ~Impl() {
+ for (auto const& entry : jobs_)
+ entry.second->Detach();
+ }
+
+ void CreateJob(const base::UnguessableToken& frame_token,
+ int32_t process_id,
+ std::unique_ptr<CreateLoaderParameters> create_params,
+ network::mojom::URLLoaderRequest loader_request,
+ network::mojom::URLLoaderClientPtr client,
+ network::mojom::URLLoaderFactoryPtr target_factory) {
+ DCHECK(!frame_token.is_empty());
+
+ 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), std::move(loader_request),
+ std::move(client), std::move(target_factory));
+ jobs_.emplace(std::move(id), job);
+ }
+
+ void SetPatterns(std::vector<DevToolsNetworkInterceptor::Pattern> patterns) {
+ patterns_ = std::move(patterns);
+ }
+
+ InterceptionStage GetInterceptionStage(const GURL& url,
+ ResourceType resource_type) const {
+ InterceptionStage stage = InterceptionStage::DONT_INTERCEPT;
+ std::string url_str = protocol::NetworkHandler::ClearUrlRef(url).spec();
+ for (const auto& pattern : patterns_) {
+ if (pattern.Matches(url_str, resource_type))
+ stage |= pattern.interception_stage;
+ }
+ return stage;
+ }
+
+ void GetResponseBody(
+ const std::string& interception_id,
+ std::unique_ptr<GetResponseBodyForInterceptionCallback> callback) {
+ if (InterceptionJob* job = FindJob(interception_id, &callback))
+ job->GetResponseBody(std::move(callback));
+ }
+
+ void ContinueInterceptedRequest(
+ const std::string& interception_id,
+ std::unique_ptr<Modifications> modifications,
+ std::unique_ptr<ContinueInterceptedRequestCallback> callback) {
+ if (InterceptionJob* job = FindJob(interception_id, &callback)) {
+ job->ContinueInterceptedRequest(std::move(modifications),
+ std::move(callback));
+ }
+ }
+
+ private:
+ friend class content::InterceptionJob;
+
+ template <typename Callback>
+ InterceptionJob* FindJob(const std::string& id,
+ std::unique_ptr<Callback>* callback) {
+ auto it = jobs_.find(id);
+ if (it != jobs_.end())
+ return it->second;
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(
+ &Callback::sendFailure, std::move(*callback),
+ protocol::Response::InvalidParams("Invalid InterceptionId.")));
+ return nullptr;
+ }
+
+ void RemoveJob(const std::string& id) { jobs_.erase(id); }
+
+ std::map<std::string, InterceptionJob*> jobs_;
+ RequestInterceptedCallback request_intercepted_callback_;
+ std::vector<DevToolsNetworkInterceptor::Pattern> patterns_;
+
+ DISALLOW_COPY_AND_ASSIGN(Impl);
+};
+
+class DevToolsURLLoaderFactoryProxy : public network::mojom::URLLoaderFactory {
+ public:
+ DevToolsURLLoaderFactoryProxy(
+ const base::UnguessableToken& frame_token,
+ int32_t process_id,
+ network::mojom::URLLoaderFactoryRequest loader_request,
+ network::mojom::URLLoaderFactoryPtrInfo target_factory_info,
+ base::WeakPtr<DevToolsURLLoaderInterceptor::Impl> interceptor);
+ ~DevToolsURLLoaderFactoryProxy() override;
+
+ private:
+ // network::mojom::URLLoaderFactory implementation
+ void CreateLoaderAndStart(network::mojom::URLLoaderRequest loader,
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const network::ResourceRequest& request,
+ network::mojom::URLLoaderClientPtr client,
+ const net::MutableNetworkTrafficAnnotationTag&
+ traffic_annotation) override;
+ void Clone(network::mojom::URLLoaderFactoryRequest request) override;
+
+ void StartOnIO(network::mojom::URLLoaderFactoryRequest loader_request,
+ network::mojom::URLLoaderFactoryPtrInfo target_factory_info);
+ void OnProxyBindingError();
+ void OnTargetFactoryError();
+
+ const base::UnguessableToken frame_token_;
+ const int32_t process_id_;
+
+ network::mojom::URLLoaderFactoryPtr target_factory_;
+ base::WeakPtr<DevToolsURLLoaderInterceptor::Impl> interceptor_;
+ mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+};
+
+DevToolsURLLoaderFactoryProxy::DevToolsURLLoaderFactoryProxy(
+ const base::UnguessableToken& frame_token,
+ int32_t process_id,
+ network::mojom::URLLoaderFactoryRequest loader_request,
+ network::mojom::URLLoaderFactoryPtrInfo target_factory_info,
+ base::WeakPtr<DevToolsURLLoaderInterceptor::Impl> interceptor)
+ : frame_token_(frame_token),
+ process_id_(process_id),
+ interceptor_(std::move(interceptor)) {
+ DETACH_FROM_SEQUENCE(sequence_checker_);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&DevToolsURLLoaderFactoryProxy::StartOnIO,
+ base::Unretained(this), std::move(loader_request),
+ std::move(target_factory_info)));
+}
+
+DevToolsURLLoaderFactoryProxy::~DevToolsURLLoaderFactoryProxy() {}
+
+void DevToolsURLLoaderFactoryProxy::CreateLoaderAndStart(
+ network::mojom::URLLoaderRequest loader,
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const network::ResourceRequest& request,
+ network::mojom::URLLoaderClientPtr client,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ DevToolsURLLoaderInterceptor::Impl* interceptor = interceptor_.get();
+ if (!interceptor_) {
+ target_factory_->CreateLoaderAndStart(
+ std::move(loader), routing_id, request_id, options, request,
+ std::move(client), traffic_annotation);
+ return;
+ }
+ auto creation_params = std::make_unique<CreateLoaderParameters>(
+ routing_id, request_id, options, request, traffic_annotation);
+ network::mojom::URLLoaderFactoryPtr factory_clone;
+ target_factory_->Clone(MakeRequest(&factory_clone));
+ interceptor->CreateJob(frame_token_, process_id_, std::move(creation_params),
+ std::move(loader), std::move(client),
+ std::move(factory_clone));
+}
+
+void DevToolsURLLoaderFactoryProxy::StartOnIO(
+ network::mojom::URLLoaderFactoryRequest loader_request,
+ network::mojom::URLLoaderFactoryPtrInfo target_factory_info) {
+ target_factory_.Bind(std::move(target_factory_info));
+ target_factory_.set_connection_error_handler(
+ base::BindOnce(&DevToolsURLLoaderFactoryProxy::OnTargetFactoryError,
+ base::Unretained(this)));
+
+ bindings_.AddBinding(this, std::move(loader_request));
+ bindings_.set_connection_error_handler(
+ base::BindRepeating(&DevToolsURLLoaderFactoryProxy::OnProxyBindingError,
+ base::Unretained(this)));
+}
+
+void DevToolsURLLoaderFactoryProxy::Clone(
+ network::mojom::URLLoaderFactoryRequest request) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ bindings_.AddBinding(this, std::move(request));
+}
+
+void DevToolsURLLoaderFactoryProxy::OnTargetFactoryError() {
+ DCHECK(!target_factory_.is_bound());
+ delete this;
+}
+
+void DevToolsURLLoaderFactoryProxy::OnProxyBindingError() {
+ if (bindings_.empty())
+ delete this;
+}
+
+// static
+void DevToolsURLLoaderInterceptor::HandleAuthRequest(
+ int32_t process_id,
+ int32_t routing_id,
+ int32_t request_id,
+ const scoped_refptr<net::AuthChallengeInfo>& auth_info,
+ HandleAuthRequestCallback callback) {
+ GlobalRequestId req_id = std::make_tuple(process_id, routing_id, request_id);
+ if (auto* job = InterceptionJob::FindByRequestId(req_id))
+ job->OnAuthRequest(auth_info, std::move(callback));
+ else
+ std::move(callback).Run(true, base::nullopt);
+}
+
+DevToolsURLLoaderInterceptor::DevToolsURLLoaderInterceptor(
+ FrameTreeNode* const local_root,
+ RequestInterceptedCallback callback)
+ : local_root_(local_root),
+ enabled_(false),
+ impl_(new DevToolsURLLoaderInterceptor::Impl(std::move(callback)),
+ base::OnTaskRunnerDeleter(
+ BrowserThread::GetTaskRunnerForThread(BrowserThread::IO))),
+ weak_impl_(impl_->AsWeakPtr()) {}
+
+DevToolsURLLoaderInterceptor::~DevToolsURLLoaderInterceptor() {
+ UpdateSubresourceLoaderFactories();
+};
+
+void DevToolsURLLoaderInterceptor::UpdateSubresourceLoaderFactories() {
+ base::queue<FrameTreeNode*> queue;
+ queue.push(local_root_);
+ while (!queue.empty()) {
+ FrameTreeNode* node = queue.front();
+ queue.pop();
+ RenderFrameHostImpl* host = node->current_frame_host();
+ if (node != local_root_ && host->IsCrossProcessSubframe())
+ continue;
+ host->UpdateSubresourceLoaderFactories();
+ for (size_t i = 0; i < node->child_count(); ++i)
+ queue.push(node->child_at(i));
+ }
+}
+
+void DevToolsURLLoaderInterceptor::SetPatterns(
+ std::vector<DevToolsNetworkInterceptor::Pattern> patterns) {
+ if (enabled_ != !!patterns.size()) {
+ enabled_ = !!patterns.size();
+ UpdateSubresourceLoaderFactories();
+ }
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&Impl::SetPatterns, base::Unretained(impl_.get()),
+ std::move(patterns)));
+}
+
+void DevToolsURLLoaderInterceptor::GetResponseBody(
+ const std::string& interception_id,
+ std::unique_ptr<GetResponseBodyForInterceptionCallback> callback) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&Impl::GetResponseBody, base::Unretained(impl_.get()),
+ interception_id, std::move(callback)));
+}
+
+void DevToolsURLLoaderInterceptor::ContinueInterceptedRequest(
+ const std::string& interception_id,
+ std::unique_ptr<Modifications> modifications,
+ std::unique_ptr<ContinueInterceptedRequestCallback> callback) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&Impl::ContinueInterceptedRequest,
+ base::Unretained(impl_.get()), interception_id,
+ std::move(modifications), std::move(callback)));
+}
+
+bool DevToolsURLLoaderInterceptor::CreateProxyForInterception(
+ const base::UnguessableToken frame_token,
+ int process_id,
+ network::mojom::URLLoaderFactoryRequest* request) const {
+ if (!enabled_)
+ return false;
+ network::mojom::URLLoaderFactoryRequest original_request =
+ std::move(*request);
+ network::mojom::URLLoaderFactoryPtrInfo target_ptr_info;
+ *request = MakeRequest(&target_ptr_info);
+
+ new DevToolsURLLoaderFactoryProxy(frame_token, process_id,
+ std::move(original_request),
+ std::move(target_ptr_info), weak_impl_);
+ return true;
+}
+
+InterceptionJob::InterceptionJob(
+ DevToolsURLLoaderInterceptor::Impl* interceptor,
+ const std::string& id,
+ const base::UnguessableToken& frame_token,
+ int process_id,
+ std::unique_ptr<CreateLoaderParameters> create_loader_params,
+ network::mojom::URLLoaderRequest loader_request,
+ network::mojom::URLLoaderClientPtr client,
+ network::mojom::URLLoaderFactoryPtr target_factory)
+ : id_(std::move(id)),
+ global_req_id_(
+ std::make_tuple(process_id,
+ create_loader_params->request.render_frame_id,
+ create_loader_params->request_id)),
+ frame_token_(frame_token),
+ start_ticks_(base::TimeTicks::Now()),
+ start_time_(base::Time::Now()),
+ report_upload_(!!create_loader_params->request.request_body),
+ interceptor_(interceptor),
+ create_loader_params_(std::move(create_loader_params)),
+ client_binding_(this),
+ loader_binding_(this),
+ client_(std::move(client)),
+ target_factory_(std::move(target_factory)),
+ state_(kNotStarted),
+ waiting_for_resolution_(false) {
+ const network::ResourceRequest& request = create_loader_params_->request;
+ stage_ = interceptor_->GetInterceptionStage(
+ request.url, static_cast<ResourceType>(request.resource_type));
+
+ loader_binding_.Bind(std::move(loader_request));
+ loader_binding_.set_connection_error_handler(
+ base::BindOnce(&InterceptionJob::Shutdown, base::Unretained(this)));
+
+ auto& job_map = GetInterceptionJobMap();
+ bool inserted = job_map.emplace(global_req_id_, this).second;
+ DCHECK(inserted);
+
+ if (stage_ & InterceptionStage::REQUEST) {
+ NotifyClient(BuildRequestInfo(nullptr));
+ return;
+ }
+
+ StartRequest();
+}
+
+void InterceptionJob::GetResponseBody(
+ std::unique_ptr<GetResponseBodyForInterceptionCallback> callback) {
+ std::string error_reason;
+
+ if (!(stage_ & InterceptionStage::RESPONSE)) {
+ error_reason =
+ "Can only get response body on HeadersReceived pattern matched "
+ "requests.";
+ } else if (state_ != kResponseReceived) {
+ DCHECK(waiting_for_resolution_);
+ error_reason =
+ "Can only get response body on requests captured after headers "
+ "received.";
+ }
+ if (!error_reason.empty()) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&GetResponseBodyForInterceptionCallback::sendFailure,
+ std::move(callback),
+ Response::Error(std::move(error_reason))));
+ return;
+ }
+
+ if (!body_reader_) {
+ body_reader_ = std::make_unique<BodyReader>(base::BindOnce(
+ &InterceptionJob::ResponseBodyComplete, base::Unretained(this)));
+ client_binding_.ResumeIncomingMethodCallProcessing();
+ loader_->ResumeReadingBodyFromNet();
+ }
+ body_reader_->AddCallback(std::move(callback));
+}
+
+void InterceptionJob::ContinueInterceptedRequest(
+ std::unique_ptr<Modifications> modifications,
+ std::unique_ptr<ContinueInterceptedRequestCallback> callback) {
+ Response response = InnerContinueRequest(std::move(modifications));
+ // |this| may be destroyed at this pont.
+ bool success = response.isSuccess();
+ base::OnceClosure task =
+ success ? base::BindOnce(&ContinueInterceptedRequestCallback::sendSuccess,
+ std::move(callback))
+ : base::BindOnce(&ContinueInterceptedRequestCallback::sendFailure,
+ std::move(callback), std::move(response));
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, std::move(task));
+}
+
+void InterceptionJob::Detach() {
+ stage_ = InterceptionStage::DONT_INTERCEPT;
+ interceptor_ = nullptr;
+ if (!waiting_for_resolution_)
+ return;
+ if (state_ == State::kAuthRequired) {
+ state_ = State::kRequestSent;
+ waiting_for_resolution_ = false;
+ std::move(pending_auth_callback_).Run(true, base::nullopt);
+ return;
+ }
+ InnerContinueRequest(std::make_unique<Modifications>());
+}
+
+Response InterceptionJob::InnerContinueRequest(
+ std::unique_ptr<Modifications> modifications) {
+ if (!waiting_for_resolution_)
+ return Response::Error("Invalid state for continueInterceptedRequest");
+ waiting_for_resolution_ = false;
+
+ if (state_ == State::kAuthRequired) {
+ if (!modifications->auth_challenge_response.isJust())
+ return Response::InvalidParams("authChallengeResponse required.");
+ return ProcessAuthResponse(
+ modifications->auth_challenge_response.fromJust());
+ } else if (modifications->auth_challenge_response.isJust()) {
+ return Response::InvalidParams("authChallengeResponse not expected.");
+ }
+
+ if (modifications->mark_as_canceled || modifications->error_reason) {
+ int error = modifications->error_reason
+ ? *modifications->error_reason
+ : (modifications->mark_as_canceled ? net::ERR_ABORTED
+ : net::ERR_FAILED);
+ network::URLLoaderCompletionStatus status(error);
+ status.completion_time = base::TimeTicks::Now();
+ client_->OnComplete(status);
+ Shutdown();
+ return Response::OK();
+ }
+
+ if (modifications->raw_response)
+ return ProcessResponseOverride(*modifications->raw_response);
+
+ if (state_ == State::kRedirectReceived) {
+ // TODO(caseq): report error if other modifications are present.
+ if (modifications->modified_url.isJust()) {
+ std::string location = modifications->modified_url.fromJust();
+ CancelRequest();
+ auto* headers = response_metadata_->head.headers.get();
+ headers->RemoveHeader("location");
+ headers->AddHeader("location: " + location);
+ return ProcessRedirectByClient(location);
+ }
+ client_->OnReceiveRedirect(*response_metadata_->redirect_info,
+ response_metadata_->head);
+ return Response::OK();
+ }
+
+ if (body_reader_) {
+ if (body_reader_->data_complete())
+ SendResponse(body_reader_->body());
+
+ // There are read callbacks pending, so let the reader do its job and come
+ // back when it's done.
+ return Response::OK();
+ }
+
+ if (response_metadata_) {
+ // TODO(caseq): report error if other modifications are present.
+ DCHECK_EQ(State::kResponseReceived, state_);
+ DCHECK(!body_reader_);
+ client_->OnReceiveResponse(response_metadata_->head,
+ std::move(response_metadata_->downloaded_file));
+ response_metadata_.reset();
+ loader_->ResumeReadingBodyFromNet();
+ client_binding_.ResumeIncomingMethodCallProcessing();
+ return Response::OK();
+ }
+
+ DCHECK_EQ(State::kNotStarted, state_);
+ ApplyModificationsToRequest(std::move(modifications));
+ StartRequest();
+ return Response::OK();
+}
+
+void InterceptionJob::ApplyModificationsToRequest(
+ std::unique_ptr<Modifications> modifications) {
+ network::ResourceRequest* request = &create_loader_params_->request;
+
+ // Note this redirect is not visible to the page by design. If they want a
+ // visible redirect they can mock a response with a 302.
+ if (modifications->modified_url.isJust())
+ request->url = GURL(modifications->modified_url.fromJust());
+
+ if (modifications->modified_method.isJust())
+ request->method = modifications->modified_method.fromJust();
+
+ if (modifications->modified_post_data.isJust()) {
+ const std::string& post_data = modifications->modified_post_data.fromJust();
+ request->request_body = network::ResourceRequestBody::CreateFromBytes(
+ post_data.data(), post_data.size());
+ }
+
+ if (modifications->modified_headers.isJust()) {
+ request->headers.Clear();
+ std::unique_ptr<protocol::DictionaryValue> headers =
+ modifications->modified_headers.fromJust()->toValue();
+ for (size_t i = 0; i < headers->size(); i++) {
+ protocol::DictionaryValue::Entry entry = headers->at(i);
+ std::string value;
+ if (!entry.second->asString(&value))
+ continue;
+ if (base::EqualsCaseInsensitiveASCII(entry.first,
+ net::HttpRequestHeaders::kReferer)) {
+ request->referrer = GURL(value);
+ request->referrer_policy = net::URLRequest::NEVER_CLEAR_REFERRER;
+ } else {
+ request->headers.SetHeader(entry.first, value);
+ }
+ }
+ }
+}
+
+Response InterceptionJob::ProcessAuthResponse(
+ AuthChallengeResponse* auth_challenge_response) {
+ std::string response = auth_challenge_response->GetResponse();
+ state_ = State::kRequestSent;
+ if (response == AuthChallengeResponse::ResponseEnum::Default) {
+ std::move(pending_auth_callback_).Run(true, base::nullopt);
+ } else if (response == AuthChallengeResponse::ResponseEnum::CancelAuth) {
+ std::move(pending_auth_callback_).Run(false, base::nullopt);
+ } else if (response ==
+ AuthChallengeResponse::ResponseEnum::ProvideCredentials) {
+ net::AuthCredentials credentials(
+ base::UTF8ToUTF16(auth_challenge_response->GetUsername("")),
+ base::UTF8ToUTF16(auth_challenge_response->GetPassword("")));
+ std::move(pending_auth_callback_).Run(false, std::move(credentials));
+ } else {
+ return Response::InvalidParams("Unrecognized authChallengeResponse.");
+ }
+
+ return Response::OK();
+}
+
+Response InterceptionJob::ProcessResponseOverride(const std::string& response) {
+ CancelRequest();
+
+ std::string raw_headers;
+ int header_size =
+ net::HttpUtil::LocateEndOfHeaders(response.c_str(), response.size());
+ if (header_size == -1) {
+ LOG(WARNING) << "Can't find headers in result";
+ header_size = 0;
+ } else {
+ raw_headers =
+ net::HttpUtil::AssembleRawHeaders(response.c_str(), header_size);
+ }
+ CHECK_LE(static_cast<size_t>(header_size), response.size());
+ size_t body_size = response.size() - header_size;
+
+ response_metadata_ = std::make_unique<ResponseMetadata>();
+ network::ResourceResponseHead* head = &response_metadata_->head;
+
+ head->request_time = start_time_;
+ head->response_time = base::Time::Now();
+ head->headers = new net::HttpResponseHeaders(std::move(raw_headers));
+ head->headers->GetMimeTypeAndCharset(&head->mime_type, &head->charset);
+ if (head->mime_type.empty()) {
+ net::SniffMimeType(response.data() + header_size, body_size,
+ create_loader_params_->request.url, "",
+ net::ForceSniffFileUrlsForHtml::kDisabled,
+ &head->mime_type);
+ }
+ head->content_length = body_size;
+ head->encoded_data_length = header_size;
+ head->encoded_body_length = 0;
+ head->request_start = start_ticks_;
+ head->response_start = base::TimeTicks::Now();
+
+ std::string location_url;
+ if (head->headers->IsRedirect(&location_url))
+ return ProcessRedirectByClient(location_url);
+
+ response_metadata_->transfer_size = body_size;
+
+ response_metadata_->status.completion_time = base::TimeTicks::Now();
+ response_metadata_->status.encoded_data_length = response.size();
+ response_metadata_->status.encoded_body_length = body_size;
+ response_metadata_->status.decoded_body_length = body_size;
+
+ SendResponse(base::StringPiece(response.data() + header_size, body_size));
+ return Response::OK();
+}
+
+Response InterceptionJob::ProcessRedirectByClient(const std::string& location) {
+ GURL redirect_url = create_loader_params_->request.url.Resolve(location);
+
+ if (!redirect_url.is_valid())
+ return Response::Error("Invalid redirect URL in overriden headers");
+
+ const net::HttpResponseHeaders& headers = *response_metadata_->head.headers;
+ const network::ResourceRequest& request = create_loader_params_->request;
+
+ auto first_party_url_policy =
+ request.update_first_party_url_on_redirect
+ ? net::URLRequest::FirstPartyURLPolicy::
+ UPDATE_FIRST_PARTY_URL_ON_REDIRECT
+ : net::URLRequest::FirstPartyURLPolicy::NEVER_CHANGE_FIRST_PARTY_URL;
+
+ response_metadata_->redirect_info = std::make_unique<net::RedirectInfo>(
+ net::RedirectInfo::ComputeRedirectInfo(
+ request.method, request.url, request.site_for_cookies,
+ first_party_url_policy, request.referrer_policy,
+ request.referrer.spec(), &headers, headers.response_code(),
+ redirect_url, false /* token_binding_negotiated */,
+ false /* copy_fragment */));
+
+ client_->OnReceiveRedirect(*response_metadata_->redirect_info,
+ response_metadata_->head);
+ return Response::OK();
+}
+
+void InterceptionJob::SendResponse(const base::StringPiece& body) {
+ client_->OnReceiveResponse(response_metadata_->head,
+ std::move(response_metadata_->downloaded_file));
+
+ // We shouldn't be able to transfer a string that big over the protocol,
+ // but just in case...
+ DCHECK_LE(body.size(), UINT32_MAX)
+ << "Response bodies larger than " << UINT32_MAX << " are not supported";
+ mojo::DataPipe pipe(body.size());
+ uint32_t num_bytes = body.size();
+ MojoResult res = pipe.producer_handle->WriteData(body.data(), &num_bytes,
+ MOJO_WRITE_DATA_FLAG_NONE);
+ DCHECK_EQ(0u, res);
+ DCHECK_EQ(num_bytes, body.size());
+
+ if (!response_metadata_->cached_metadata.empty())
+ client_->OnReceiveCachedMetadata(response_metadata_->cached_metadata);
+ client_->OnStartLoadingResponseBody(std::move(pipe.consumer_handle));
+ if (response_metadata_->transfer_size)
+ client_->OnTransferSizeUpdated(response_metadata_->transfer_size);
+
+ client_->OnComplete(response_metadata_->status);
+ Shutdown();
+}
+
+void InterceptionJob::ResponseBodyComplete() {
+ if (waiting_for_resolution_)
+ return;
+ // We're here only if client has already told us to proceed with unmodified
+ // response.
+ SendResponse(body_reader_->body());
+}
+
+void InterceptionJob::StartRequest() {
+ DCHECK_EQ(State::kNotStarted, state_);
+ DCHECK(!response_metadata_);
+
+ state_ = State::kRequestSent;
+
+ network::mojom::URLLoaderClientPtr loader_client;
+ client_binding_.Bind(MakeRequest(&loader_client));
+ client_binding_.set_connection_error_handler(
+ base::BindOnce(&InterceptionJob::Shutdown, base::Unretained(this)));
+
+ target_factory_->CreateLoaderAndStart(
+ MakeRequest(&loader_), create_loader_params_->routing_id,
+ create_loader_params_->request_id, create_loader_params_->options,
+ create_loader_params_->request, std::move(loader_client),
+ create_loader_params_->traffic_annotation);
+
+ if (priority_)
+ loader_->SetPriority(priority_->first, priority_->second);
+}
+
+void InterceptionJob::CancelRequest() {
+ if (state_ == State::kNotStarted)
+ return;
+ client_binding_.Close();
+ loader_.reset();
+ if (body_reader_) {
+ body_reader_->CancelWithError(
+ "Another command has cancelled the fetch request");
+ body_reader_.reset();
+ }
+ state_ = State::kNotStarted;
+}
+
+std::unique_ptr<InterceptedRequestInfo> InterceptionJob::BuildRequestInfo(
+ const network::ResourceResponseHead* head) {
+ auto result = std::make_unique<InterceptedRequestInfo>();
+ result->interception_id = id_;
+ result->network_request =
+ protocol::NetworkHandler::CreateRequestFromResourceRequest(
+ create_loader_params_->request);
+ result->frame_id = frame_token_;
+ ResourceType resource_type =
+ static_cast<ResourceType>(create_loader_params_->request.resource_type);
+ result->resource_type = resource_type;
+ result->is_navigation = resource_type == RESOURCE_TYPE_MAIN_FRAME ||
+ resource_type == RESOURCE_TYPE_SUB_FRAME;
+
+ // TODO(caseq): merge with NetworkHandler::BuildResponse()
+ if (head && head->headers) {
+ result->http_response_status_code = head->headers->response_code();
+ auto headers_dict = protocol::DictionaryValue::create();
+ size_t iter = 0;
+ std::string name;
+ std::string value;
+ while (head->headers->EnumerateHeaderLines(&iter, &name, &value)) {
+ std::string old_value;
+ bool merge_with_another = headers_dict->getString(name, &old_value);
+ headers_dict->setString(
+ name, merge_with_another ? old_value + '\n' + value : value);
+ }
+ result->response_headers =
+ protocol::Object::fromValue(headers_dict.get(), nullptr);
+ }
+ return result;
+}
+
+void InterceptionJob::NotifyClient(
+ std::unique_ptr<InterceptedRequestInfo> request_info) {
+ waiting_for_resolution_ = true;
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(interceptor_->request_intercepted_callback_,
+ std::move(request_info)));
+}
+
+void InterceptionJob::Shutdown() {
+ if (interceptor_)
+ interceptor_->RemoveJob(id_);
+ delete this;
+}
+
+// URLLoader methods
+void InterceptionJob::FollowRedirect() {
+ DCHECK(!waiting_for_resolution_);
+
+ network::ResourceRequest* request = &create_loader_params_->request;
+ const net::RedirectInfo& info = *response_metadata_->redirect_info;
+ request->method = info.new_method;
+ request->url = info.new_url;
+ request->site_for_cookies = info.new_site_for_cookies;
+ request->referrer_policy = info.new_referrer_policy;
+ request->referrer = GURL(info.new_referrer);
+ response_metadata_.reset();
+ if (interceptor_) {
+ stage_ = interceptor_->GetInterceptionStage(
+ request->url, static_cast<ResourceType>(request->resource_type));
+ }
+ if (state_ == State::kRedirectReceived) {
+ state_ = State::kRequestSent;
+ loader_->FollowRedirect();
+ return;
+ }
+
+ DCHECK_EQ(State::kNotStarted, state_);
+ StartRequest();
+}
+
+void InterceptionJob::ProceedWithResponse() {
+ NOTREACHED();
+}
+
+void InterceptionJob::SetPriority(net::RequestPriority priority,
+ int32_t intra_priority_value) {
+ priority_ = std::make_pair(priority, intra_priority_value);
+
+ if (state_ != State::kNotStarted)
+ loader_->SetPriority(priority, intra_priority_value);
+}
+
+void InterceptionJob::PauseReadingBodyFromNet() {
+ if (state_ != State::kNotStarted && !body_reader_)
+ loader_->PauseReadingBodyFromNet();
+}
+
+void InterceptionJob::ResumeReadingBodyFromNet() {
+ if (state_ != State::kNotStarted && !body_reader_)
+ loader_->ResumeReadingBodyFromNet();
+}
+
+// URLLoaderClient methods
+void InterceptionJob::OnReceiveResponse(
+ const network::ResourceResponseHead& head,
+ network::mojom::DownloadedTempFilePtr downloaded_file) {
+ state_ = State::kResponseReceived;
+ DCHECK(!response_metadata_);
+ if (!(stage_ & InterceptionStage::RESPONSE)) {
+ client_->OnReceiveResponse(head, std::move(downloaded_file));
+ return;
+ }
+ loader_->PauseReadingBodyFromNet();
+ client_binding_.PauseIncomingMethodCallProcessing();
+
+ response_metadata_ = std::make_unique<ResponseMetadata>(head);
+ response_metadata_->downloaded_file = std::move(downloaded_file);
+
+ NotifyClient(BuildRequestInfo(&head));
+}
+
+void InterceptionJob::OnReceiveRedirect(
+ const net::RedirectInfo& redirect_info,
+ const network::ResourceResponseHead& head) {
+ DCHECK_EQ(State::kRequestSent, state_);
+ state_ = State::kRedirectReceived;
+ response_metadata_ = std::make_unique<ResponseMetadata>(head);
+ response_metadata_->redirect_info =
+ std::make_unique<net::RedirectInfo>(redirect_info);
+
+ if (!(stage_ & InterceptionStage::REQUEST)) {
+ client_->OnReceiveRedirect(redirect_info, head);
+ return;
+ }
+
+ std::unique_ptr<InterceptedRequestInfo> request_info =
+ BuildRequestInfo(&head);
+ request_info->http_response_status_code = redirect_info.status_code;
+ request_info->redirect_url = redirect_info.new_url.spec();
+ NotifyClient(std::move(request_info));
+}
+
+void InterceptionJob::OnDataDownloaded(int64_t data_length,
+ int64_t encoded_length) {
+ if (ShouldBypassForResponse())
+ client_->OnDataDownloaded(data_length, encoded_length);
+}
+
+void InterceptionJob::OnUploadProgress(int64_t current_position,
+ int64_t total_size,
+ OnUploadProgressCallback callback) {
+ if (!report_upload_)
+ return;
+ client_->OnUploadProgress(current_position, total_size, std::move(callback));
+}
+
+void InterceptionJob::OnReceiveCachedMetadata(
+ const std::vector<uint8_t>& data) {
+ if (ShouldBypassForResponse())
+ client_->OnReceiveCachedMetadata(data);
+ else
+ response_metadata_->cached_metadata = data;
+}
+
+void InterceptionJob::OnTransferSizeUpdated(int32_t transfer_size_diff) {
+ if (ShouldBypassForResponse())
+ client_->OnTransferSizeUpdated(transfer_size_diff);
+ else
+ response_metadata_->transfer_size += transfer_size_diff;
+}
+
+void InterceptionJob::OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body) {
+ if (ShouldBypassForResponse())
+ client_->OnStartLoadingResponseBody(std::move(body));
+ else
+ body_reader_->StartReading(std::move(body));
+}
+
+void InterceptionJob::OnComplete(
+ const network::URLLoaderCompletionStatus& status) {
+ if (ShouldBypassForResponse()) {
+ client_->OnComplete(status);
+ Shutdown();
+ return;
+ }
+ response_metadata_->status = status;
+}
+
+void InterceptionJob::OnAuthRequest(
+ const scoped_refptr<net::AuthChallengeInfo>& auth_info,
+ DevToolsURLLoaderInterceptor::HandleAuthRequestCallback callback) {
+ DCHECK_EQ(kRequestSent, state_);
+ DCHECK(pending_auth_callback_.is_null());
+ DCHECK(!waiting_for_resolution_);
+
+ if (!(stage_ & InterceptionStage::REQUEST)) {
+ std::move(callback).Run(true, base::nullopt);
+ return;
+ }
+ state_ = State::kAuthRequired;
+ auto request_info = BuildRequestInfo(nullptr);
+ request_info->auth_challenge =
+ protocol::Network::AuthChallenge::Create()
+ .SetSource(auth_info->is_proxy
+ ? protocol::Network::AuthChallenge::SourceEnum::Proxy
+ : protocol::Network::AuthChallenge::SourceEnum::Server)
+ .SetOrigin(auth_info->challenger.Serialize())
+ .SetScheme(auth_info->scheme)
+ .SetRealm(auth_info->realm)
+ .Build();
+ pending_auth_callback_ = std::move(callback);
+ NotifyClient(std::move(request_info));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_url_loader_interceptor.h b/chromium/content/browser/devtools/devtools_url_loader_interceptor.h
new file mode 100644
index 00000000000..a05c8bc1f56
--- /dev/null
+++ b/chromium/content/browser/devtools/devtools_url_loader_interceptor.h
@@ -0,0 +1,68 @@
+// Copyright 2018 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.
+
+#ifndef CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_URL_LOADER_INTERCEPTOR_H_
+#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_URL_LOADER_INTERCEPTOR_H_
+
+#include "base/memory/weak_ptr.h"
+#include "content/browser/devtools/devtools_network_interceptor.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+
+namespace content {
+
+class FrameTreeNode;
+
+class DevToolsURLLoaderInterceptor {
+ public:
+ class Impl;
+
+ using HandleAuthRequestCallback =
+ base::OnceCallback<void(bool use_fallback,
+ const base::Optional<net::AuthCredentials>&)>;
+ // Can only be called on the IO thread.
+ static void HandleAuthRequest(
+ int32_t process_id,
+ int32_t routing_id,
+ int32_t request_id,
+ const scoped_refptr<net::AuthChallengeInfo>& auth_info,
+ HandleAuthRequestCallback callback);
+
+ DevToolsURLLoaderInterceptor(
+ FrameTreeNode* local_root,
+ DevToolsNetworkInterceptor::RequestInterceptedCallback callback);
+ ~DevToolsURLLoaderInterceptor();
+
+ void SetPatterns(std::vector<DevToolsNetworkInterceptor::Pattern> patterns);
+
+ void GetResponseBody(
+ const std::string& interception_id,
+ std::unique_ptr<
+ DevToolsNetworkInterceptor::GetResponseBodyForInterceptionCallback>
+ callback);
+ void ContinueInterceptedRequest(
+ const std::string& interception_id,
+ std::unique_ptr<DevToolsNetworkInterceptor::Modifications> modifications,
+ std::unique_ptr<
+ DevToolsNetworkInterceptor::ContinueInterceptedRequestCallback>
+ callback);
+
+ bool CreateProxyForInterception(
+ const base::UnguessableToken frame_token,
+ int process_id, // 0 for navigation
+ network::mojom::URLLoaderFactoryRequest* request) const;
+
+ private:
+ void UpdateSubresourceLoaderFactories();
+
+ FrameTreeNode* const local_root_;
+ bool enabled_;
+ std::unique_ptr<Impl, base::OnTaskRunnerDeleter> impl_;
+ base::WeakPtr<Impl> weak_impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(DevToolsURLLoaderInterceptor);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_URL_LOADER_INTERCEPTOR_H_
diff --git a/chromium/content/browser/devtools/devtools_url_request_interceptor.cc b/chromium/content/browser/devtools/devtools_url_request_interceptor.cc
index 3f361e8e0c5..260a5206a1f 100644
--- a/chromium/content/browser/devtools/devtools_url_request_interceptor.cc
+++ b/chromium/content/browser/devtools/devtools_url_request_interceptor.cc
@@ -4,7 +4,6 @@
#include "content/browser/devtools/devtools_url_request_interceptor.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/pattern.h"
#include "base/strings/stringprintf.h"
#include "content/browser/devtools/devtools_interceptor_controller.h"
@@ -42,20 +41,6 @@ DevToolsURLRequestInterceptor::~DevToolsURLRequestInterceptor() {
// DevToolsURLRequestInterceptorUserData explicitly.
}
-DevToolsURLRequestInterceptor::Pattern::Pattern() = default;
-
-DevToolsURLRequestInterceptor::Pattern::~Pattern() = default;
-
-DevToolsURLRequestInterceptor::Pattern::Pattern(const Pattern& other) = default;
-
-DevToolsURLRequestInterceptor::Pattern::Pattern(
- const std::string& url_pattern,
- base::flat_set<ResourceType> resource_types,
- InterceptionStage interception_stage)
- : url_pattern(url_pattern),
- resource_types(std::move(resource_types)),
- interception_stage(interception_stage) {}
-
const DevToolsTargetRegistry::TargetInfo*
DevToolsURLRequestInterceptor::TargetInfoForRequestInfo(
const ResourceRequestInfo* request_info) const {
@@ -318,25 +303,4 @@ void DevToolsURLRequestInterceptor::JobFinished(
controller_, interception_id));
}
-DevToolsURLRequestInterceptor::Modifications::Modifications(
- base::Optional<net::Error> error_reason,
- base::Optional<std::string> raw_response,
- protocol::Maybe<std::string> modified_url,
- protocol::Maybe<std::string> modified_method,
- protocol::Maybe<std::string> modified_post_data,
- protocol::Maybe<protocol::Network::Headers> modified_headers,
- protocol::Maybe<protocol::Network::AuthChallengeResponse>
- auth_challenge_response,
- bool mark_as_canceled)
- : error_reason(std::move(error_reason)),
- raw_response(std::move(raw_response)),
- modified_url(std::move(modified_url)),
- modified_method(std::move(modified_method)),
- modified_post_data(std::move(modified_post_data)),
- modified_headers(std::move(modified_headers)),
- auth_challenge_response(std::move(auth_challenge_response)),
- mark_as_canceled(mark_as_canceled) {}
-
-DevToolsURLRequestInterceptor::Modifications::~Modifications() {}
-
} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_video_consumer.cc b/chromium/content/browser/devtools/devtools_video_consumer.cc
new file mode 100644
index 00000000000..8c9bdd44ade
--- /dev/null
+++ b/chromium/content/browser/devtools/devtools_video_consumer.cc
@@ -0,0 +1,169 @@
+// Copyright 2018 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_video_consumer.h"
+
+#include "cc/paint/skia_paint_canvas.h"
+#include "components/viz/host/host_frame_sink_manager.h"
+#include "components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h"
+#include "content/browser/compositor/surface_utils.h"
+#include "media/base/limits.h"
+#include "media/renderers/paint_canvas_video_renderer.h"
+
+namespace content {
+
+namespace {
+
+// Frame capture period is 10 frames per second by default.
+constexpr base::TimeDelta kDefaultMinCapturePeriod =
+ base::TimeDelta::FromMilliseconds(100);
+
+// Frame size can change every frame.
+constexpr base::TimeDelta kDefaultMinPeriod = base::TimeDelta();
+
+// Allow variable aspect ratio.
+const bool kDefaultUseFixedAspectRatio = false;
+
+} // namespace
+
+// static
+constexpr gfx::Size DevToolsVideoConsumer::kDefaultMinFrameSize;
+
+// static
+constexpr gfx::Size DevToolsVideoConsumer::kDefaultMaxFrameSize;
+
+DevToolsVideoConsumer::DevToolsVideoConsumer(OnFrameCapturedCallback callback)
+ : callback_(std::move(callback)),
+ min_capture_period_(kDefaultMinCapturePeriod),
+ min_frame_size_(kDefaultMinFrameSize),
+ max_frame_size_(kDefaultMaxFrameSize),
+ binding_(this) {}
+
+DevToolsVideoConsumer::~DevToolsVideoConsumer() = default;
+
+// static
+SkBitmap DevToolsVideoConsumer::GetSkBitmapFromFrame(
+ scoped_refptr<media::VideoFrame> frame) {
+ media::PaintCanvasVideoRenderer renderer;
+ SkBitmap skbitmap;
+ skbitmap.allocN32Pixels(frame->visible_rect().width(),
+ frame->visible_rect().height());
+ cc::SkiaPaintCanvas canvas(skbitmap);
+ renderer.Copy(frame, &canvas, media::Context3D());
+ return skbitmap;
+}
+
+void DevToolsVideoConsumer::StartCapture() {
+ if (capturer_)
+ return;
+ InnerStartCapture(CreateCapturer());
+}
+
+void DevToolsVideoConsumer::StopCapture() {
+ if (!capturer_)
+ return;
+ binding_.Close();
+ capturer_->Stop();
+ capturer_.reset();
+}
+
+void DevToolsVideoConsumer::SetFrameSinkId(
+ const viz::FrameSinkId& frame_sink_id) {
+ frame_sink_id_ = frame_sink_id;
+ if (capturer_)
+ capturer_->ChangeTarget(frame_sink_id_);
+}
+
+void DevToolsVideoConsumer::SetMinCapturePeriod(
+ base::TimeDelta min_capture_period) {
+ min_capture_period_ = min_capture_period;
+ if (capturer_)
+ capturer_->SetMinCapturePeriod(min_capture_period_);
+}
+
+void DevToolsVideoConsumer::SetMinAndMaxFrameSize(gfx::Size min_frame_size,
+ gfx::Size max_frame_size) {
+ DCHECK(IsValidMinAndMaxFrameSize(min_frame_size, max_frame_size));
+ min_frame_size_ = min_frame_size;
+ max_frame_size_ = max_frame_size;
+ if (capturer_) {
+ capturer_->SetResolutionConstraints(min_frame_size_, max_frame_size_,
+ kDefaultUseFixedAspectRatio);
+ }
+}
+
+viz::mojom::FrameSinkVideoCapturerPtrInfo
+DevToolsVideoConsumer::CreateCapturer() {
+ viz::HostFrameSinkManager* const manager = GetHostFrameSinkManager();
+ viz::mojom::FrameSinkVideoCapturerPtr capturer;
+ manager->CreateVideoCapturer(mojo::MakeRequest(&capturer));
+ return capturer.PassInterface();
+}
+
+void DevToolsVideoConsumer::InnerStartCapture(
+ viz::mojom::FrameSinkVideoCapturerPtrInfo capturer_info) {
+ capturer_.Bind(std::move(capturer_info));
+
+ // Give |capturer_| the capture parameters.
+ capturer_->SetMinCapturePeriod(min_capture_period_);
+ capturer_->SetMinSizeChangePeriod(kDefaultMinPeriod);
+ capturer_->SetResolutionConstraints(min_frame_size_, max_frame_size_,
+ kDefaultUseFixedAspectRatio);
+ capturer_->ChangeTarget(frame_sink_id_);
+
+ viz::mojom::FrameSinkVideoConsumerPtr consumer;
+ binding_.Bind(mojo::MakeRequest(&consumer));
+ capturer_->Start(std::move(consumer));
+}
+
+bool DevToolsVideoConsumer::IsValidMinAndMaxFrameSize(
+ gfx::Size min_frame_size,
+ gfx::Size max_frame_size) {
+ // Returns true if
+ // 0 < |min_frame_size| <= |max_frame_size| <= media::limits::kMaxDimension.
+ return 0 < min_frame_size.width() && 0 < min_frame_size.height() &&
+ min_frame_size.width() <= max_frame_size.width() &&
+ min_frame_size.height() <= max_frame_size.height() &&
+ max_frame_size.width() <= media::limits::kMaxDimension &&
+ max_frame_size.height() <= media::limits::kMaxDimension;
+}
+
+void DevToolsVideoConsumer::OnFrameCaptured(
+ mojo::ScopedSharedBufferHandle buffer,
+ uint32_t buffer_size,
+ ::media::mojom::VideoFrameInfoPtr info,
+ const gfx::Rect& update_rect,
+ const gfx::Rect& content_rect,
+ viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) {
+ if (!buffer.is_valid())
+ return;
+
+ mojo::ScopedSharedBufferMapping mapping = buffer->Map(buffer_size);
+ if (!mapping) {
+ DLOG(ERROR) << "Shared memory mapping failed.";
+ return;
+ }
+
+ scoped_refptr<media::VideoFrame> frame;
+ // Setting |frame|'s visible rect equal to |content_rect| so that only the
+ // portion of the frame that contain content are used.
+ frame = media::VideoFrame::WrapExternalData(
+ info->pixel_format, info->coded_size, info->visible_rect,
+ info->visible_rect.size(), static_cast<uint8_t*>(mapping.get()),
+ buffer_size, info->timestamp);
+ if (!frame)
+ return;
+ frame->AddDestructionObserver(base::BindOnce(
+ [](mojo::ScopedSharedBufferMapping mapping) {}, std::move(mapping)));
+ frame->metadata()->MergeInternalValuesFrom(info->metadata);
+
+ callback_.Run(std::move(frame));
+}
+
+void DevToolsVideoConsumer::OnTargetLost(
+ const viz::FrameSinkId& frame_sink_id) {}
+
+void DevToolsVideoConsumer::OnStopped() {}
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_video_consumer.h b/chromium/content/browser/devtools/devtools_video_consumer.h
new file mode 100644
index 00000000000..fc9bbdba359
--- /dev/null
+++ b/chromium/content/browser/devtools/devtools_video_consumer.h
@@ -0,0 +1,104 @@
+// Copyright 2018 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.
+
+#ifndef CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_VIDEO_CONSUMER_H_
+#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_VIDEO_CONSUMER_H_
+
+#include "base/time/time.h"
+#include "content/common/content_export.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/viz/privileged/interfaces/compositing/frame_sink_video_capture.mojom.h"
+#include "ui/gfx/geometry/size.h"
+
+class SkBitmap;
+
+namespace content {
+
+// This class is the video consumer to FrameSinkVideoCapturerImpl. This class,
+// in turn sends video frames to its host via the OnFrameCapturedCallback. Used
+// when the VizDisplayCompositor feature is enabled.
+// TODO(https://crbug.com/813929): Use this class everywhere even if viz is not
+// enabled.
+class CONTENT_EXPORT DevToolsVideoConsumer
+ : public viz::mojom::FrameSinkVideoConsumer {
+ public:
+ using OnFrameCapturedCallback =
+ base::RepeatingCallback<void(scoped_refptr<media::VideoFrame> frame)>;
+
+ explicit DevToolsVideoConsumer(OnFrameCapturedCallback callback);
+ ~DevToolsVideoConsumer() override;
+
+ // Copies |frame| onto a SkBitmap and returns it.
+ static SkBitmap GetSkBitmapFromFrame(scoped_refptr<media::VideoFrame> frame);
+
+ // If not currently capturing, this creates the capturer and starts capturing.
+ void StartCapture();
+
+ // Closes |binding_|. Stops capturing and resets |capturer_|.
+ void StopCapture();
+
+ // These functions cache the values passed to them and if we're currently
+ // capturing, they call the corresponding |capturer_| functions.
+ // TODO(samans): Add a SetFormat function here so that ARGB pixel format can
+ // be used.
+ void SetFrameSinkId(const viz::FrameSinkId& frame_sink_id);
+ void SetMinCapturePeriod(base::TimeDelta min_capture_period);
+ void SetMinAndMaxFrameSize(gfx::Size min_frame_size,
+ gfx::Size max_frame_size);
+
+ private:
+ friend class DevToolsVideoConsumerTest;
+ // Sets up a mojo message pipe and requests the HostFrameSinkManager create a
+ // new capturer instance bound to it. Returns the client-side interface.
+ viz::mojom::FrameSinkVideoCapturerPtrInfo CreateCapturer();
+
+ // Binds |capturer_info| to the |capturer_|, sets capture parameters, and
+ // starts capture. Normally, CreateCapturer produces the |capturer_info|, but
+ // unittests can provide a mock.
+ void InnerStartCapture(
+ viz::mojom::FrameSinkVideoCapturerPtrInfo capturer_info);
+
+ // Checks that |min_frame_size| and |max_frame_size| are in the expected
+ // range. Limits are specified in media::limits.
+ bool IsValidMinAndMaxFrameSize(gfx::Size min_frame_size,
+ gfx::Size max_frame_size);
+
+ // viz::mojom::FrameSinkVideoConsumer:
+ void OnFrameCaptured(
+ mojo::ScopedSharedBufferHandle buffer,
+ uint32_t buffer_size,
+ ::media::mojom::VideoFrameInfoPtr info,
+ const gfx::Rect& update_rect,
+ const gfx::Rect& content_rect,
+ viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) override;
+ void OnTargetLost(const viz::FrameSinkId& frame_sink_id) override;
+ void OnStopped() override;
+
+ // Default min frame size is 1x1, as otherwise, nothing would be captured.
+ static constexpr gfx::Size kDefaultMinFrameSize = gfx::Size(1, 1);
+
+ // Using an arbitrary default max frame size of 500x500.
+ static constexpr gfx::Size kDefaultMaxFrameSize = gfx::Size(500, 500);
+
+ // Callback that is run when a frame is received.
+ const OnFrameCapturedCallback callback_;
+
+ // Capture parameters.
+ base::TimeDelta min_capture_period_;
+ gfx::Size min_frame_size_;
+ gfx::Size max_frame_size_;
+ viz::FrameSinkId frame_sink_id_;
+
+ // Mojo pointer to the viz::FrameSinkVideoCapturer instance. If |capturer_|
+ // is alive, then we are currently capturing.
+ viz::mojom::FrameSinkVideoCapturerPtr capturer_;
+
+ mojo::Binding<viz::mojom::FrameSinkVideoConsumer> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(DevToolsVideoConsumer);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_VIDEO_CONSUMER_H_
diff --git a/chromium/content/browser/devtools/devtools_video_consumer_browsertest.cc b/chromium/content/browser/devtools/devtools_video_consumer_browsertest.cc
new file mode 100644
index 00000000000..789594ed607
--- /dev/null
+++ b/chromium/content/browser/devtools/devtools_video_consumer_browsertest.cc
@@ -0,0 +1,128 @@
+// Copyright 2018 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 <memory>
+
+#include "content/browser/devtools/devtools_video_consumer.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "net/test/embedded_test_server/controllable_http_response.h"
+
+namespace {
+
+// Helper to verify that |frame| dimensions are in the expected ranges.
+bool VerifyFrameSize(scoped_refptr<media::VideoFrame> frame,
+ gfx::Size min_frame_size,
+ gfx::Size max_frame_size) {
+ // Returns true if |min_frame_size| <= |frame| <= |max_frame_size|.
+ return min_frame_size.width() <= frame->visible_rect().width() &&
+ min_frame_size.height() <= frame->visible_rect().height() &&
+ frame->visible_rect().width() <= max_frame_size.width() &&
+ frame->visible_rect().height() <= max_frame_size.height();
+}
+
+// The default video pixel format.
+// TODO(sundarrajs): Add |FrameSinkVideoCapturerImpl::kDefaultPixelFormat| to
+// frame_sink_video_capture.mojom and use that instead of
+// |kVideoCapturerDefaultPixelFormat|.
+constexpr media::VideoPixelFormat kVideoCapturerDefaultPixelFormat =
+ media::PIXEL_FORMAT_I420;
+
+} // namespace
+
+namespace content {
+
+class DevToolsVideoConsumerTest : public ContentBrowserTest {
+ public:
+ DevToolsVideoConsumerTest() {}
+
+ void SetUpOnMainThread() override {
+ consumer_ = std::make_unique<DevToolsVideoConsumer>(base::BindRepeating(
+ &DevToolsVideoConsumerTest::OnFrameFromVideoConsumer,
+ base::Unretained(this)));
+ consumer_->SetFrameSinkId(
+ static_cast<content::WebContentsImpl*>(shell()->web_contents())
+ ->GetRenderViewHost()
+ ->GetWidget()
+ ->GetFrameSinkId());
+ }
+
+ scoped_refptr<media::VideoFrame> GetFrame(int i) { return frames_[i]; }
+
+ size_t NumberOfFramesReceived() { return frames_.size(); }
+
+ void OnFrameFromVideoConsumer(scoped_refptr<media::VideoFrame> frame) {
+ run_loop_->Quit();
+ frames_.push_back(std::move(frame));
+ }
+
+ void WaitUntilFrameReceived() {
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
+ }
+
+ static gfx::Size GetVideoConsumerDefaultMinFrameSize() {
+ return DevToolsVideoConsumer::kDefaultMinFrameSize;
+ }
+
+ static gfx::Size GetVideoConsumerDefaultMaxFrameSize() {
+ return DevToolsVideoConsumer::kDefaultMaxFrameSize;
+ }
+
+ protected:
+ std::unique_ptr<DevToolsVideoConsumer> consumer_;
+
+ private:
+ std::vector<scoped_refptr<media::VideoFrame>> frames_;
+ std::unique_ptr<base::RunLoop> run_loop_;
+};
+
+// Tests that setting new frame dimensions via SetMinAndMaxFrameSizes
+// produces frames of the new dimensions.
+IN_PROC_BROWSER_TEST_F(DevToolsVideoConsumerTest,
+ SetMinAndMaxFramesChangesDimensions) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ // Complete navigation to a page and then start capture. Since navigation is
+ // complete before capturing, we only expect the refresh frame from the
+ // StartCapture call. Wait for this refresh frame and verify its info.
+ NavigateToURLBlockUntilNavigationsComplete(
+ shell(), embedded_test_server()->GetURL("/devtools/navigation.html"), 1);
+ consumer_->StartCapture();
+ WaitUntilFrameReceived();
+ size_t cur_frame_index = 0;
+ size_t num_frames_received = 1;
+ EXPECT_EQ(num_frames_received, NumberOfFramesReceived());
+ scoped_refptr<media::VideoFrame> frame = GetFrame(cur_frame_index);
+ EXPECT_EQ(frame->format(), kVideoCapturerDefaultPixelFormat);
+ EXPECT_TRUE(VerifyFrameSize(frame, GetVideoConsumerDefaultMinFrameSize(),
+ GetVideoConsumerDefaultMaxFrameSize()));
+
+ // Setting |kNewMinFrameSize| > |kDefaultMaxFrameSize| to disambiguate
+ // frames with older vs. newer dimensions.
+ const gfx::Size kNewMinFrameSize =
+ gfx::Size(GetVideoConsumerDefaultMaxFrameSize().width() + 1,
+ GetVideoConsumerDefaultMaxFrameSize().height() + 1);
+ // |kNewMaxFrameSize| only needs to be >= |kNewMinFrameSize|.
+ const gfx::Size kNewMaxFrameSize = gfx::Size(kNewMinFrameSize.width() + 500,
+ kNewMinFrameSize.height() + 500);
+ // Set the min and max frame sizes. This will call
+ // FrameSinkVideoCapturer::SetResolutionConstraints which triggers sending a
+ // refresh frame. Wait for this refresh frame and verify it's info.
+ consumer_->SetMinAndMaxFrameSize(kNewMinFrameSize, kNewMaxFrameSize);
+ WaitUntilFrameReceived();
+ EXPECT_EQ(++num_frames_received, NumberOfFramesReceived());
+ frame = GetFrame(++cur_frame_index);
+ EXPECT_EQ(frame->format(), kVideoCapturerDefaultPixelFormat);
+ EXPECT_TRUE(VerifyFrameSize(frame, kNewMinFrameSize, kNewMaxFrameSize));
+
+ // Stop capturing.
+ consumer_->StopCapture();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_video_consumer_unittest.cc b/chromium/content/browser/devtools/devtools_video_consumer_unittest.cc
new file mode 100644
index 00000000000..adb95d4bbab
--- /dev/null
+++ b/chromium/content/browser/devtools/devtools_video_consumer_unittest.cc
@@ -0,0 +1,394 @@
+// Copyright 2018 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 <memory>
+
+#include "base/message_loop/message_loop.h"
+#include "content/browser/devtools/devtools_video_consumer.h"
+#include "content/public/test/test_utils.h"
+#include "media/base/limits.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::_;
+
+namespace content {
+namespace {
+
+// Capture parameters.
+constexpr gfx::Size kResolution = gfx::Size(320, 180); // Arbitrarily chosen.
+constexpr media::VideoPixelFormat kFormat = media::PIXEL_FORMAT_I420;
+constexpr media::VideoPixelStorage kStorage = media::VideoPixelStorage::CPU;
+
+// A non-zero FrameSinkId to prevent validation errors when
+// DevToolsVideoConsumer::ChangeTarget(viz::FrameSinkId) is called
+// (which eventually fails in FrameSinkVideoCapturerStubDispatch::Accept).
+constexpr viz::FrameSinkId kInitialFrameSinkId = viz::FrameSinkId(1, 1);
+
+} // namespace
+
+// Mock for the FrameSinkVideoCapturer running in the VIZ process.
+class MockFrameSinkVideoCapturer : public viz::mojom::FrameSinkVideoCapturer {
+ public:
+ MockFrameSinkVideoCapturer() : binding_(this) {}
+
+ bool is_bound() const { return binding_.is_bound(); }
+
+ void Bind(viz::mojom::FrameSinkVideoCapturerRequest request) {
+ DCHECK(!binding_.is_bound());
+ binding_.Bind(std::move(request));
+ }
+
+ // This is never called.
+ MOCK_METHOD2(SetFormat,
+ void(media::VideoPixelFormat format,
+ media::ColorSpace color_space));
+ void SetMinCapturePeriod(base::TimeDelta min_capture_period) final {
+ min_capture_period_ = min_capture_period;
+ MockSetMinCapturePeriod(min_capture_period_);
+ }
+ MOCK_METHOD1(MockSetMinCapturePeriod,
+ void(base::TimeDelta min_capture_period));
+ void SetMinSizeChangePeriod(base::TimeDelta min_period) final {
+ min_period_ = min_period;
+ MockSetMinSizeChangePeriod(min_period_);
+ }
+ MOCK_METHOD1(MockSetMinSizeChangePeriod, void(base::TimeDelta min_period));
+ void SetResolutionConstraints(const gfx::Size& min_frame_size,
+ const gfx::Size& max_frame_size,
+ bool use_fixed_aspect_ratio) final {
+ min_frame_size_ = min_frame_size;
+ max_frame_size_ = max_frame_size;
+ MockSetResolutionConstraints(min_frame_size_, max_frame_size_, true);
+ }
+ MOCK_METHOD3(MockSetResolutionConstraints,
+ void(const gfx::Size& min_frame_size,
+ const gfx::Size& max_frame_size,
+ bool use_fixed_aspect_ratio));
+ // This is never called.
+ MOCK_METHOD1(SetAutoThrottlingEnabled, void(bool));
+ void ChangeTarget(const viz::FrameSinkId& frame_sink_id) final {
+ frame_sink_id_ = frame_sink_id;
+ MockChangeTarget(frame_sink_id_);
+ }
+ MOCK_METHOD1(MockChangeTarget, void(const viz::FrameSinkId& frame_sink_id));
+ void Start(viz::mojom::FrameSinkVideoConsumerPtr consumer) final {
+ DCHECK(!consumer_);
+ consumer_ = std::move(consumer);
+ MockStart(consumer_.get());
+ }
+ MOCK_METHOD1(MockStart, void(viz::mojom::FrameSinkVideoConsumer* consumer));
+ void Stop() final {
+ binding_.Close();
+ consumer_.reset();
+ MockStop();
+ }
+ MOCK_METHOD0(MockStop, void());
+ MOCK_METHOD0(RequestRefreshFrame, void());
+
+ // Const accessors to get the cached variables.
+ base::TimeDelta min_capture_period() const { return min_capture_period_; }
+ base::TimeDelta min_period() const { return min_period_; }
+ gfx::Size min_frame_size() const { return min_frame_size_; }
+ gfx::Size max_frame_size() const { return max_frame_size_; }
+ viz::FrameSinkId frame_sink_id() const { return frame_sink_id_; }
+
+ private:
+ // These variables are cached when they are received from
+ // DevToolsVideoConsumer.
+ base::TimeDelta min_capture_period_;
+ base::TimeDelta min_period_;
+ gfx::Size min_frame_size_;
+ gfx::Size max_frame_size_;
+ viz::FrameSinkId frame_sink_id_;
+ viz::mojom::FrameSinkVideoConsumerPtr consumer_;
+
+ mojo::Binding<viz::mojom::FrameSinkVideoCapturer> binding_;
+};
+
+// Represents the FrameSinkVideoConsumerFrameCallbacks instance in the VIZ
+// process.
+class MockFrameSinkVideoConsumerFrameCallbacks
+ : public viz::mojom::FrameSinkVideoConsumerFrameCallbacks {
+ public:
+ MockFrameSinkVideoConsumerFrameCallbacks() : binding_(this) {}
+
+ void Bind(viz::mojom::FrameSinkVideoConsumerFrameCallbacksRequest request) {
+ binding_.Bind(std::move(request));
+ }
+
+ MOCK_METHOD0(Done, void());
+ MOCK_METHOD1(ProvideFeedback, void(double utilization));
+
+ private:
+ mojo::Binding<viz::mojom::FrameSinkVideoConsumerFrameCallbacks> binding_;
+};
+
+// Mock for the classes like TracingHandler that receive frames from
+// DevToolsVideoConsumer via the OnFrameCapturedCallback.
+class MockDevToolsVideoFrameReceiver {
+ public:
+ MOCK_METHOD1(OnFrameFromVideoConsumerMock,
+ void(scoped_refptr<media::VideoFrame> frame));
+
+ MockDevToolsVideoFrameReceiver() : weak_factory_(this) {}
+
+ scoped_refptr<media::VideoFrame> TakeFrameAt(int i) {
+ return std::move(frames_[i]);
+ }
+
+ void OnFrameFromVideoConsumer(scoped_refptr<media::VideoFrame> frame) {
+ OnFrameFromVideoConsumerMock(frame);
+ frames_.push_back(std::move(frame));
+ }
+
+ std::unique_ptr<DevToolsVideoConsumer> CreateDevToolsVideoConsumer() {
+ return std::make_unique<DevToolsVideoConsumer>(base::BindRepeating(
+ &MockDevToolsVideoFrameReceiver::OnFrameFromVideoConsumer,
+ weak_factory_.GetWeakPtr()));
+ }
+
+ private:
+ std::vector<scoped_refptr<media::VideoFrame>> frames_;
+ base::WeakPtrFactory<MockDevToolsVideoFrameReceiver> weak_factory_;
+};
+
+class DevToolsVideoConsumerTest : public testing::Test {
+ public:
+ DevToolsVideoConsumerTest() : weak_factory_(this) {}
+
+ void SetUp() override {
+ consumer_ = receiver_.CreateDevToolsVideoConsumer();
+
+ consumer_->SetFrameSinkId(kInitialFrameSinkId);
+ }
+
+ void SimulateFrameCapture(mojo::ScopedSharedBufferHandle buffer,
+ uint32_t buffer_size) {
+ viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks_ptr;
+ callbacks.Bind(mojo::MakeRequest(&callbacks_ptr));
+
+ media::mojom::VideoFrameInfoPtr info = media::mojom::VideoFrameInfo::New(
+ base::TimeDelta(), base::Value(base::Value::Type::DICTIONARY), kFormat,
+ kStorage, kResolution, gfx::Rect(kResolution));
+
+ consumer_->OnFrameCaptured(std::move(buffer), buffer_size, std::move(info),
+ gfx::Rect(kResolution), gfx::Rect(kResolution),
+ std::move(callbacks_ptr));
+ }
+
+ void StartCaptureWithMockCapturer() {
+ consumer_->InnerStartCapture(BindMockCapturer());
+ }
+
+ bool IsValidMinAndMaxFrameSize(gfx::Size min_frame_size,
+ gfx::Size max_frame_size) {
+ return consumer_->IsValidMinAndMaxFrameSize(min_frame_size, max_frame_size);
+ }
+
+ static gfx::Size GetVideoConsumerDefaultMinFrameSize() {
+ return DevToolsVideoConsumer::kDefaultMinFrameSize;
+ }
+
+ static gfx::Size GetVideoConsumerDefaultMaxFrameSize() {
+ return DevToolsVideoConsumer::kDefaultMaxFrameSize;
+ }
+
+ // Getters for |consumer_|'s private variables.
+ base::TimeDelta GetMinCapturePeriod() const {
+ return consumer_->min_capture_period_;
+ }
+ gfx::Size GetMinFrameSize() const { return consumer_->min_frame_size_; }
+ gfx::Size GetMaxFrameSize() const { return consumer_->max_frame_size_; }
+ viz::FrameSinkId GetFrameSinkId() const { return consumer_->frame_sink_id_; }
+
+ protected:
+ MockFrameSinkVideoCapturer capturer_;
+ MockFrameSinkVideoConsumerFrameCallbacks callbacks;
+ MockDevToolsVideoFrameReceiver receiver_;
+ std::unique_ptr<DevToolsVideoConsumer> consumer_;
+
+ private:
+ viz::mojom::FrameSinkVideoCapturerPtrInfo BindMockCapturer() {
+ viz::mojom::FrameSinkVideoCapturerPtr capturer_ptr;
+ capturer_.Bind(mojo::MakeRequest(&capturer_ptr));
+ return capturer_ptr.PassInterface();
+ }
+
+ base::MessageLoop message_loop_;
+ base::WeakPtrFactory<DevToolsVideoConsumerTest> weak_factory_;
+};
+
+// Tests that the OnFrameFromVideoConsumer callbacks is called when
+// OnFrameCaptured is passed a valid buffer with valid mapping.
+TEST_F(DevToolsVideoConsumerTest, CallbacksAreCalledWhenBufferValid) {
+ // Create a valid buffer.
+ const size_t buffer_size =
+ media::VideoFrame::AllocationSize(kFormat, kResolution);
+ mojo::ScopedSharedBufferHandle buffer =
+ mojo::SharedBufferHandle::Create(buffer_size);
+
+ // On valid buffer the |receiver_| gets a frame via OnFrameFromVideoConsumer.
+ EXPECT_CALL(receiver_, OnFrameFromVideoConsumerMock(_)).Times(1);
+
+ SimulateFrameCapture(std::move(buffer), buffer_size);
+ base::RunLoop().RunUntilIdle();
+}
+
+// Tests that only the OnFrameFromVideoConsumer callback is not called when
+// OnFrameCaptured is passed an invalid buffer.
+TEST_F(DevToolsVideoConsumerTest, OnFrameCapturedExitEarlyOnInvalidBuffer) {
+ // Create an invalid buffer.
+ const size_t buffer_size = 0;
+ mojo::ScopedSharedBufferHandle buffer =
+ mojo::SharedBufferHandle::Create(buffer_size);
+
+ // On invalid buffer, the |receiver_| doesn't get a frame.
+ EXPECT_CALL(receiver_, OnFrameFromVideoConsumerMock(_)).Times(0);
+
+ SimulateFrameCapture(std::move(buffer), buffer_size);
+ base::RunLoop().RunUntilIdle();
+}
+
+// Tests that the OnFrameFromVideoConsumer callback is not called when
+// OnFrameCaptured is passed a buffer with invalid mapping.
+TEST_F(DevToolsVideoConsumerTest, OnFrameCapturedExitsOnInvalidMapping) {
+ // Create a valid buffer, but change buffer_size to simulate an invalid
+ // mapping.
+ size_t buffer_size = media::VideoFrame::AllocationSize(kFormat, kResolution);
+ mojo::ScopedSharedBufferHandle buffer =
+ mojo::SharedBufferHandle::Create(buffer_size);
+ buffer_size = 0;
+
+ // On invalid mapping, the |receiver_| doesn't get a frame.
+ EXPECT_CALL(receiver_, OnFrameFromVideoConsumerMock(_)).Times(0);
+
+ SimulateFrameCapture(std::move(buffer), buffer_size);
+ base::RunLoop().RunUntilIdle();
+}
+
+// Tests that starting capture calls |capturer_| functions, and capture can be
+// restarted. This test is important as it ensures that when restarting capture,
+// a FrameSinkVideoCapturerPtrInfo is bound to |capturer_| and it verifies that
+// resources used in the previous StartCapture aren't reused.
+TEST_F(DevToolsVideoConsumerTest, StartCaptureCallsSetFunctions) {
+ // Starting capture should call these |capturer_| functions once.
+ EXPECT_CALL(capturer_, MockSetMinCapturePeriod(_));
+ EXPECT_CALL(capturer_, MockSetMinSizeChangePeriod(_));
+ EXPECT_CALL(capturer_, MockSetResolutionConstraints(_, _, _));
+ EXPECT_CALL(capturer_, MockChangeTarget(_));
+ EXPECT_CALL(capturer_, MockStart(_));
+ StartCaptureWithMockCapturer();
+ base::RunLoop().RunUntilIdle();
+
+ // Stop capturing.
+ EXPECT_CALL(capturer_, MockStop());
+ consumer_->StopCapture();
+ base::RunLoop().RunUntilIdle();
+
+ // Start capturing again, and expect that these |capturer_| functions are
+ // called once. This will re-bind the |capturer_| and ensures that destroyed
+ // resources aren't being reused.
+ EXPECT_CALL(capturer_, MockSetMinCapturePeriod(_));
+ EXPECT_CALL(capturer_, MockSetMinSizeChangePeriod(_));
+ EXPECT_CALL(capturer_, MockSetResolutionConstraints(_, _, _));
+ EXPECT_CALL(capturer_, MockChangeTarget(_));
+ EXPECT_CALL(capturer_, MockStart(_));
+ StartCaptureWithMockCapturer();
+ base::RunLoop().RunUntilIdle();
+}
+
+// Tests that calling 'Set' functions in DevToolsVideoConsumer before
+// |capturer_| is initialized results in the passed values being cached.
+// When capture is later started (and |capturer_| initialized), these cached
+// values should be used and sent to the |capturer_|.
+TEST_F(DevToolsVideoConsumerTest, CapturerIsPassedCachedValues) {
+ // These values are chosen so that they are valid, and different from
+ // the default values in DevToolsVideoConsumer.
+ constexpr base::TimeDelta kNewMinCapturePeriod = base::TimeDelta();
+ const gfx::Size kNewMinFrameSize =
+ gfx::Size(GetVideoConsumerDefaultMinFrameSize().width() + 1,
+ GetVideoConsumerDefaultMinFrameSize().height() + 1);
+ const gfx::Size kNewMaxFrameSize =
+ gfx::Size(GetVideoConsumerDefaultMaxFrameSize().width() + 1,
+ GetVideoConsumerDefaultMaxFrameSize().width() + 1);
+ constexpr viz::FrameSinkId kNewFrameSinkId = viz::FrameSinkId(2, 2);
+
+ // Right now, |capturer_| has not been created via StartCapture, so
+ // calling these functions should not call the |capturer_|, but the
+ // values that are passed in should be cached.
+ EXPECT_CALL(capturer_, MockSetMinCapturePeriod(_)).Times(0);
+ EXPECT_CALL(capturer_, MockSetMinSizeChangePeriod(_)).Times(0);
+ EXPECT_CALL(capturer_, MockSetResolutionConstraints(_, _, _)).Times(0);
+ EXPECT_CALL(capturer_, MockChangeTarget(_)).Times(0);
+ EXPECT_CALL(capturer_, MockStart(_)).Times(0);
+ consumer_->SetMinCapturePeriod(kNewMinCapturePeriod);
+ consumer_->SetMinAndMaxFrameSize(kNewMinFrameSize, kNewMaxFrameSize);
+ consumer_->SetFrameSinkId(kNewFrameSinkId);
+ base::RunLoop().RunUntilIdle();
+ // Verify that new values are cached.
+ EXPECT_EQ(GetMinCapturePeriod(), kNewMinCapturePeriod);
+ EXPECT_EQ(GetMinFrameSize(), kNewMinFrameSize);
+ EXPECT_EQ(GetMaxFrameSize(), kNewMaxFrameSize);
+ EXPECT_EQ(GetFrameSinkId(), kNewFrameSinkId);
+
+ // Starting capture now, will result in the cached values being sent to
+ // |capturer_|. So, expect that these calls are made and verify the values.
+ EXPECT_CALL(capturer_, MockSetMinCapturePeriod(_));
+ EXPECT_CALL(capturer_, MockSetMinSizeChangePeriod(_));
+ EXPECT_CALL(capturer_, MockSetResolutionConstraints(_, _, _));
+ EXPECT_CALL(capturer_, MockChangeTarget(_));
+ EXPECT_CALL(capturer_, MockStart(_));
+ StartCaptureWithMockCapturer();
+ base::RunLoop().RunUntilIdle();
+ // Verify that the previously cached values are sent to |capturer_|.
+ EXPECT_EQ(capturer_.min_capture_period(), kNewMinCapturePeriod);
+ EXPECT_EQ(capturer_.min_frame_size(), kNewMinFrameSize);
+ EXPECT_EQ(capturer_.max_frame_size(), kNewMaxFrameSize);
+ EXPECT_EQ(capturer_.frame_sink_id(), kNewFrameSinkId);
+}
+
+// Tests that DevToolsVideoConsumer::IsValidMinAndMaxFrameSize adheres to the
+// limits set by media::limits::kMaxDimension
+TEST_F(DevToolsVideoConsumerTest, IsValidMinAndMaxFrameSize) {
+ // Choosing valid frame sizes with
+ // kNormalMinSize.height() > kNormalMaxSize.width() so that width
+ // and height are not interchanged in this test.
+ constexpr gfx::Size kNormalMinSize = gfx::Size(50, 150);
+ constexpr gfx::Size kNormalMaxSize = gfx::Size(100, 200);
+
+ // Testing success cases.
+ EXPECT_TRUE(IsValidMinAndMaxFrameSize(kNormalMinSize, kNormalMaxSize));
+ // Non-zero frames that are equal should pass.
+ EXPECT_TRUE(IsValidMinAndMaxFrameSize(kNormalMinSize, kNormalMaxSize));
+ // Swapping width and height of frames should pass.
+ EXPECT_TRUE(IsValidMinAndMaxFrameSize(
+ gfx::Size(kNormalMinSize.height(), kNormalMinSize.width()),
+ gfx::Size(kNormalMaxSize.height(), kNormalMaxSize.width())));
+
+ // Testing failure cases.
+ // |min_frame_size|.width() should be > 0
+ EXPECT_FALSE(IsValidMinAndMaxFrameSize(gfx::Size(0, kNormalMinSize.height()),
+ kNormalMaxSize));
+ // |min_frame_size|.height() should be > 0
+ EXPECT_FALSE(IsValidMinAndMaxFrameSize(gfx::Size(kNormalMinSize.width(), 0),
+ kNormalMaxSize));
+ // |min_frame_size|.width() should be <= |max_frame_size|.width()
+ EXPECT_FALSE(IsValidMinAndMaxFrameSize(
+ gfx::Size(kNormalMaxSize.width() + 1, kNormalMinSize.height()),
+ kNormalMaxSize));
+ // |max_frame_size|.height() should be <= |max_frame_size|.height()
+ EXPECT_FALSE(IsValidMinAndMaxFrameSize(
+ gfx::Size(kNormalMinSize.width(), kNormalMaxSize.height() + 1),
+ kNormalMaxSize));
+ // |max_frame_size|.height() should be <= media::limits::kMaxDimension
+ EXPECT_FALSE(IsValidMinAndMaxFrameSize(
+ kNormalMinSize,
+ gfx::Size(kNormalMaxSize.width(), media::limits::kMaxDimension + 1)));
+ // |max_frame_size|.width() should be <= media::limits::kMaxDimension
+ EXPECT_FALSE(IsValidMinAndMaxFrameSize(
+ kNormalMinSize,
+ gfx::Size(media::limits::kMaxDimension + 1, kNormalMaxSize.height())));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/browser_handler.cc b/chromium/content/browser/devtools/protocol/browser_handler.cc
index aed9964e47b..7e03482fde2 100644
--- a/chromium/content/browser/devtools/protocol/browser_handler.cc
+++ b/chromium/content/browser/devtools/protocol/browser_handler.cc
@@ -112,7 +112,7 @@ Response BrowserHandler::GetHistogram(
return Response::OK();
}
-Response BrowserHandler::GetCommandLine(
+Response BrowserHandler::GetBrowserCommandLine(
std::unique_ptr<protocol::Array<String>>* arguments) {
*arguments = protocol::Array<String>::create();
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
diff --git a/chromium/content/browser/devtools/protocol/browser_handler.h b/chromium/content/browser/devtools/protocol/browser_handler.h
index 8af1d28e08a..b4f3e05eccc 100644
--- a/chromium/content/browser/devtools/protocol/browser_handler.h
+++ b/chromium/content/browser/devtools/protocol/browser_handler.h
@@ -34,7 +34,7 @@ class BrowserHandler : public DevToolsDomainHandler, public Browser::Backend {
const std::string& in_name,
std::unique_ptr<Browser::Histogram>* out_histogram) override;
- Response GetCommandLine(
+ Response GetBrowserCommandLine(
std::unique_ptr<protocol::Array<String>>* arguments) override;
private:
diff --git a/chromium/content/browser/devtools/protocol/devtools_download_manager_delegate.cc b/chromium/content/browser/devtools/protocol/devtools_download_manager_delegate.cc
index 687a744304b..f71a5bf4ab3 100644
--- a/chromium/content/browser/devtools/protocol/devtools_download_manager_delegate.cc
+++ b/chromium/content/browser/devtools/protocol/devtools_download_manager_delegate.cc
@@ -121,7 +121,7 @@ bool DevToolsDownloadManagerDelegate::DetermineDownloadTarget(
base::BindOnce(&DevToolsDownloadManagerDelegate::GenerateFilename,
item->GetURL(), item->GetContentDisposition(),
item->GetSuggestedFilename(), item->GetMimeType(),
- download_path, filename_determined_callback));
+ download_path, std::move(filename_determined_callback)));
return true;
}
diff --git a/chromium/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/chromium/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index d8eba18ceb5..5a364cef4ed 100644
--- a/chromium/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/chromium/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -21,15 +21,16 @@
#include "base/sys_info.h"
#include "base/values.h"
#include "build/build_config.h"
+#include "components/download/public/common/download_file_factory.h"
+#include "components/download/public/common/download_file_impl.h"
#include "components/download/public/common/download_task_runner.h"
#include "content/browser/devtools/protocol/devtools_download_manager_delegate.h"
-#include "content/browser/download/download_file_factory.h"
-#include "content/browser/download/download_file_impl.h"
#include "content/browser/download/download_manager_impl.h"
#include "content/browser/frame_host/interstitial_page_impl.h"
#include "content/browser/frame_host/navigator.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/interstitial_page_delegate.h"
@@ -49,6 +50,7 @@
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/download_test_observer.h"
+#include "content/public/test/slow_download_http_response.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/shell/browser/shell.h"
#include "content/shell/browser/shell_browser_context.h"
@@ -58,9 +60,7 @@
#include "net/dns/mock_host_resolver.h"
#include "net/test/cert_test_util.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "net/test/test_data_directory.h"
-#include "net/test/url_request/url_request_mock_http_job.h"
-#include "net/test/url_request/url_request_slow_download_job.h"
+#include "services/network/public/cpp/features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -2243,6 +2243,24 @@ IN_PROC_BROWSER_TEST_F(DevToolsProtocolDeviceEmulationTest, MAYBE_DeviceSize) {
EXPECT_EQ(original_size, GetViewSize());
}
+// Setting frame size (through RWHV) is not supported on Android.
+#if defined(OS_ANDROID)
+#define MAYBE_RenderKillDoesNotCrashBrowser \
+ DISABLED_RenderKillDoesNotCrashBrowser
+#else
+#define MAYBE_RenderKillDoesNotCrashBrowser RenderKillDoesNotCrashBrowser
+#endif
+IN_PROC_BROWSER_TEST_F(DevToolsProtocolDeviceEmulationTest,
+ MAYBE_RenderKillDoesNotCrashBrowser) {
+ NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
+ Attach();
+ EmulateDeviceSize(gfx::Size(200, 200));
+ NavigateToURLBlockUntilNavigationsComplete(
+ shell(), GURL(content::kChromeUICrashURL), 1);
+ SendCommand("Emulation.clearDeviceMetricsOverride", nullptr);
+ // Should not crash at this point.
+}
+
class DevToolsProtocolTouchTest : public DevToolsProtocolTest {
public:
~DevToolsProtocolTouchTest() override {}
@@ -2385,32 +2403,34 @@ static void RemoveShellDelegate(Shell* shell) {
DownloadManagerForShell(shell)->SetDelegate(nullptr);
}
-class CountingDownloadFile : public DownloadFileImpl {
+class CountingDownloadFile : public download::DownloadFileImpl {
public:
- CountingDownloadFile(std::unique_ptr<download::DownloadSaveInfo> save_info,
- const base::FilePath& default_downloads_directory,
- std::unique_ptr<DownloadManager::InputStream> stream,
- uint32_t download_id,
- base::WeakPtr<DownloadDestinationObserver> observer)
- : DownloadFileImpl(std::move(save_info),
- default_downloads_directory,
- std::move(stream),
- download_id,
- observer) {}
+ CountingDownloadFile(
+ std::unique_ptr<download::DownloadSaveInfo> save_info,
+ const base::FilePath& default_downloads_directory,
+ std::unique_ptr<download::InputStream> stream,
+ uint32_t download_id,
+ base::WeakPtr<download::DownloadDestinationObserver> observer)
+ : download::DownloadFileImpl(std::move(save_info),
+ default_downloads_directory,
+ std::move(stream),
+ download_id,
+ observer) {}
~CountingDownloadFile() override {
DCHECK(download::GetDownloadTaskRunner()->RunsTasksInCurrentSequence());
active_files_--;
}
- void Initialize(const InitializeCallback& callback,
+ void Initialize(InitializeCallback callback,
const CancelRequestCallback& cancel_request_callback,
const download::DownloadItem::ReceivedSlices& received_slices,
bool is_parallelizable) override {
DCHECK(download::GetDownloadTaskRunner()->RunsTasksInCurrentSequence());
active_files_++;
- DownloadFileImpl::Initialize(callback, cancel_request_callback,
- received_slices, is_parallelizable);
+ download::DownloadFileImpl::Initialize(std::move(callback),
+ cancel_request_callback,
+ received_slices, is_parallelizable);
}
static void GetNumberActiveFiles(int* result) {
@@ -2437,18 +2457,18 @@ class CountingDownloadFile : public DownloadFileImpl {
int CountingDownloadFile::active_files_ = 0;
-class CountingDownloadFileFactory : public DownloadFileFactory {
+class CountingDownloadFileFactory : public download::DownloadFileFactory {
public:
CountingDownloadFileFactory() {}
~CountingDownloadFileFactory() override {}
// DownloadFileFactory interface.
- DownloadFile* CreateFile(
+ download::DownloadFile* CreateFile(
std::unique_ptr<download::DownloadSaveInfo> save_info,
const base::FilePath& default_downloads_directory,
- std::unique_ptr<DownloadManager::InputStream> stream,
+ std::unique_ptr<download::InputStream> stream,
uint32_t download_id,
- base::WeakPtr<DownloadDestinationObserver> observer) override {
+ base::WeakPtr<download::DownloadDestinationObserver> observer) override {
return new CountingDownloadFile(std::move(save_info),
default_downloads_directory,
std::move(stream), download_id, observer);
@@ -2488,7 +2508,7 @@ class TestShellDownloadManagerDelegate : public ShellDownloadManagerDelegate {
class DownloadCreateObserver : DownloadManager::Observer {
public:
explicit DownloadCreateObserver(DownloadManager* manager)
- : manager_(manager), item_(nullptr) {
+ : manager_(manager), item_(nullptr), received_item_response_(false) {
manager_->AddObserver(this);
}
@@ -2506,16 +2526,26 @@ class DownloadCreateObserver : DownloadManager::Observer {
void OnDownloadCreated(DownloadManager* manager,
download::DownloadItem* download) override {
+ received_item_response_ = true;
+
if (!item_)
item_ = download;
- if (!completion_closure_.is_null())
- base::ResetAndReturn(&completion_closure_).Run();
+ if (completion_closure_)
+ std::move(completion_closure_).Run();
+ }
+
+ void OnDownloadDropped(DownloadManager* manager) override {
+ received_item_response_ = true;
+
+ item_ = nullptr;
+ if (completion_closure_)
+ std::move(completion_closure_).Run();
}
download::DownloadItem* WaitForFinished() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (!item_) {
+ if (!received_item_response_) {
base::RunLoop run_loop;
completion_closure_ = run_loop.QuitClosure();
run_loop.Run();
@@ -2526,6 +2556,7 @@ class DownloadCreateObserver : DownloadManager::Observer {
private:
DownloadManager* manager_;
download::DownloadItem* item_;
+ bool received_item_response_;
base::Closure completion_closure_;
};
@@ -2549,14 +2580,8 @@ class DevToolsDownloadContentTest : public DevToolsProtocolTest {
manager->SetDelegate(test_delegate_.get());
test_delegate_->SetDownloadManager(manager);
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(&net::URLRequestSlowDownloadJob::AddUrlHandler));
- base::FilePath mock_base(GetTestFilePath("download", ""));
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(&net::URLRequestMockHTTPJob::AddUrlHandlers, mock_base));
+ embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
+ &content::SlowDownloadHttpResponse::HandleSlowDownloadRequest));
ASSERT_TRUE(embedded_test_server()->Start());
}
@@ -2590,7 +2615,7 @@ class DevToolsDownloadContentTest : public DevToolsProtocolTest {
// Note: Cannot be used with other alternative DownloadFileFactorys
void SetupEnsureNoPendingDownloads() {
DownloadManagerForShell(shell())->SetDownloadFileFactoryForTesting(
- std::unique_ptr<DownloadFileFactory>(
+ std::unique_ptr<download::DownloadFileFactory>(
new CountingDownloadFileFactory()));
}
@@ -2602,13 +2627,7 @@ class DevToolsDownloadContentTest : public DevToolsProtocolTest {
}
bool EnsureNoPendingDownloads() {
- bool result = true;
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(&EnsureNoPendingDownloadJobsOnIO, &result));
- base::RunLoop().Run();
- return result &&
- (CountingDownloadFile::GetNumberActiveFilesFromFileThread() == 0);
+ return CountingDownloadFile::GetNumberActiveFilesFromFileThread() == 0;
}
// Checks that |path| is has |file_size| bytes, and matches the |value|
@@ -2652,14 +2671,6 @@ class DevToolsDownloadContentTest : public DevToolsProtocolTest {
}
private:
- static void EnsureNoPendingDownloadJobsOnIO(bool* result) {
- if (net::URLRequestSlowDownloadJob::NumberOutstandingRequests())
- *result = false;
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::MessageLoop::current()->QuitWhenIdleClosure());
- }
-
// Location of the downloads directory for these tests
base::ScopedTempDir downloads_directory_;
std::unique_ptr<TestShellDownloadManagerDelegate> test_delegate_;
@@ -2678,8 +2689,7 @@ IN_PROC_BROWSER_TEST_F(DevToolsDownloadContentTest, SingleDownload) {
// Create a download, wait until it's started, and confirm
// we're in the expected state.
download::DownloadItem* download = StartDownloadAndReturnItem(
- shell(),
- GURL(net::URLRequestMockHTTPJob::GetMockUrl("download-test.lib")));
+ shell(), embedded_test_server()->GetURL("/download/download-test.lib"));
ASSERT_EQ(download::DownloadItem::IN_PROGRESS, download->GetState());
WaitForCompletion(download);
@@ -2697,7 +2707,8 @@ IN_PROC_BROWSER_TEST_F(DevToolsDownloadContentTest, DownloadCancelled) {
// Create a download, wait until it's started, and confirm
// we're in the expected state.
download::DownloadItem* download = StartDownloadAndReturnItem(
- shell(), GURL(net::URLRequestSlowDownloadJob::kUnknownSizeUrl));
+ shell(), embedded_test_server()->GetURL(
+ content::SlowDownloadHttpResponse::kUnknownSizeUrl));
ASSERT_EQ(download::DownloadItem::IN_PROGRESS, download->GetState());
// Cancel the download and wait for download system quiesce.
@@ -2719,9 +2730,10 @@ IN_PROC_BROWSER_TEST_F(DevToolsDownloadContentTest, DeniedDownload) {
SetDownloadBehavior("deny");
// Create a download, wait and confirm it was cancelled.
download::DownloadItem* download = StartDownloadAndReturnItem(
- shell(),
- GURL(net::URLRequestMockHTTPJob::GetMockUrl("download-test.lib")));
- EnsureNoPendingDownloads();
+ shell(), embedded_test_server()->GetURL("/download/download-test.lib"));
+ DownloadTestFlushObserver flush_observer(DownloadManagerForShell(shell()));
+ flush_observer.WaitForFlush();
+ EXPECT_TRUE(EnsureNoPendingDownloads());
ASSERT_EQ(download::DownloadItem::CANCELLED, download->GetState());
}
@@ -2736,7 +2748,8 @@ IN_PROC_BROWSER_TEST_F(DevToolsDownloadContentTest, DefaultDownload) {
// Create a download, wait until it's started, and confirm
// we're in the expected state.
download::DownloadItem* download = StartDownloadAndReturnItem(
- shell(), GURL(net::URLRequestSlowDownloadJob::kUnknownSizeUrl));
+ shell(), embedded_test_server()->GetURL(
+ content::SlowDownloadHttpResponse::kUnknownSizeUrl));
ASSERT_EQ(download::DownloadItem::IN_PROGRESS, download->GetState());
// Cancel the download and wait for download system quiesce.
@@ -2760,10 +2773,17 @@ IN_PROC_BROWSER_TEST_F(DevToolsDownloadContentTest, DefaultDownloadHeadless) {
SetDownloadBehavior("default");
// Create a download, wait and confirm it was cancelled.
download::DownloadItem* download = StartDownloadAndReturnItem(
- shell(),
- GURL(net::URLRequestMockHTTPJob::GetMockUrl("download-test.lib")));
- EnsureNoPendingDownloads();
- ASSERT_EQ(download::DownloadItem::CANCELLED, download->GetState());
+ shell(), embedded_test_server()->GetURL("/download/download-test.lib"));
+ DownloadTestFlushObserver flush_observer(DownloadManagerForShell(shell()));
+ flush_observer.WaitForFlush();
+ EXPECT_TRUE(EnsureNoPendingDownloads());
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ // The download manager will intercept the download navigation and drop it
+ // since we have set the delegate to null.
+ EXPECT_EQ(nullptr, download);
+ } else {
+ EXPECT_EQ(download::DownloadItem::CANCELLED, download->GetState());
+ }
}
// Check that download logic is reset when creating a new target.
@@ -2780,7 +2800,7 @@ IN_PROC_BROWSER_TEST_F(DevToolsDownloadContentTest, ResetDownloadState) {
// Create a download, wait and confirm it wasn't cancelled.
download::DownloadItem* download = StartDownloadAndReturnItem(
new_window,
- GURL(net::URLRequestMockHTTPJob::GetMockUrl("download-test.lib")));
+ embedded_test_server()->GetURL("/download/download-test.lib"));
WaitForCompletion(download);
ASSERT_EQ(download::DownloadItem::COMPLETE, download->GetState());
}
@@ -2797,13 +2817,14 @@ IN_PROC_BROWSER_TEST_F(DevToolsDownloadContentTest, MultiDownload) {
// Create a download, wait until it's started, and confirm
// we're in the expected state.
download::DownloadItem* download1 = StartDownloadAndReturnItem(
- shell(), GURL(net::URLRequestSlowDownloadJob::kUnknownSizeUrl));
+ shell(), embedded_test_server()->GetURL(
+ content::SlowDownloadHttpResponse::kUnknownSizeUrl));
ASSERT_EQ(download::DownloadItem::IN_PROGRESS, download1->GetState());
NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
SetDownloadBehavior("allow", "download2");
// Start the second download and wait until it's done.
- GURL url(net::URLRequestMockHTTPJob::GetMockUrl("download-test.lib"));
+ GURL url(embedded_test_server()->GetURL("/download/download-test.lib"));
download::DownloadItem* download2 = StartDownloadAndReturnItem(shell(), url);
WaitForCompletion(download2);
@@ -2813,7 +2834,8 @@ IN_PROC_BROWSER_TEST_F(DevToolsDownloadContentTest, MultiDownload) {
// Allow the first request to finish.
std::unique_ptr<DownloadTestObserver> observer2(CreateWaiter(shell(), 1));
NavigateToURL(shell(),
- GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl));
+ embedded_test_server()->GetURL(
+ content::SlowDownloadHttpResponse::kFinishDownloadUrl));
observer2->WaitForFinished(); // Wait for the third request.
EXPECT_EQ(
1u, observer2->NumDownloadsSeenInState(download::DownloadItem::COMPLETE));
@@ -2827,8 +2849,8 @@ IN_PROC_BROWSER_TEST_F(DevToolsDownloadContentTest, MultiDownload) {
// source file.
base::FilePath file1(download1->GetTargetFilePath());
ASSERT_EQ(file1.DirName().MaybeAsASCII(), "download1");
- size_t file_size1 = net::URLRequestSlowDownloadJob::kFirstDownloadSize +
- net::URLRequestSlowDownloadJob::kSecondDownloadSize;
+ size_t file_size1 = content::SlowDownloadHttpResponse::kFirstDownloadSize +
+ content::SlowDownloadHttpResponse::kSecondDownloadSize;
std::string expected_contents(file_size1, '*');
ASSERT_TRUE(VerifyFile(file1, expected_contents, file_size1));
diff --git a/chromium/content/browser/devtools/protocol/emulation_handler.cc b/chromium/content/browser/devtools/protocol/emulation_handler.cc
index 25ffa90042d..f61f93491cc 100644
--- a/chromium/content/browser/devtools/protocol/emulation_handler.cc
+++ b/chromium/content/browser/devtools/protocol/emulation_handler.cc
@@ -265,8 +265,12 @@ Response EmulationHandler::SetDeviceMetricsOverride(
device_emulation_enabled_ = true;
device_emulation_params_ = params;
UpdateDeviceEmulationState();
+
// Renderer should answer after emulation params were updated, so that the
// response is only sent to the client once updates were applied.
+ // Unless the renderer has crashed.
+ if (GetWebContents() && GetWebContents()->IsCrashed())
+ return Response::OK();
return Response::FallThrough();
}
@@ -282,6 +286,9 @@ Response EmulationHandler::ClearDeviceMetricsOverride() {
UpdateDeviceEmulationState();
// Renderer should answer after emulation was disabled, so that the response
// is only sent to the client once updates were applied.
+ // Unless the renderer has crashed.
+ if (GetWebContents() && GetWebContents()->IsCrashed())
+ return Response::OK();
return Response::FallThrough();
}
@@ -316,16 +323,16 @@ WebContentsImpl* EmulationHandler::GetWebContents() {
}
void EmulationHandler::UpdateTouchEventEmulationState() {
- RenderWidgetHostImpl* widget_host =
- host_ ? host_->GetRenderWidgetHost() : nullptr;
- if (!widget_host)
+ if (!host_ || !host_->GetRenderWidgetHost())
+ return;
+ if (host_->GetParent() && !host_->IsCrossProcessSubframe())
return;
if (touch_emulation_enabled_) {
- widget_host->GetTouchEmulator()->Enable(
+ host_->GetRenderWidgetHost()->GetTouchEmulator()->Enable(
TouchEmulator::Mode::kEmulatingTouchFromMouse,
TouchEmulationConfigurationToType(touch_emulation_configuration_));
} else {
- widget_host->GetTouchEmulator()->Disable();
+ host_->GetRenderWidgetHost()->GetTouchEmulator()->Disable();
}
if (GetWebContents()) {
GetWebContents()->SetForceDisableOverscrollContent(
@@ -334,9 +341,9 @@ void EmulationHandler::UpdateTouchEventEmulationState() {
}
void EmulationHandler::UpdateDeviceEmulationState() {
- RenderWidgetHostImpl* widget_host =
- host_ ? host_->GetRenderWidgetHost() : nullptr;
- if (!widget_host)
+ if (!host_ || !host_->GetRenderWidgetHost())
+ return;
+ if (host_->GetParent() && !host_->IsCrossProcessSubframe())
return;
// TODO(eseckler): Once we change this to mojo, we should wait for an ack to
// these messages from the renderer. The renderer should send the ack once the
@@ -346,11 +353,12 @@ void EmulationHandler::UpdateDeviceEmulationState() {
// ViewMsg and acknowledgment, as well as plump the acknowledgment back to the
// EmulationHandler somehow. Mojo callbacks should make this much simpler.
if (device_emulation_enabled_) {
- widget_host->Send(new ViewMsg_EnableDeviceEmulation(
- widget_host->GetRoutingID(), device_emulation_params_));
+ host_->GetRenderWidgetHost()->Send(new ViewMsg_EnableDeviceEmulation(
+ host_->GetRenderWidgetHost()->GetRoutingID(),
+ device_emulation_params_));
} else {
- widget_host->Send(new ViewMsg_DisableDeviceEmulation(
- widget_host->GetRoutingID()));
+ host_->GetRenderWidgetHost()->Send(new ViewMsg_DisableDeviceEmulation(
+ host_->GetRenderWidgetHost()->GetRoutingID()));
}
}
diff --git a/chromium/content/browser/devtools/protocol/emulation_handler.h b/chromium/content/browser/devtools/protocol/emulation_handler.h
index f322802b648..1503b2e70da 100644
--- a/chromium/content/browser/devtools/protocol/emulation_handler.h
+++ b/chromium/content/browser/devtools/protocol/emulation_handler.h
@@ -8,7 +8,7 @@
#include "base/macros.h"
#include "content/browser/devtools/protocol/devtools_domain_handler.h"
#include "content/browser/devtools/protocol/emulation.h"
-#include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
+#include "third_party/blink/public/web/web_device_emulation_params.h"
namespace content {
diff --git a/chromium/content/browser/devtools/protocol/input_handler.cc b/chromium/content/browser/devtools/protocol/input_handler.cc
index 689dc38a92d..3556f33c0fb 100644
--- a/chromium/content/browser/devtools/protocol/input_handler.cc
+++ b/chromium/content/browser/devtools/protocol/input_handler.cc
@@ -10,7 +10,6 @@
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
-#include "components/viz/common/quads/compositor_frame_metadata.h"
#include "content/browser/devtools/devtools_session.h"
#include "content/browser/devtools/protocol/native_input_event_builder.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
@@ -441,9 +440,8 @@ void InputHandler::Wire(UberDispatcher* dispatcher) {
Input::Dispatcher::wire(dispatcher, this);
}
-void InputHandler::OnSwapCompositorFrame(
- const viz::CompositorFrameMetadata& frame_metadata) {
- page_scale_factor_ = frame_metadata.page_scale_factor;
+void InputHandler::OnPageScaleFactorChanged(float page_scale_factor) {
+ page_scale_factor_ = page_scale_factor;
}
Response InputHandler::Disable() {
diff --git a/chromium/content/browser/devtools/protocol/input_handler.h b/chromium/content/browser/devtools/protocol/input_handler.h
index 9dce4844708..ae8fd55904c 100644
--- a/chromium/content/browser/devtools/protocol/input_handler.h
+++ b/chromium/content/browser/devtools/protocol/input_handler.h
@@ -16,11 +16,7 @@
#include "content/browser/renderer_host/input/synthetic_gesture.h"
#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
#include "content/public/browser/render_widget_host.h"
-#include "third_party/WebKit/public/platform/WebInputEvent.h"
-
-namespace viz {
-class CompositorFrameMetadata;
-}
+#include "third_party/blink/public/platform/web_input_event.h"
namespace content {
class DevToolsAgentHostImpl;
@@ -40,8 +36,7 @@ class InputHandler : public DevToolsDomainHandler, public Input::Backend {
void SetRenderer(int process_host_id,
RenderFrameHostImpl* frame_host) override;
- void OnSwapCompositorFrame(
- const viz::CompositorFrameMetadata& frame_metadata);
+ void OnPageScaleFactorChanged(float page_scale_factor);
Response Disable() override;
void DispatchKeyEvent(
diff --git a/chromium/content/browser/devtools/protocol/native_input_event_builder_mac.mm b/chromium/content/browser/devtools/protocol/native_input_event_builder_mac.mm
index 601ec197b5b..3faae032e20 100644
--- a/chromium/content/browser/devtools/protocol/native_input_event_builder_mac.mm
+++ b/chromium/content/browser/devtools/protocol/native_input_event_builder_mac.mm
@@ -5,7 +5,7 @@
#include <Cocoa/Cocoa.h>
#include "base/strings/sys_string_conversions.h"
#include "content/browser/devtools/protocol/native_input_event_builder.h"
-#include "third_party/WebKit/public/platform/WebInputEvent.h"
+#include "third_party/blink/public/platform/web_input_event.h"
namespace content {
namespace protocol {
diff --git a/chromium/content/browser/devtools/protocol/network_handler.cc b/chromium/content/browser/devtools/protocol/network_handler.cc
index 06c84ec3703..6d62f72deae 100644
--- a/chromium/content/browser/devtools/protocol/network_handler.cc
+++ b/chromium/content/browser/devtools/protocol/network_handler.cc
@@ -19,6 +19,7 @@
#include "base/time/time.h"
#include "content/browser/devtools/devtools_interceptor_controller.h"
#include "content/browser/devtools/devtools_session.h"
+#include "content/browser/devtools/devtools_url_loader_interceptor.h"
#include "content/browser/devtools/protocol/page.h"
#include "content/browser/devtools/protocol/security.h"
#include "content/browser/frame_host/frame_tree_node.h"
@@ -38,10 +39,12 @@
#include "content/public/browser/site_instance.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/common/browser_side_navigation_policy.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
#include "net/base/net_errors.h"
#include "net/base/upload_bytes_element_reader.h"
+#include "net/cert/ct_policy_status.h"
#include "net/cert/ct_sct_to_string.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_store.h"
@@ -53,6 +56,7 @@
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "services/network/public/cpp/data_element.h"
+#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/http_raw_request_response_info.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/resource_response.h"
@@ -76,125 +80,203 @@ using ClearBrowserCookiesCallback =
const char kDevToolsEmulateNetworkConditionsClientId[] =
"X-DevTools-Emulate-Network-Conditions-Client-Id";
+Network::CertificateTransparencyCompliance SerializeCTPolicyCompliance(
+ net::ct::CTPolicyCompliance ct_compliance) {
+ switch (ct_compliance) {
+ case net::ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS:
+ return Network::CertificateTransparencyComplianceEnum::Compliant;
+ case net::ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS:
+ case net::ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS:
+ return Network::CertificateTransparencyComplianceEnum::NotCompliant;
+ case net::ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY:
+ case net::ct::CTPolicyCompliance::
+ CT_POLICY_COMPLIANCE_DETAILS_NOT_AVAILABLE:
+ return Network::CertificateTransparencyComplianceEnum::Unknown;
+ case net::ct::CTPolicyCompliance::CT_POLICY_MAX:
+ NOTREACHED();
+ return Network::CertificateTransparencyComplianceEnum::Unknown;
+ }
+ NOTREACHED();
+ return Network::CertificateTransparencyComplianceEnum::Unknown;
+}
+
+std::unique_ptr<Network::Cookie> BuildCookie(
+ const net::CanonicalCookie& cookie) {
+ std::unique_ptr<Network::Cookie> devtools_cookie =
+ Network::Cookie::Create()
+ .SetName(cookie.Name())
+ .SetValue(cookie.Value())
+ .SetDomain(cookie.Domain())
+ .SetPath(cookie.Path())
+ .SetExpires(cookie.ExpiryDate().is_null()
+ ? -1
+ : cookie.ExpiryDate().ToDoubleT())
+ .SetSize(cookie.Name().length() + cookie.Value().length())
+ .SetHttpOnly(cookie.IsHttpOnly())
+ .SetSecure(cookie.IsSecure())
+ .SetSession(!cookie.IsPersistent())
+ .Build();
+
+ switch (cookie.SameSite()) {
+ case net::CookieSameSite::STRICT_MODE:
+ devtools_cookie->SetSameSite(Network::CookieSameSiteEnum::Strict);
+ break;
+ case net::CookieSameSite::LAX_MODE:
+ devtools_cookie->SetSameSite(Network::CookieSameSiteEnum::Lax);
+ break;
+ case net::CookieSameSite::NO_RESTRICTION:
+ break;
+ }
+ return devtools_cookie;
+}
+
+std::unique_ptr<ProtocolCookieArray> BuildCookieArray(
+ const std::vector<net::CanonicalCookie>& cookie_list) {
+ auto cookies = std::make_unique<ProtocolCookieArray>();
+
+ for (const net::CanonicalCookie& cookie : cookie_list)
+ cookies->addItem(BuildCookie(cookie));
+
+ return cookies;
+}
+
class CookieRetriever : public base::RefCountedThreadSafe<CookieRetriever> {
- public:
- CookieRetriever(std::unique_ptr<GetCookiesCallback> callback)
- : callback_(std::move(callback)),
- all_callback_(nullptr) {}
-
- CookieRetriever(std::unique_ptr<GetAllCookiesCallback> callback)
- : callback_(nullptr),
- all_callback_(std::move(callback)) {}
-
- void RetrieveCookiesOnIO(
- net::URLRequestContextGetter* context_getter,
- const std::vector<GURL>& urls) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- callback_count_ = urls.size();
-
- if (callback_count_ == 0) {
- GotAllCookies();
- return;
- }
+ public:
+ CookieRetriever(std::unique_ptr<GetCookiesCallback> callback)
+ : callback_(std::move(callback)), all_callback_(nullptr) {
+ DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
+ }
- for (const GURL& url : urls) {
- net::URLRequestContext* request_context =
- context_getter->GetURLRequestContext();
- request_context->cookie_store()->GetAllCookiesForURLAsync(
- url, base::BindOnce(&CookieRetriever::GotCookies, this));
- }
- }
+ CookieRetriever(std::unique_ptr<GetAllCookiesCallback> callback)
+ : callback_(nullptr), all_callback_(std::move(callback)) {}
- void RetrieveAllCookiesOnIO(
- net::URLRequestContextGetter* context_getter) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- callback_count_ = 1;
+ void RetrieveCookiesOnIO(net::URLRequestContextGetter* context_getter,
+ const std::vector<GURL>& urls) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ callback_count_ = urls.size();
+ if (callback_count_ == 0) {
+ GotAllCookies();
+ return;
+ }
+
+ for (const GURL& url : urls) {
net::URLRequestContext* request_context =
context_getter->GetURLRequestContext();
- request_context->cookie_store()->GetAllCookiesAsync(
- base::BindOnce(&CookieRetriever::GotCookies, this));
+ request_context->cookie_store()->GetAllCookiesForURLAsync(
+ url, base::BindOnce(&CookieRetriever::GotCookies, this));
+ }
+ }
+
+ void RetrieveAllCookiesOnIO(net::URLRequestContextGetter* context_getter) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ callback_count_ = 1;
+
+ net::URLRequestContext* request_context =
+ context_getter->GetURLRequestContext();
+ request_context->cookie_store()->GetAllCookiesAsync(
+ base::BindOnce(&CookieRetriever::GotCookies, this));
+ }
+
+ protected:
+ virtual ~CookieRetriever() {}
+
+ void GotCookies(const net::CookieList& cookie_list) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ for (const net::CanonicalCookie& cookie : cookie_list) {
+ std::string key = base::StringPrintf(
+ "%s::%s::%s::%d", cookie.Name().c_str(), cookie.Domain().c_str(),
+ cookie.Path().c_str(), cookie.IsSecure());
+ cookies_[key] = cookie;
}
- protected:
- virtual ~CookieRetriever() {}
-
- void GotCookies(const net::CookieList& cookie_list) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- for (const net::CanonicalCookie& cookie : cookie_list) {
- std::string key = base::StringPrintf(
- "%s::%s::%s::%d", cookie.Name().c_str(), cookie.Domain().c_str(),
- cookie.Path().c_str(), cookie.IsSecure());
- cookies_[key] = cookie;
- }
- --callback_count_;
- if (callback_count_ == 0)
- GotAllCookies();
+ --callback_count_;
+ if (callback_count_ == 0)
+ GotAllCookies();
+ }
+
+ void GotAllCookies() {
+ net::CookieList master_cookie_list;
+ for (const auto& pair : cookies_)
+ master_cookie_list.push_back(pair.second);
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&CookieRetriever::SendCookiesResponseOnUI, this,
+ master_cookie_list));
+ }
+
+ void SendCookiesResponseOnUI(const net::CookieList& cookie_list) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ std::unique_ptr<ProtocolCookieArray> cookies =
+ BuildCookieArray(cookie_list);
+
+ if (callback_) {
+ callback_->sendSuccess(std::move(cookies));
+ } else {
+ DCHECK(all_callback_);
+ all_callback_->sendSuccess(std::move(cookies));
}
+ }
+
+ std::unique_ptr<GetCookiesCallback> callback_;
+ std::unique_ptr<GetAllCookiesCallback> all_callback_;
+ int callback_count_ = 0;
+ std::unordered_map<std::string, net::CanonicalCookie> cookies_;
- void GotAllCookies() {
- net::CookieList master_cookie_list;
- for (const auto& pair : cookies_)
- master_cookie_list.push_back(pair.second);
+ private:
+ friend class base::RefCountedThreadSafe<CookieRetriever>;
+};
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::BindOnce(&CookieRetriever::SendCookiesResponseOnUI, this,
- master_cookie_list));
+class CookieRetrieverNetworkService
+ : public base::RefCounted<CookieRetrieverNetworkService> {
+ public:
+ static void Retrieve(network::mojom::CookieManager* cookie_manager,
+ const std::vector<GURL> urls,
+ std::unique_ptr<GetCookiesCallback> callback) {
+ scoped_refptr<CookieRetrieverNetworkService> self =
+ new CookieRetrieverNetworkService(std::move(callback));
+ net::CookieOptions cookie_options;
+ cookie_options.set_include_httponly();
+ cookie_options.set_same_site_cookie_mode(
+ net::CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX);
+ cookie_options.set_do_not_update_access_time();
+ for (const auto& url : urls) {
+ cookie_manager->GetCookieList(
+ url, cookie_options,
+ base::BindOnce(&CookieRetrieverNetworkService::GotCookies, self));
}
+ }
- void SendCookiesResponseOnUI(const net::CookieList& cookie_list) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- std::unique_ptr<ProtocolCookieArray> cookies =
- ProtocolCookieArray::create();
-
- for (const net::CanonicalCookie& cookie : cookie_list) {
- std::unique_ptr<Network::Cookie> devtools_cookie =
- Network::Cookie::Create()
- .SetName(cookie.Name())
- .SetValue(cookie.Value())
- .SetDomain(cookie.Domain())
- .SetPath(cookie.Path())
- .SetExpires(cookie.ExpiryDate().is_null() ? -1 : cookie.ExpiryDate().ToDoubleT())
- .SetSize(cookie.Name().length() + cookie.Value().length())
- .SetHttpOnly(cookie.IsHttpOnly())
- .SetSecure(cookie.IsSecure())
- .SetSession(!cookie.IsPersistent())
- .Build();
+ private:
+ friend class base::RefCounted<CookieRetrieverNetworkService>;
- switch (cookie.SameSite()) {
- case net::CookieSameSite::STRICT_MODE:
- devtools_cookie->SetSameSite(Network::CookieSameSiteEnum::Strict);
- break;
- case net::CookieSameSite::LAX_MODE:
- devtools_cookie->SetSameSite(Network::CookieSameSiteEnum::Lax);
- break;
- case net::CookieSameSite::NO_RESTRICTION:
- break;
- }
-
- cookies->addItem(std::move(devtools_cookie));
- }
+ CookieRetrieverNetworkService(std::unique_ptr<GetCookiesCallback> callback)
+ : callback_(std::move(callback)) {}
- if (callback_) {
- callback_->sendSuccess(std::move(cookies));
- } else {
- DCHECK(all_callback_);
- all_callback_->sendSuccess(std::move(cookies));
- }
+ void GotCookies(const std::vector<net::CanonicalCookie>& cookies) {
+ for (const auto& cookie : cookies) {
+ std::string key = base::StringPrintf(
+ "%s::%s::%s::%d", cookie.Name().c_str(), cookie.Domain().c_str(),
+ cookie.Path().c_str(), cookie.IsSecure());
+ all_cookies_.emplace(std::move(key), cookie);
}
+ }
- std::unique_ptr<GetCookiesCallback> callback_;
- std::unique_ptr<GetAllCookiesCallback> all_callback_;
- int callback_count_ = 0;
- std::unordered_map<std::string, net::CanonicalCookie> cookies_;
+ ~CookieRetrieverNetworkService() {
+ auto cookies = std::make_unique<ProtocolCookieArray>();
+ for (const auto& entry : all_cookies_)
+ cookies->addItem(BuildCookie(entry.second));
+ callback_->sendSuccess(std::move(cookies));
+ }
- private:
- friend class base::RefCountedThreadSafe<CookieRetriever>;
+ std::unique_ptr<GetCookiesCallback> callback_;
+ std::unordered_map<std::string, net::CanonicalCookie> all_cookies_;
};
void ClearedCookiesOnIO(std::unique_ptr<ClearBrowserCookiesCallback> callback,
uint32_t num_deleted) {
+ DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
DCHECK_CURRENTLY_ON(BrowserThread::IO);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
@@ -204,6 +286,7 @@ void ClearedCookiesOnIO(std::unique_ptr<ClearBrowserCookiesCallback> callback,
void ClearCookiesOnIO(net::URLRequestContextGetter* context_getter,
std::unique_ptr<ClearBrowserCookiesCallback> callback) {
+ DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
DCHECK_CURRENTLY_ON(BrowserThread::IO);
net::URLRequestContext* request_context =
context_getter->GetURLRequestContext();
@@ -216,36 +299,38 @@ void DeletedCookiesOnIO(base::OnceClosure callback, uint32_t num_deleted) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, std::move(callback));
}
-void DeleteSelectedCookiesOnIO(net::URLRequestContextGetter* context_getter,
- const std::string& name,
- const std::string& url_spec,
- const std::string& domain,
- const std::string& path,
- base::OnceClosure callback,
- const net::CookieList& cookie_list) {
- net::URLRequestContext* request_context =
- context_getter->GetURLRequestContext();
- std::string normalized_domain = domain;
- if (normalized_domain.empty()) {
- GURL url(url_spec);
- if (!url.SchemeIsHTTPOrHTTPS()) {
- std::move(callback).Run();
- return;
- }
- normalized_domain = url.host();
- }
+std::vector<net::CanonicalCookie> FilterCookies(
+ const std::vector<net::CanonicalCookie>& cookies,
+ const std::string& name,
+ const std::string& normalized_domain,
+ const std::string& path) {
+ std::vector<net::CanonicalCookie> result;
- net::CookieList filtered_list;
- for (const auto& cookie : cookie_list) {
+ for (const auto& cookie : cookies) {
if (cookie.Name() != name)
continue;
if (cookie.Domain() != normalized_domain)
continue;
if (!path.empty() && cookie.Path() != path)
continue;
- filtered_list.push_back(cookie);
+ result.push_back(cookie);
}
+ return result;
+}
+
+void DeleteSelectedCookiesOnIO(net::URLRequestContextGetter* context_getter,
+ const std::string& name,
+ const std::string& normalized_domain,
+ const std::string& path,
+ base::OnceClosure callback,
+ const net::CookieList& cookie_list) {
+ DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
+
+ net::URLRequestContext* request_context =
+ context_getter->GetURLRequestContext();
+ net::CookieList filtered_list =
+ FilterCookies(cookie_list, name, normalized_domain, path);
for (size_t i = 0; i < filtered_list.size(); ++i) {
const auto& cookie = filtered_list[i];
base::OnceCallback<void(uint32_t)> once_callback;
@@ -255,22 +340,22 @@ void DeleteSelectedCookiesOnIO(net::URLRequestContextGetter* context_getter,
cookie, std::move(once_callback));
}
if (!filtered_list.size())
- std::move(callback).Run();
+ DeletedCookiesOnIO(std::move(callback), 0);
}
void DeleteCookiesOnIO(net::URLRequestContextGetter* context_getter,
const std::string& name,
- const std::string& url,
- const std::string& domain,
+ const std::string& normalized_domain,
const std::string& path,
base::OnceClosure callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
net::URLRequestContext* request_context =
context_getter->GetURLRequestContext();
request_context->cookie_store()->GetAllCookiesAsync(base::BindOnce(
- &DeleteSelectedCookiesOnIO, base::Unretained(context_getter), name, url,
- domain, path, std::move(callback)));
+ &DeleteSelectedCookiesOnIO, base::Unretained(context_getter), name,
+ normalized_domain, path, std::move(callback)));
}
void CookieSetOnIO(std::unique_ptr<SetCookieCallback> callback, bool success) {
@@ -280,33 +365,55 @@ void CookieSetOnIO(std::unique_ptr<SetCookieCallback> callback, bool success) {
std::move(callback), success));
}
-void SetCookieOnIO(net::URLRequestContextGetter* context_getter,
- const std::string& name,
- const std::string& value,
- const std::string& url_spec,
- const std::string& domain,
- const std::string& path,
- bool secure,
- bool http_only,
- const std::string& same_site,
- double expires,
- base::OnceCallback<void(bool)> callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- net::URLRequestContext* request_context =
- context_getter->GetURLRequestContext();
+void DeleteFilteredCookies(network::mojom::CookieManager* cookie_manager,
+ const std::string& name,
+ const std::string& normalized_domain,
+ const std::string& path,
+ std::unique_ptr<DeleteCookiesCallback> callback,
+ const std::vector<net::CanonicalCookie>& cookies) {
+ base::Time yesterday(base::Time::Now() - base::TimeDelta::FromDays(1));
- if (url_spec.empty() && domain.empty()) {
- std::move(callback).Run(false);
- return;
+ std::vector<net::CanonicalCookie> filtered_list =
+ FilterCookies(cookies, name, normalized_domain, path);
+
+ base::RepeatingClosure barrier_closure = base::BarrierClosure(
+ filtered_list.size(),
+ base::BindOnce(&DeleteCookiesCallback::sendSuccess, std::move(callback)));
+
+ for (auto& cookie : filtered_list) {
+ // Delete a single cookie by setting its expiration time into the past.
+ cookie_manager->SetCanonicalCookie(
+ net::CanonicalCookie(cookie.Name(), cookie.Value(), cookie.Domain(),
+ cookie.Path(), cookie.CreationDate(), yesterday,
+ cookie.LastAccessDate(), cookie.IsSecure(),
+ cookie.IsHttpOnly(), cookie.SameSite(),
+ cookie.Priority()),
+ true /* secure_source */, true /* modify_http_only */,
+ base::BindOnce(
+ [](base::RepeatingClosure callback, bool) { callback.Run(); },
+ barrier_closure));
}
+}
+std::unique_ptr<net::CanonicalCookie> MakeCookieFromProtocolValues(
+ const std::string& name,
+ const std::string& value,
+ const std::string& url_spec,
+ const std::string& domain,
+ const std::string& path,
+ bool secure,
+ bool http_only,
+ const std::string& same_site,
+ double expires) {
std::string normalized_domain = domain;
+
+ if (url_spec.empty() && domain.empty())
+ return nullptr;
+
if (!url_spec.empty()) {
GURL source_url = GURL(url_spec);
- if (!source_url.SchemeIsHTTPOrHTTPS()) {
- std::move(callback).Run(false);
- return;
- }
+ if (!source_url.SchemeIsHTTPOrHTTPS())
+ return nullptr;
secure = secure || source_url.SchemeIsCryptographic();
if (normalized_domain.empty())
@@ -329,45 +436,44 @@ void SetCookieOnIO(net::URLRequestContextGetter* context_getter,
if (same_site == Network::CookieSameSiteEnum::Strict)
css = net::CookieSameSite::STRICT_MODE;
- std::unique_ptr<net::CanonicalCookie> cc(
- net::CanonicalCookie::CreateSanitizedCookie(
- url, name, value, normalized_domain, path, base::Time(),
- expiration_date, base::Time(), secure, http_only, css,
- net::COOKIE_PRIORITY_DEFAULT));
- if (!cc) {
- std::move(callback).Run(false);
- return;
- }
+ return net::CanonicalCookie::CreateSanitizedCookie(
+ url, name, value, normalized_domain, path, base::Time(), expiration_date,
+ base::Time(), secure, http_only, css, net::COOKIE_PRIORITY_DEFAULT);
+}
+
+void SetCookieOnIO(net::URLRequestContextGetter* context_getter,
+ std::unique_ptr<net::CanonicalCookie> cookie,
+ base::OnceCallback<void(bool)> callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
+ net::URLRequestContext* request_context =
+ context_getter->GetURLRequestContext();
+
request_context->cookie_store()->SetCanonicalCookieAsync(
- std::move(cc), secure, true /*modify_http_only*/, std::move(callback));
+ std::move(cookie), true /* secure_source */, true /*modify_http_only*/,
+ std::move(callback));
}
-void CookiesSetOnIO(std::unique_ptr<SetCookiesCallback> callback,
- bool success) {
+void CookiesSetOnIO(std::unique_ptr<SetCookiesCallback> callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::BindOnce(&SetCookiesCallback::sendSuccess, std::move(callback)));
}
-void SetCookiesOnIO(
- net::URLRequestContextGetter* context_getter,
- std::unique_ptr<protocol::Array<Network::CookieParam>> cookies,
- base::OnceCallback<void(bool)> callback) {
+void SetCookiesOnIO(net::URLRequestContextGetter* context_getter,
+ std::vector<std::unique_ptr<net::CanonicalCookie>> cookies,
+ base::OnceClosure callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
- for (size_t i = 0; i < cookies->length(); i++) {
- Network::CookieParam* cookie = cookies->get(i);
-
- base::OnceCallback<void(bool)> once_callback;
- if (i == cookies->length() - 1)
- once_callback = std::move(callback);
-
- SetCookieOnIO(context_getter, cookie->GetName(), cookie->GetValue(),
- cookie->GetUrl(""), cookie->GetDomain(""),
- cookie->GetPath(""), cookie->GetSecure(false),
- cookie->GetHttpOnly(false), cookie->GetSameSite(""),
- cookie->GetExpires(-1), std::move(once_callback));
+ base::RepeatingClosure barrier_closure =
+ base::BarrierClosure(cookies.size(), std::move(callback));
+ for (auto& cookie : cookies) {
+ SetCookieOnIO(context_getter, std::move(cookie),
+ base::BindOnce([](base::RepeatingClosure callback,
+ bool) { callback.Run(); },
+ barrier_closure));
}
}
@@ -809,6 +915,7 @@ Response NetworkHandler::Disable() {
enabled_ = false;
user_agent_ = std::string();
interception_handle_.reset();
+ url_loader_interceptor_.reset();
SetNetworkConditions(nullptr);
extra_headers_.clear();
return Response::FallThrough();
@@ -863,30 +970,47 @@ void NetworkHandler::ClearBrowserCookies(
return;
}
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(
- &ClearCookiesOnIO,
- base::Unretained(storage_partition_->GetURLRequestContext()),
- std::move(callback)));
+ if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(
+ &ClearCookiesOnIO,
+ base::Unretained(storage_partition_->GetURLRequestContext()),
+ std::move(callback)));
+ return;
+ }
+
+ storage_partition_->GetCookieManagerForBrowserProcess()->DeleteCookies(
+ network::mojom::CookieDeletionFilter::New(),
+ base::BindOnce([](std::unique_ptr<ClearBrowserCookiesCallback> callback,
+ uint32_t) { callback->sendSuccess(); },
+ std::move(callback)));
}
void NetworkHandler::GetCookies(Maybe<Array<String>> protocol_urls,
std::unique_ptr<GetCookiesCallback> callback) {
- if (!host_) {
+ if (!host_ || !storage_partition_) {
callback->sendFailure(Response::InternalError());
return;
}
-
std::vector<GURL> urls = ComputeCookieURLs(host_, protocol_urls);
- scoped_refptr<CookieRetriever> retriever =
- new CookieRetriever(std::move(callback));
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(
- &CookieRetriever::RetrieveCookiesOnIO, retriever,
- base::Unretained(storage_partition_->GetURLRequestContext()), urls));
+ if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ scoped_refptr<CookieRetriever> retriever =
+ new CookieRetriever(std::move(callback));
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(
+ &CookieRetriever::RetrieveCookiesOnIO, retriever,
+ base::Unretained(storage_partition_->GetURLRequestContext()),
+ urls));
+ return;
+ }
+
+ CookieRetrieverNetworkService::Retrieve(
+ storage_partition_->GetCookieManagerForBrowserProcess(), urls,
+ std::move(callback));
}
void NetworkHandler::GetAllCookies(
@@ -895,15 +1019,25 @@ void NetworkHandler::GetAllCookies(
callback->sendFailure(Response::InternalError());
return;
}
+ if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ scoped_refptr<CookieRetriever> retriever =
+ new CookieRetriever(std::move(callback));
- scoped_refptr<CookieRetriever> retriever =
- new CookieRetriever(std::move(callback));
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(
+ &CookieRetriever::RetrieveAllCookiesOnIO, retriever,
+ base::Unretained(storage_partition_->GetURLRequestContext())));
+ return;
+ }
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
+ storage_partition_->GetCookieManagerForBrowserProcess()->GetAllCookies(
base::BindOnce(
- &CookieRetriever::RetrieveAllCookiesOnIO, retriever,
- base::Unretained(storage_partition_->GetURLRequestContext())));
+ [](std::unique_ptr<GetAllCookiesCallback> callback,
+ const std::vector<net::CanonicalCookie>& cookies) {
+ callback->sendSuccess(BuildCookieArray(cookies));
+ },
+ std::move(callback)));
}
void NetworkHandler::SetCookie(const std::string& name,
@@ -926,15 +1060,32 @@ void NetworkHandler::SetCookie(const std::string& name,
"At least one of the url and domain needs to be specified"));
}
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(
- &SetCookieOnIO,
- base::Unretained(storage_partition_->GetURLRequestContext()), name,
- value, url.fromMaybe(""), domain.fromMaybe(""), path.fromMaybe(""),
- secure.fromMaybe(false), http_only.fromMaybe(false),
- same_site.fromMaybe(""), expires.fromMaybe(-1),
- base::BindOnce(&CookieSetOnIO, std::move(callback))));
+ std::unique_ptr<net::CanonicalCookie> cookie = MakeCookieFromProtocolValues(
+ name, value, url.fromMaybe(""), domain.fromMaybe(""), path.fromMaybe(""),
+ secure.fromMaybe(false), http_only.fromMaybe(false),
+ same_site.fromMaybe(""), expires.fromMaybe(-1));
+
+ if (!cookie) {
+ // TODO(caseq): Current logic is for compatability only.
+ // Consider returning protocol error here.
+ callback->sendSuccess(false);
+ return;
+ }
+
+ if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(
+ &SetCookieOnIO,
+ base::Unretained(storage_partition_->GetURLRequestContext()),
+ std::move(cookie),
+ base::BindOnce(&CookieSetOnIO, std::move(callback))));
+ return;
+ }
+
+ storage_partition_->GetCookieManagerForBrowserProcess()->SetCanonicalCookie(
+ *cookie, true /* secure_source */, true /* modify_http_only */,
+ base::BindOnce(&SetCookieCallback::sendSuccess, std::move(callback)));
}
void NetworkHandler::SetCookies(
@@ -945,18 +1096,51 @@ void NetworkHandler::SetCookies(
return;
}
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(
- &SetCookiesOnIO,
- base::Unretained(storage_partition_->GetURLRequestContext()),
- std::move(cookies),
- base::BindOnce(&CookiesSetOnIO, std::move(callback))));
+ std::vector<std::unique_ptr<net::CanonicalCookie>> net_cookies;
+ for (size_t i = 0; i < cookies->length(); i++) {
+ Network::CookieParam* cookie = cookies->get(i);
+ std::unique_ptr<net::CanonicalCookie> net_cookie =
+ MakeCookieFromProtocolValues(
+ cookie->GetName(), cookie->GetValue(), cookie->GetUrl(""),
+ cookie->GetDomain(""), cookie->GetPath(""),
+ cookie->GetSecure(false), cookie->GetHttpOnly(false),
+ cookie->GetSameSite(""), cookie->GetExpires(-1));
+ if (!cookie) {
+ callback->sendFailure(Response::InvalidParams("Invalid cookie fields"));
+ return;
+ }
+ net_cookies.push_back(std::move(net_cookie));
+ }
+
+ if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(
+ &SetCookiesOnIO,
+ base::Unretained(storage_partition_->GetURLRequestContext()),
+ std::move(net_cookies),
+ base::BindOnce(&CookiesSetOnIO, std::move(callback))));
+ return;
+ }
+
+ base::RepeatingClosure barrier_closure = base::BarrierClosure(
+ net_cookies.size(),
+ base::BindOnce(&SetCookiesCallback::sendSuccess, std::move(callback)));
+
+ auto* cookie_manager =
+ storage_partition_->GetCookieManagerForBrowserProcess();
+ for (const auto& cookie : net_cookies) {
+ cookie_manager->SetCanonicalCookie(
+ *cookie, true, true,
+ base::BindOnce(
+ [](base::RepeatingClosure callback, bool) { callback.Run(); },
+ barrier_closure));
+ }
}
void NetworkHandler::DeleteCookies(
const std::string& name,
- Maybe<std::string> url,
+ Maybe<std::string> url_spec,
Maybe<std::string> domain,
Maybe<std::string> path,
std::unique_ptr<DeleteCookiesCallback> callback) {
@@ -964,19 +1148,40 @@ void NetworkHandler::DeleteCookies(
callback->sendFailure(Response::InternalError());
return;
}
-
- if (!url.isJust() && !domain.isJust()) {
+ if (!url_spec.isJust() && !domain.isJust()) {
callback->sendFailure(Response::InvalidParams(
"At least one of the url and domain needs to be specified"));
}
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(
- &DeleteCookiesOnIO,
- base::Unretained(storage_partition_->GetURLRequestContext()), name,
- url.fromMaybe(""), domain.fromMaybe(""), path.fromMaybe(""),
- base::BindOnce(&DeleteCookiesCallback::sendSuccess,
- std::move(callback))));
+
+ std::string normalized_domain = domain.fromMaybe("");
+ if (normalized_domain.empty()) {
+ GURL url(url_spec.fromMaybe(""));
+ if (!url.SchemeIsHTTPOrHTTPS()) {
+ callback->sendFailure(Response::InvalidParams(
+ "An http or https url URL must be specified"));
+ return;
+ }
+ normalized_domain = url.host();
+ }
+
+ if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(
+ &DeleteCookiesOnIO,
+ base::Unretained(storage_partition_->GetURLRequestContext()), name,
+ normalized_domain, path.fromMaybe(""),
+ base::BindOnce(&DeleteCookiesCallback::sendSuccess,
+ std::move(callback))));
+ return;
+ }
+
+ auto* cookie_manager =
+ storage_partition_->GetCookieManagerForBrowserProcess();
+
+ cookie_manager->GetAllCookies(base::BindOnce(
+ &DeleteFilteredCookies, base::Unretained(cookie_manager), name,
+ normalized_domain, path.fromMaybe(""), std::move(callback)));
}
Response NetworkHandler::SetUserAgentOverride(const std::string& user_agent) {
@@ -1041,20 +1246,14 @@ Response NetworkHandler::SetBypassServiceWorker(bool bypass) {
namespace {
std::unique_ptr<protocol::Network::SecurityDetails> BuildSecurityDetails(
- const network::ResourceResponseInfo& info) {
- if (info.certificate.empty())
+ const net::SSLInfo& ssl_info) {
+ if (!ssl_info.cert)
return nullptr;
- scoped_refptr<net::X509Certificate> cert(
- net::X509Certificate::CreateFromBytes(info.certificate[0].data(),
- info.certificate[0].size()));
- if (!cert)
- return nullptr;
-
std::unique_ptr<
protocol::Array<protocol::Network::SignedCertificateTimestamp>>
signed_certificate_timestamp_list =
protocol::Array<Network::SignedCertificateTimestamp>::create();
- for (auto const& sct : info.signed_certificate_timestamps) {
+ for (auto const& sct : ssl_info.signed_certificate_timestamps) {
std::unique_ptr<protocol::Network::SignedCertificateTimestamp>
signed_certificate_timestamp =
Network::SignedCertificateTimestamp::Create()
@@ -1063,8 +1262,8 @@ std::unique_ptr<protocol::Network::SecurityDetails> BuildSecurityDetails(
.SetLogDescription(sct.sct->log_description)
.SetLogId(base::HexEncode(sct.sct->log_id.c_str(),
sct.sct->log_id.length()))
- .SetTimestamp(
- (sct.sct->timestamp - base::Time()).InMillisecondsF())
+ .SetTimestamp((sct.sct->timestamp - base::Time::UnixEpoch())
+ .InMillisecondsF())
.SetHashAlgorithm(net::ct::HashAlgorithmToString(
sct.sct->signature.hash_algorithm))
.SetSignatureAlgorithm(net::ct::SignatureAlgorithmToString(
@@ -1078,7 +1277,7 @@ std::unique_ptr<protocol::Network::SecurityDetails> BuildSecurityDetails(
}
std::vector<std::string> san_dns;
std::vector<std::string> san_ip;
- cert->GetSubjectAltName(&san_dns, &san_ip);
+ ssl_info.cert->GetSubjectAltName(&san_dns, &san_ip);
std::unique_ptr<Array<String>> san_list = Array<String>::create();
for (const std::string& san : san_dns)
san_list->addItem(san);
@@ -1088,23 +1287,27 @@ std::unique_ptr<protocol::Network::SecurityDetails> BuildSecurityDetails(
.ToString());
}
+ const char* protocol = "";
+ const char* key_exchange = "";
+ const char* cipher = "";
+ const char* mac = nullptr;
+
int ssl_version =
- net::SSLConnectionStatusToVersion(info.ssl_connection_status);
- const char* protocol;
- net::SSLVersionToString(&protocol, ssl_version);
-
- const char* key_exchange;
- const char* cipher;
- const char* mac;
- bool is_aead;
- bool is_tls13;
- uint16_t cipher_suite =
- net::SSLConnectionStatusToCipherSuite(info.ssl_connection_status);
- net::SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, &is_aead,
- &is_tls13, cipher_suite);
- if (key_exchange == nullptr) {
- DCHECK(is_tls13);
- key_exchange = "";
+ net::SSLConnectionStatusToVersion(ssl_info.connection_status);
+
+ if (ssl_info.connection_status) {
+ net::SSLVersionToString(&protocol, ssl_version);
+
+ bool is_aead;
+ bool is_tls13;
+ uint16_t cipher_suite =
+ net::SSLConnectionStatusToCipherSuite(ssl_info.connection_status);
+ net::SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, &is_aead,
+ &is_tls13, cipher_suite);
+ if (key_exchange == nullptr) {
+ DCHECK(is_tls13);
+ key_exchange = "";
+ }
}
std::unique_ptr<protocol::Network::SecurityDetails> security_details =
@@ -1112,19 +1315,21 @@ std::unique_ptr<protocol::Network::SecurityDetails> BuildSecurityDetails(
.SetProtocol(protocol)
.SetKeyExchange(key_exchange)
.SetCipher(cipher)
- .SetSubjectName(cert->subject().common_name)
+ .SetSubjectName(ssl_info.cert->subject().common_name)
.SetSanList(std::move(san_list))
- .SetIssuer(cert->issuer().common_name)
- .SetValidFrom(cert->valid_start().ToDoubleT())
- .SetValidTo(cert->valid_expiry().ToDoubleT())
+ .SetIssuer(ssl_info.cert->issuer().common_name)
+ .SetValidFrom(ssl_info.cert->valid_start().ToDoubleT())
+ .SetValidTo(ssl_info.cert->valid_expiry().ToDoubleT())
.SetCertificateId(0) // Keep this in protocol for compatability.
.SetSignedCertificateTimestampList(
std::move(signed_certificate_timestamp_list))
+ .SetCertificateTransparencyCompliance(
+ SerializeCTPolicyCompliance(ssl_info.ct_policy_compliance))
.Build();
- if (info.ssl_key_exchange_group != 0) {
+ if (ssl_info.key_exchange_group != 0) {
const char* key_exchange_group =
- SSL_get_curve_name(info.ssl_key_exchange_group);
+ SSL_get_curve_name(ssl_info.key_exchange_group);
if (key_exchange_group)
security_details->SetKeyExchangeGroup(key_exchange_group);
}
@@ -1195,7 +1400,8 @@ std::unique_ptr<Network::Response> BuildResponse(
response->SetProtocol(GetProtocol(url, info));
response->SetRemoteIPAddress(info.socket_address.HostForURL());
response->SetRemotePort(info.socket_address.port());
- response->SetSecurityDetails(BuildSecurityDetails(info));
+ if (info.ssl_info.has_value())
+ response->SetSecurityDetails(BuildSecurityDetails(*info.ssl_info));
return response;
}
@@ -1242,12 +1448,13 @@ void NetworkHandler::NavigationRequestWillBeSent(
request->SetMixedContentType(Security::MixedContentTypeEnum::None);
std::unique_ptr<Network::Initiator> initiator;
- base::DictionaryValue* initiator_value =
- nav_request.begin_params()->devtools_initiator.get();
- if (initiator_value) {
+ const base::Optional<base::Value>& initiator_optional =
+ nav_request.begin_params()->devtools_initiator;
+ if (initiator_optional.has_value()) {
ErrorSupport ignored_errors;
initiator = Network::Initiator::fromValue(
- toProtocolValue(initiator_value, 1000).get(), &ignored_errors);
+ toProtocolValue(&initiator_optional.value(), 1000).get(),
+ &ignored_errors);
}
if (!initiator) {
initiator = Network::Initiator::Create()
@@ -1264,7 +1471,8 @@ void NetworkHandler::NavigationRequestWillBeSent(
id, id, StripFragment(common_params.url), std::move(request),
current_ticks, current_wall_time, std::move(initiator),
std::move(redirect_response),
- std::string(Page::ResourceTypeEnum::Document), std::move(frame_token));
+ std::string(Page::ResourceTypeEnum::Document), std::move(frame_token),
+ common_params.has_user_gesture);
}
void NetworkHandler::RequestSent(const std::string& request_id,
@@ -1290,7 +1498,8 @@ void NetworkHandler::RequestSent(const std::string& request_id,
base::Time::Now().ToDoubleT(),
Network::Initiator::Create().SetType(initiator_type).Build(),
std::unique_ptr<Network::Response>(),
- std::string(Page::ResourceTypeEnum::Other));
+ std::string(Page::ResourceTypeEnum::Other),
+ Maybe<std::string>() /* frame_id */, request.has_user_gesture);
}
void NetworkHandler::ResponseReceived(const std::string& request_id,
@@ -1369,7 +1578,9 @@ void NetworkHandler::NavigationFailed(NavigationRequest* navigation_request) {
.SetType(Network::Initiator::TypeEnum::Parser)
.Build(),
std::unique_ptr<Network::Response>(),
- std::string(Page::ResourceTypeEnum::Document));
+ std::string(Page::ResourceTypeEnum::Document),
+ Maybe<std::string>() /* frame_id */,
+ navigation_request->common_params().has_user_gesture);
frontend_->LoadingFailed(
request_id,
@@ -1381,18 +1592,9 @@ void NetworkHandler::NavigationFailed(NavigationRequest* navigation_request) {
DispatchResponse NetworkHandler::SetRequestInterception(
std::unique_ptr<protocol::Array<protocol::Network::RequestPattern>>
patterns) {
- WebContents* web_contents = WebContents::FromRenderFrameHost(host_);
- if (!web_contents)
- return Response::InternalError();
-
- DevToolsInterceptorController* interceptor =
- DevToolsInterceptorController::FromBrowserContext(
- web_contents->GetBrowserContext());
- if (!interceptor)
- return Response::Error("Interception not supported");
-
if (!patterns->length()) {
interception_handle_.reset();
+ url_loader_interceptor_.reset();
return Response::OK();
}
@@ -1412,13 +1614,37 @@ DispatchResponse NetworkHandler::SetRequestInterception(
protocol::Network::InterceptionStageEnum::Request))));
}
+ if (!host_)
+ return Response::InternalError();
+
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ if (!url_loader_interceptor_) {
+ url_loader_interceptor_ = std::make_unique<DevToolsURLLoaderInterceptor>(
+ host_->frame_tree_node(),
+ base::BindRepeating(&NetworkHandler::RequestIntercepted,
+ weak_factory_.GetWeakPtr()));
+ }
+ url_loader_interceptor_->SetPatterns(interceptor_patterns);
+ return Response::OK();
+ }
+
+ WebContents* web_contents = WebContents::FromRenderFrameHost(host_);
+ if (!web_contents)
+ return Response::InternalError();
+
+ DevToolsInterceptorController* interceptor =
+ DevToolsInterceptorController::FromBrowserContext(
+ web_contents->GetBrowserContext());
+ if (!interceptor)
+ return Response::Error("Interception not supported");
+
if (interception_handle_) {
- interception_handle_->UpdatePatterns(std::move(interceptor_patterns));
+ interception_handle_->UpdatePatterns(interceptor_patterns);
} else {
interception_handle_ = interceptor->StartInterceptingRequests(
- host_->frame_tree_node(), std::move(interceptor_patterns),
- base::Bind(&NetworkHandler::RequestIntercepted,
- weak_factory_.GetWeakPtr()));
+ host_->frame_tree_node(), interceptor_patterns,
+ base::BindRepeating(&NetworkHandler::RequestIntercepted,
+ weak_factory_.GetWeakPtr()));
}
return Response::OK();
@@ -1434,13 +1660,6 @@ void NetworkHandler::ContinueInterceptedRequest(
Maybe<protocol::Network::Headers> headers,
Maybe<protocol::Network::AuthChallengeResponse> auth_challenge_response,
std::unique_ptr<ContinueInterceptedRequestCallback> callback) {
- DevToolsInterceptorController* interceptor =
- DevToolsInterceptorController::FromBrowserContext(browser_context_);
- if (!interceptor) {
- callback->sendFailure(Response::InternalError());
- return;
- }
-
base::Optional<std::string> raw_response;
if (base64_raw_response.isJust()) {
std::string decoded;
@@ -1464,18 +1683,37 @@ void NetworkHandler::ContinueInterceptedRequest(
mark_as_canceled = true;
}
- interceptor->ContinueInterceptedRequest(
- interception_id,
+ auto modifications =
std::make_unique<DevToolsNetworkInterceptor::Modifications>(
std::move(error), std::move(raw_response), std::move(url),
std::move(method), std::move(post_data), std::move(headers),
- std::move(auth_challenge_response), mark_as_canceled),
- std::move(callback));
+ std::move(auth_challenge_response), mark_as_canceled);
+
+ if (url_loader_interceptor_) {
+ url_loader_interceptor_->ContinueInterceptedRequest(
+ interception_id, std::move(modifications), std::move(callback));
+ return;
+ }
+
+ DevToolsInterceptorController* interceptor =
+ DevToolsInterceptorController::FromBrowserContext(browser_context_);
+ if (!interceptor) {
+ callback->sendFailure(Response::InternalError());
+ return;
+ }
+ interceptor->ContinueInterceptedRequest(
+ interception_id, std::move(modifications), std::move(callback));
}
void NetworkHandler::GetResponseBodyForInterception(
const String& interception_id,
std::unique_ptr<GetResponseBodyForInterceptionCallback> callback) {
+ if (url_loader_interceptor_) {
+ url_loader_interceptor_->GetResponseBody(interception_id,
+ std::move(callback));
+ return;
+ }
+
DevToolsInterceptorController* interceptor =
DevToolsInterceptorController::FromBrowserContext(browser_context_);
if (!interceptor) {
@@ -1495,6 +1733,31 @@ GURL NetworkHandler::ClearUrlRef(const GURL& url) {
}
// static
+std::unique_ptr<Network::Request>
+NetworkHandler::CreateRequestFromResourceRequest(
+ const network::ResourceRequest& request) {
+ std::unique_ptr<DictionaryValue> headers_dict(DictionaryValue::create());
+ for (net::HttpRequestHeaders::Iterator it(request.headers); it.GetNext();)
+ headers_dict->setString(it.name(), it.value());
+ if (request.referrer.is_valid()) {
+ headers_dict->setString(net::HttpRequestHeaders::kReferer,
+ request.referrer.spec());
+ }
+ std::unique_ptr<protocol::Network::Request> request_object =
+ Network::Request::Create()
+ .SetUrl(ClearUrlRef(request.url).spec())
+ .SetMethod(request.method)
+ .SetHeaders(Object::fromValue(headers_dict.get(), nullptr))
+ .SetInitialPriority(resourcePriority(request.priority))
+ .SetReferrerPolicy(referrerPolicy(request.referrer_policy))
+ .Build();
+ std::string post_data;
+ if (request.request_body && GetPostData(*request.request_body, &post_data))
+ request_object->SetPostData(std::move(post_data));
+ return request_object;
+}
+
+// static
std::unique_ptr<Network::Request> NetworkHandler::CreateRequestFromURLRequest(
const net::URLRequest* request) {
std::unique_ptr<DictionaryValue> headers_dict(DictionaryValue::create());
@@ -1540,6 +1803,15 @@ bool NetworkHandler::ShouldCancelNavigation(
return interceptor && interceptor->ShouldCancelNavigation(global_request_id);
}
+bool NetworkHandler::MaybeCreateProxyForInterception(
+ const base::UnguessableToken& frame_token,
+ int process_id,
+ network::mojom::URLLoaderFactoryRequest* target_factory_request) {
+ return url_loader_interceptor_ &&
+ url_loader_interceptor_->CreateProxyForInterception(
+ frame_token, process_id, target_factory_request);
+}
+
void NetworkHandler::ApplyOverrides(net::HttpRequestHeaders* headers,
bool* skip_service_worker,
bool* disable_cache) {
diff --git a/chromium/content/browser/devtools/protocol/network_handler.h b/chromium/content/browser/devtools/protocol/network_handler.h
index f28d42d4601..6bf4e7e976a 100644
--- a/chromium/content/browser/devtools/protocol/network_handler.h
+++ b/chromium/content/browser/devtools/protocol/network_handler.h
@@ -11,12 +11,17 @@
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "content/browser/devtools/devtools_url_loader_interceptor.h"
#include "content/browser/devtools/protocol/devtools_domain_handler.h"
#include "content/browser/devtools/protocol/network.h"
#include "net/base/net_errors.h"
#include "net/cookies/canonical_cookie.h"
#include "services/network/public/mojom/network_service.mojom.h"
+namespace base {
+class UnguessableToken;
+};
+
namespace net {
class HttpRequestHeaders;
class URLRequest;
@@ -120,6 +125,11 @@ class NetworkHandler : public DevToolsDomainHandler,
std::unique_ptr<GetResponseBodyForInterceptionCallback> callback)
override;
+ bool MaybeCreateProxyForInterception(
+ const base::UnguessableToken& frame_token,
+ int process_id,
+ network::mojom::URLLoaderFactoryRequest* target_factory_request);
+
void ApplyOverrides(net::HttpRequestHeaders* headers,
bool* skip_service_worker,
bool* disable_cache);
@@ -146,6 +156,8 @@ class NetworkHandler : public DevToolsDomainHandler,
Network::Frontend* frontend() const { return frontend_.get(); }
static GURL ClearUrlRef(const GURL& url);
+ static std::unique_ptr<Network::Request> CreateRequestFromResourceRequest(
+ const network::ResourceRequest& request);
static std::unique_ptr<Network::Request> CreateRequestFromURLRequest(
const net::URLRequest* request);
@@ -169,6 +181,7 @@ class NetworkHandler : public DevToolsDomainHandler,
std::vector<std::pair<std::string, std::string>> extra_headers_;
std::string host_id_;
std::unique_ptr<InterceptionHandle> interception_handle_;
+ std::unique_ptr<DevToolsURLLoaderInterceptor> url_loader_interceptor_;
bool bypass_service_worker_;
bool cache_disabled_;
base::WeakPtrFactory<NetworkHandler> weak_factory_;
diff --git a/chromium/content/browser/devtools/protocol/page_handler.cc b/chromium/content/browser/devtools/protocol/page_handler.cc
index a76eb43b702..8dc4689a515 100644
--- a/chromium/content/browser/devtools/protocol/page_handler.cc
+++ b/chromium/content/browser/devtools/protocol/page_handler.cc
@@ -230,6 +230,7 @@ void PageHandler::DidRunJavaScriptDialog(const GURL& url,
const base::string16& message,
const base::string16& default_prompt,
JavaScriptDialogType dialog_type,
+ bool has_non_devtools_handlers,
JavaScriptDialogCallback callback) {
if (!enabled_)
return;
@@ -241,10 +242,12 @@ void PageHandler::DidRunJavaScriptDialog(const GURL& url,
if (dialog_type == JAVASCRIPT_DIALOG_TYPE_PROMPT)
type = Page::DialogTypeEnum::Prompt;
frontend_->JavascriptDialogOpening(url.spec(), base::UTF16ToUTF8(message),
- type, base::UTF16ToUTF8(default_prompt));
+ type, has_non_devtools_handlers,
+ base::UTF16ToUTF8(default_prompt));
}
void PageHandler::DidRunBeforeUnloadConfirm(const GURL& url,
+ bool has_non_devtools_handlers,
JavaScriptDialogCallback callback) {
if (!enabled_)
return;
@@ -252,7 +255,7 @@ void PageHandler::DidRunBeforeUnloadConfirm(const GURL& url,
pending_dialog_ = std::move(callback);
frontend_->JavascriptDialogOpening(url.spec(), std::string(),
Page::DialogTypeEnum::Beforeunload,
- std::string());
+ has_non_devtools_handlers, std::string());
}
void PageHandler::DidCloseJavaScriptDialog(bool success,
diff --git a/chromium/content/browser/devtools/protocol/page_handler.h b/chromium/content/browser/devtools/protocol/page_handler.h
index 9c1b84e68d9..8e45be2d993 100644
--- a/chromium/content/browser/devtools/protocol/page_handler.h
+++ b/chromium/content/browser/devtools/protocol/page_handler.h
@@ -24,7 +24,7 @@
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/common/javascript_dialog_type.h"
-#include "third_party/WebKit/public/platform/modules/manifest/manifest_manager.mojom.h"
+#include "third_party/blink/public/platform/modules/manifest/manifest_manager.mojom.h"
#include "url/gurl.h"
class SkBitmap;
@@ -78,8 +78,10 @@ class PageHandler : public DevToolsDomainHandler,
const base::string16& message,
const base::string16& default_prompt,
JavaScriptDialogType dialog_type,
+ bool has_non_devtools_handlers,
JavaScriptDialogCallback callback);
void DidRunBeforeUnloadConfirm(const GURL& url,
+ bool has_non_devtools_handlers,
JavaScriptDialogCallback callback);
void DidCloseJavaScriptDialog(bool success, const base::string16& user_input);
void NavigationReset(NavigationRequest* navigation_request);
diff --git a/chromium/content/browser/devtools/protocol/security_handler.cc b/chromium/content/browser/devtools/protocol/security_handler.cc
index bd4a401fdca..bdc3c63acb8 100644
--- a/chromium/content/browser/devtools/protocol/security_handler.cc
+++ b/chromium/content/browser/devtools/protocol/security_handler.cc
@@ -20,7 +20,7 @@
#include "content/public/browser/web_contents_delegate.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_util.h"
-#include "third_party/WebKit/public/platform/WebMixedContentContextType.h"
+#include "third_party/blink/public/platform/web_mixed_content_context_type.h"
namespace content {
namespace protocol {
@@ -141,6 +141,8 @@ void SecurityHandler::SetRenderer(int process_host_id,
void SecurityHandler::DidChangeVisibleSecurityState() {
DCHECK(enabled_);
+ if (!web_contents()->GetDelegate())
+ return;
SecurityStyleExplanations security_style_explanations;
blink::WebSecurityStyle security_style =
@@ -206,7 +208,7 @@ bool SecurityHandler::NotifyCertificateError(int cert_error,
CertErrorCallback handler) {
if (cert_error_override_mode_ == CertErrorOverrideMode::kIgnoreAll) {
if (handler)
- handler.Run(content::CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE);
+ std::move(handler).Run(content::CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE);
return true;
}
@@ -222,7 +224,7 @@ bool SecurityHandler::NotifyCertificateError(int cert_error,
return false;
}
- cert_error_callbacks_[last_cert_error_id_] = handler;
+ cert_error_callbacks_[last_cert_error_id_] = std::move(handler);
return true;
}
diff --git a/chromium/content/browser/devtools/protocol/service_worker_handler.cc b/chromium/content/browser/devtools/protocol/service_worker_handler.cc
index 5501f6ad645..5449b409717 100644
--- a/chromium/content/browser/devtools/protocol/service_worker_handler.cc
+++ b/chromium/content/browser/devtools/protocol/service_worker_handler.cc
@@ -29,8 +29,8 @@
#include "content/public/browser/web_contents.h"
#include "content/public/common/push_event_payload.h"
#include "content/public/common/push_messaging_status.mojom.h"
-#include "third_party/WebKit/public/mojom/service_worker/service_worker_object.mojom.h"
-#include "third_party/WebKit/public/mojom/service_worker/service_worker_provider_type.mojom.h"
+#include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h"
+#include "third_party/blink/public/mojom/service_worker/service_worker_provider_type.mojom.h"
#include "url/gurl.h"
namespace content {
@@ -213,8 +213,7 @@ Response ServiceWorkerHandler::Unregister(const std::string& scope_url) {
return CreateDomainNotEnabledErrorResponse();
if (!context_)
return CreateContextErrorResponse();
- context_->UnregisterServiceWorker(GURL(scope_url),
- base::DoNothing::Repeatedly<bool>());
+ context_->UnregisterServiceWorker(GURL(scope_url), base::DoNothing());
return Response::OK();
}
@@ -223,8 +222,7 @@ Response ServiceWorkerHandler::StartWorker(const std::string& scope_url) {
return CreateDomainNotEnabledErrorResponse();
if (!context_)
return CreateContextErrorResponse();
- context_->StartServiceWorker(
- GURL(scope_url), base::DoNothing::Repeatedly<ServiceWorkerStatusCode>());
+ context_->StartServiceWorker(GURL(scope_url), base::DoNothing());
return Response::OK();
}
diff --git a/chromium/content/browser/devtools/protocol/storage_handler.cc b/chromium/content/browser/devtools/protocol/storage_handler.cc
index 2c621aa87f0..ad5bb6d37ed 100644
--- a/chromium/content/browser/devtools/protocol/storage_handler.cc
+++ b/chromium/content/browser/devtools/protocol/storage_handler.cc
@@ -12,11 +12,12 @@
#include "base/strings/string_split.h"
#include "content/browser/cache_storage/cache_storage_context_impl.h"
#include "content/browser/indexed_db/indexed_db_context_impl.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/storage_partition.h"
#include "storage/browser/quota/quota_client.h"
#include "storage/browser/quota/quota_manager.h"
-#include "third_party/WebKit/public/mojom/quota/quota_types.mojom.h"
+#include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -88,8 +89,7 @@ void GetUsageAndQuotaOnIOThread(
DCHECK_CURRENTLY_ON(BrowserThread::IO);
manager->GetUsageAndQuotaWithBreakdown(
url, blink::mojom::StorageType::kTemporary,
- base::Bind(&GotUsageAndQuotaDataCallback,
- base::Passed(std::move(callback))));
+ base::BindOnce(&GotUsageAndQuotaDataCallback, std::move(callback)));
}
} // namespace
diff --git a/chromium/content/browser/devtools/protocol/system_info_handler.cc b/chromium/content/browser/devtools/protocol/system_info_handler.cc
index 5372bd781ab..3a90a35db77 100644
--- a/chromium/content/browser/devtools/protocol/system_info_handler.cc
+++ b/chromium/content/browser/devtools/protocol/system_info_handler.cc
@@ -10,7 +10,6 @@
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "content/browser/gpu/compositor_util.h"
diff --git a/chromium/content/browser/devtools/protocol/target_auto_attacher.cc b/chromium/content/browser/devtools/protocol/target_auto_attacher.cc
index b460c7fa321..3d4b128b294 100644
--- a/chromium/content/browser/devtools/protocol/target_auto_attacher.cc
+++ b/chromium/content/browser/devtools/protocol/target_auto_attacher.cc
@@ -170,7 +170,10 @@ DevToolsAgentHost* TargetAutoAttacher::AutoAttachToFrame(
DCHECK(old_cross_process);
auto it = auto_attached_hosts_.find(agent_host);
- DCHECK(it != auto_attached_hosts_.end());
+ // This should not happen in theory, but error pages are sometimes not
+ // picked up. See https://crbug.com/836511 and https://crbug.com/817881.
+ if (it == auto_attached_hosts_.end())
+ return nullptr;
auto_attached_hosts_.erase(it);
detach_callback_.Run(agent_host.get());
return nullptr;
diff --git a/chromium/content/browser/devtools/protocol/tethering_handler.cc b/chromium/content/browser/devtools/protocol/tethering_handler.cc
index 494aea4d93b..ce6738651b2 100644
--- a/chromium/content/browser/devtools/protocol/tethering_handler.cc
+++ b/chromium/content/browser/devtools/protocol/tethering_handler.cc
@@ -6,7 +6,6 @@
#include <map>
-#include "base/memory/ptr_util.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/io_buffer.h"
#include "net/base/ip_address.h"
@@ -295,7 +294,7 @@ void TetheringHandler::TetheringImpl::Bind(
BoundSocket::AcceptedCallback accepted = base::Bind(
&TetheringHandler::TetheringImpl::Accepted, base::Unretained(this));
std::unique_ptr<BoundSocket> bound_socket =
- std::make_unique<BoundSocket>(accepted, socket_callback_);
+ std::make_unique<BoundSocket>(std::move(accepted), socket_callback_);
if (!bound_socket->Listen(port)) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
diff --git a/chromium/content/browser/devtools/protocol/tracing_handler.cc b/chromium/content/browser/devtools/protocol/tracing_handler.cc
index e94eb77facf..ea314dff3c0 100644
--- a/chromium/content/browser/devtools/protocol/tracing_handler.cc
+++ b/chromium/content/browser/devtools/protocol/tracing_handler.cc
@@ -25,13 +25,19 @@
#include "base/trace_event/tracing_agent.h"
#include "components/tracing/common/trace_config_file.h"
#include "components/viz/common/features.h"
-#include "content/browser/devtools/devtools_frame_trace_recorder_for_viz.h"
+#include "content/browser/devtools/devtools_frame_trace_recorder.h"
#include "content/browser/devtools/devtools_io_context.h"
#include "content/browser/devtools/devtools_session.h"
+#include "content/browser/devtools/devtools_traceable_screenshot.h"
+#include "content/browser/devtools/devtools_video_consumer.h"
+#include "content/browser/frame_host/frame_tree.h"
+#include "content/browser/frame_host/frame_tree_node.h"
+#include "content/browser/frame_host/navigation_handle_impl.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/tracing/tracing_controller_impl.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/common/content_features.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
#include "services/tracing/public/mojom/constants.mojom.h"
@@ -44,6 +50,17 @@ const double kMinimumReportingInterval = 250.0;
const char kRecordModeParam[] = "record_mode";
+// Settings for |video_consumer_|.
+// Tracing requires a 10ms minimum capture period.
+constexpr base::TimeDelta kMinCapturePeriod =
+ base::TimeDelta::FromMilliseconds(10);
+
+// Frames need to be at least 1x1, otherwise nothing would be captured.
+constexpr gfx::Size kMinFrameSize = gfx::Size(1, 1);
+
+// Frames do not need to be greater than 500x500 for tracing.
+constexpr gfx::Size kMaxFrameSize = gfx::Size(500, 500);
+
// Convert from camel case to separator + lowercase.
std::string ConvertFromCamelCase(const std::string& in_str, char separator) {
std::string out_str;
@@ -143,22 +160,66 @@ class DevToolsStreamEndpoint : public TracingController::TraceDataEndpoint {
base::WeakPtr<TracingHandler> tracing_handler_;
};
+std::string GetProcessHostHex(RenderProcessHost* host) {
+ return base::StringPrintf("0x%" PRIxPTR, reinterpret_cast<uintptr_t>(host));
+}
+
+void SendProcessReadyInBrowserEvent(const base::UnguessableToken& frame_token,
+ RenderProcessHost* host) {
+ auto data = std::make_unique<base::trace_event::TracedValue>();
+ data->SetString("frame", frame_token.ToString());
+ data->SetString("processPseudoId", GetProcessHostHex(host));
+ data->SetInteger("processId",
+ static_cast<int>(base::GetProcId(host->GetHandle())));
+ TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
+ "ProcessReadyInBrowser", TRACE_EVENT_SCOPE_THREAD,
+ "data", std::move(data));
+}
+
+void FillFrameData(base::trace_event::TracedValue* data,
+ FrameTreeNode* node,
+ RenderFrameHostImpl* frame_host,
+ const GURL& url) {
+ url::Replacements<char> strip_fragment;
+ strip_fragment.ClearRef();
+ data->SetString("frame", node->devtools_frame_token().ToString());
+ data->SetString("url", url.ReplaceComponents(strip_fragment).spec());
+ data->SetString("name", node->frame_name());
+ if (node->parent())
+ data->SetString("parent",
+ node->parent()->devtools_frame_token().ToString());
+ if (frame_host) {
+ RenderProcessHost* process_host = frame_host->GetProcess();
+ base::ProcessId process_id = base::GetProcId(process_host->GetHandle());
+ if (process_id == base::kNullProcessId) {
+ data->SetString("processPseudoId", GetProcessHostHex(process_host));
+ frame_host->GetProcess()->PostTaskWhenProcessIsReady(
+ base::BindOnce(&SendProcessReadyInBrowserEvent,
+ node->devtools_frame_token(), process_host));
+ } else {
+ // Cast process id to int to be compatible with tracing.
+ data->SetInteger("processId", static_cast<int>(process_id));
+ }
+ }
+}
+
} // namespace
-TracingHandler::TracingHandler(TracingHandler::Target target,
- int frame_tree_node_id,
+TracingHandler::TracingHandler(FrameTreeNode* frame_tree_node_,
DevToolsIOContext* io_context)
: DevToolsDomainHandler(Tracing::Metainfo::domainName),
- target_(target),
io_context_(io_context),
- frame_tree_node_id_(frame_tree_node_id),
+ frame_tree_node_(frame_tree_node_),
did_initiate_recording_(false),
return_as_stream_(false),
gzip_compression_(false),
weak_factory_(this) {
- if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor)) {
- frame_trace_recorder_ =
- std::make_unique<DevToolsFrameTraceRecorderForViz>();
+ if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor) ||
+ base::FeatureList::IsEnabled(
+ features::kUseVideoCaptureApiForDevToolsSnapshots)) {
+ video_consumer_ =
+ std::make_unique<DevToolsVideoConsumer>(base::BindRepeating(
+ &TracingHandler::OnFrameFromVideoConsumer, base::Unretained(this)));
}
}
@@ -174,9 +235,9 @@ std::vector<TracingHandler*> TracingHandler::ForAgentHost(
void TracingHandler::SetRenderer(int process_host_id,
RenderFrameHostImpl* frame_host) {
- if (!frame_trace_recorder_ || !frame_host)
+ if (!video_consumer_ || !frame_host)
return;
- frame_trace_recorder_->SetFrameSinkId(
+ video_consumer_->SetFrameSinkId(
frame_host->GetRenderWidgetHost()->GetFrameSinkId());
}
@@ -340,7 +401,7 @@ void TracingHandler::Start(Maybe<std::string> categories,
// If inspected target is a render process Tracing.start will be handled by
// tracing agent in the renderer.
- if (target_ == Renderer)
+ if (frame_tree_node_)
callback->fallThrough();
TracingController::GetInstance()->StartTracing(
@@ -377,7 +438,7 @@ void TracingHandler::End(std::unique_ptr<EndCallback> callback) {
}
// If inspected target is a render process Tracing.end will be handled by
// tracing agent in the renderer.
- if (target_ == Renderer)
+ if (frame_tree_node_)
callback->fallThrough();
else
callback->sendSuccess();
@@ -393,17 +454,21 @@ void TracingHandler::GetCategories(
void TracingHandler::OnRecordingEnabled(
std::unique_ptr<StartCallback> callback) {
- TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
- "TracingStartedInBrowser", TRACE_EVENT_SCOPE_THREAD,
- "frameTreeNodeId", frame_tree_node_id_);
- if (target_ != Renderer)
+ EmitFrameTree();
+
+ if (!frame_tree_node_)
callback->sendSuccess();
bool screenshot_enabled;
TRACE_EVENT_CATEGORY_GROUP_ENABLED(
TRACE_DISABLED_BY_DEFAULT("devtools.screenshot"), &screenshot_enabled);
- if (frame_trace_recorder_ && screenshot_enabled)
- frame_trace_recorder_->StartCapture();
+ if (video_consumer_ && screenshot_enabled) {
+ // Reset number of screenshots received, each time tracing begins.
+ number_of_screenshots_from_video_consumer_ = 0;
+ video_consumer_->SetMinCapturePeriod(kMinCapturePeriod);
+ video_consumer_->SetMinAndMaxFrameSize(kMinFrameSize, kMaxFrameSize);
+ video_consumer_->StartCapture();
+ }
}
void TracingHandler::OnBufferUsage(float percent_full,
@@ -437,7 +502,7 @@ void TracingHandler::RequestMemoryDump(
->RequestGlobalDumpAndAppendToTrace(
base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED,
base::trace_event::MemoryDumpLevelOfDetail::DETAILED,
- on_memory_dump_finished);
+ std::move(on_memory_dump_finished));
}
void TracingHandler::OnMemoryDumpFinished(
@@ -447,6 +512,27 @@ void TracingHandler::OnMemoryDumpFinished(
callback->sendSuccess(base::StringPrintf("0x%" PRIx64, dump_id), success);
}
+void TracingHandler::OnFrameFromVideoConsumer(
+ scoped_refptr<media::VideoFrame> frame) {
+ const SkBitmap skbitmap = DevToolsVideoConsumer::GetSkBitmapFromFrame(frame);
+
+ base::TimeTicks reference_time;
+ const bool had_reference_time = frame->metadata()->GetTimeTicks(
+ media::VideoFrameMetadata::REFERENCE_TIME, &reference_time);
+ DCHECK(had_reference_time);
+
+ TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID_AND_TIMESTAMP(
+ TRACE_DISABLED_BY_DEFAULT("devtools.screenshot"), "Screenshot", 1,
+ reference_time, std::make_unique<DevToolsTraceableScreenshot>(skbitmap));
+
+ ++number_of_screenshots_from_video_consumer_;
+ DCHECK(video_consumer_);
+ if (number_of_screenshots_from_video_consumer_ >=
+ DevToolsFrameTraceRecorder::kMaximumNumberOfScreenshots) {
+ video_consumer_->StopCapture();
+ }
+}
+
Response TracingHandler::RecordClockSyncMarker(const std::string& sync_id) {
if (!IsTracing())
return Response::Error("Tracing is not started");
@@ -478,17 +564,63 @@ void TracingHandler::StopTracing(
buffer_usage_poll_timer_.reset();
TracingController::GetInstance()->StopTracing(endpoint, agent_label);
did_initiate_recording_ = false;
- if (frame_trace_recorder_)
- frame_trace_recorder_->StopCapture();
+ if (video_consumer_)
+ video_consumer_->StopCapture();
}
bool TracingHandler::IsTracing() const {
return TracingController::GetInstance()->IsTracing();
}
+void TracingHandler::EmitFrameTree() {
+ auto data = std::make_unique<base::trace_event::TracedValue>();
+ if (frame_tree_node_) {
+ data->SetInteger("frameTreeNodeId", frame_tree_node_->frame_tree_node_id());
+ data->SetBoolean("persistentIds", true);
+ data->BeginArray("frames");
+ FrameTree::NodeRange subtree =
+ frame_tree_node_->frame_tree()->SubtreeNodes(frame_tree_node_);
+ for (FrameTreeNode* node : subtree) {
+ data->BeginDictionary();
+ FillFrameData(data.get(), node, node->current_frame_host(),
+ node->current_url());
+ data->EndDictionary();
+ }
+ data->EndArray();
+ }
+ TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
+ "TracingStartedInBrowser", TRACE_EVENT_SCOPE_THREAD,
+ "data", std::move(data));
+}
+
+void TracingHandler::ReadyToCommitNavigation(
+ NavigationHandleImpl* navigation_handle) {
+ if (!did_initiate_recording_)
+ return;
+ auto data = std::make_unique<base::trace_event::TracedValue>();
+ FillFrameData(data.get(), navigation_handle->frame_tree_node(),
+ navigation_handle->GetRenderFrameHost(),
+ navigation_handle->GetURL());
+ TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
+ "FrameCommittedInBrowser", TRACE_EVENT_SCOPE_THREAD,
+ "data", std::move(data));
+}
+
+void TracingHandler::FrameDeleted(RenderFrameHostImpl* frame_host) {
+ if (!did_initiate_recording_)
+ return;
+ auto data = std::make_unique<base::trace_event::TracedValue>();
+ data->SetString(
+ "frame",
+ frame_host->frame_tree_node()->devtools_frame_token().ToString());
+ TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
+ "FrameDeletedInBrowser", TRACE_EVENT_SCOPE_THREAD,
+ "data", std::move(data));
+}
+
+// static
bool TracingHandler::IsStartupTracingActive() {
- return ::tracing::TraceConfigFile::GetInstance()->IsEnabled() &&
- TracingController::GetInstance()->IsTracing();
+ return ::tracing::TraceConfigFile::GetInstance()->IsEnabled();
}
// static
diff --git a/chromium/content/browser/devtools/protocol/tracing_handler.h b/chromium/content/browser/devtools/protocol/tracing_handler.h
index 8515e3a3dfa..7f21754cc10 100644
--- a/chromium/content/browser/devtools/protocol/tracing_handler.h
+++ b/chromium/content/browser/devtools/protocol/tracing_handler.h
@@ -26,19 +26,23 @@ namespace base {
class Timer;
}
+namespace media {
+class VideoFrame;
+}
+
namespace content {
class DevToolsAgentHostImpl;
-class DevToolsFrameTraceRecorderForViz;
+class DevToolsVideoConsumer;
class DevToolsIOContext;
+class FrameTreeNode;
+class NavigationHandleImpl;
namespace protocol {
class TracingHandler : public DevToolsDomainHandler, public Tracing::Backend {
public:
- enum Target { Browser, Renderer };
- CONTENT_EXPORT TracingHandler(Target target,
- int frame_tree_node_id,
+ CONTENT_EXPORT TracingHandler(FrameTreeNode* frame_tree_node,
DevToolsIOContext* io_context);
CONTENT_EXPORT ~TracingHandler() override;
@@ -69,6 +73,8 @@ class TracingHandler : public DevToolsDomainHandler, public Tracing::Backend {
Response RecordClockSyncMarker(const std::string& sync_id) override;
bool did_initiate_recording() { return did_initiate_recording_; }
+ void ReadyToCommitNavigation(NavigationHandleImpl* navigation_handle);
+ void FrameDeleted(RenderFrameHostImpl* frame_host);
private:
friend class TracingHandlerTest;
@@ -90,7 +96,7 @@ class TracingHandler : public DevToolsDomainHandler, public Tracing::Backend {
void OnMemoryDumpFinished(std::unique_ptr<RequestMemoryDumpCallback> callback,
bool success,
uint64_t dump_id);
-
+ void OnFrameFromVideoConsumer(scoped_refptr<media::VideoFrame> frame);
// Assuming that the input is a potentially incomplete string representation
// of a comma separated list of JSON objects, return the longest prefix that
// is a valid list and store the rest to be used in subsequent calls.
@@ -102,22 +108,23 @@ class TracingHandler : public DevToolsDomainHandler, public Tracing::Backend {
const scoped_refptr<TracingController::TraceDataEndpoint>& endpoint,
const std::string& agent_label);
bool IsTracing() const;
+ void EmitFrameTree();
static bool IsStartupTracingActive();
CONTENT_EXPORT static base::trace_event::TraceConfig
GetTraceConfigFromDevToolsConfig(
const base::DictionaryValue& devtools_config);
std::unique_ptr<base::Timer> buffer_usage_poll_timer_;
- Target target_;
std::unique_ptr<Tracing::Frontend> frontend_;
DevToolsIOContext* io_context_;
- int frame_tree_node_id_;
+ FrameTreeNode* frame_tree_node_;
bool did_initiate_recording_;
bool return_as_stream_;
bool gzip_compression_;
TraceDataBufferState trace_data_buffer_state_;
- std::unique_ptr<DevToolsFrameTraceRecorderForViz> frame_trace_recorder_;
+ std::unique_ptr<DevToolsVideoConsumer> video_consumer_;
+ int number_of_screenshots_from_video_consumer_ = 0;
base::WeakPtrFactory<TracingHandler> weak_factory_;
FRIEND_TEST_ALL_PREFIXES(TracingHandlerTest,
diff --git a/chromium/content/browser/devtools/protocol/tracing_handler_unittest.cc b/chromium/content/browser/devtools/protocol/tracing_handler_unittest.cc
index 5af1a8d65d4..a392742902a 100644
--- a/chromium/content/browser/devtools/protocol/tracing_handler_unittest.cc
+++ b/chromium/content/browser/devtools/protocol/tracing_handler_unittest.cc
@@ -72,8 +72,7 @@ const char kCustomTraceConfigStringDevToolsStyle[] =
class TracingHandlerTest : public testing::Test {
public:
void SetUp() override {
- tracing_handler_.reset(
- new TracingHandler(TracingHandler::Browser, 0, nullptr));
+ tracing_handler_.reset(new TracingHandler(nullptr, nullptr));
}
void TearDown() override { tracing_handler_.reset(); }
diff --git a/chromium/content/browser/devtools/protocol_config.json b/chromium/content/browser/devtools/protocol_config.json
index 4e9d341cc03..f40789fe6f4 100644
--- a/chromium/content/browser/devtools/protocol_config.json
+++ b/chromium/content/browser/devtools/protocol_config.json
@@ -11,7 +11,7 @@
"options": [
{
"domain": "Browser",
- "include": ["getVersion", "getHistograms", "getHistogram", "getCommandLine"]
+ "include": ["getVersion", "getHistograms", "getHistogram", "getBrowserCommandLine"]
},
{
"domain": "DOM",
diff --git a/chromium/content/browser/devtools/render_frame_devtools_agent_host.cc b/chromium/content/browser/devtools/render_frame_devtools_agent_host.cc
index cdeca684d4f..f6977596a09 100644
--- a/chromium/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/chromium/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -12,6 +12,7 @@
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "components/viz/common/features.h"
#include "content/browser/bad_message.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/devtools/devtools_frame_trace_recorder.h"
@@ -42,17 +43,19 @@
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/render_widget_host_iterator.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/browser_side_navigation_policy.h"
+#include "content/public/common/content_features.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
#include "net/base/load_flags.h"
#include "net/http/http_request_headers.h"
#include "services/network/public/cpp/features.h"
-#include "third_party/WebKit/public/common/associated_interfaces/associated_interface_provider.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#if defined(OS_ANDROID)
#include "content/public/browser/render_widget_host_view.h"
@@ -272,6 +275,7 @@ void RenderFrameDevToolsAgentHost::ApplyOverrides(
net::HttpRequestHeaders headers;
headers.AddHeadersFromString(begin_params->headers);
for (auto* network : protocol::NetworkHandler::ForAgentHost(agent_host)) {
+ // TODO(caseq): consider chaining intercepting proxies from multiple agents.
if (!network->enabled())
continue;
*report_raw_headers = true;
@@ -289,6 +293,27 @@ void RenderFrameDevToolsAgentHost::ApplyOverrides(
}
// static
+bool RenderFrameDevToolsAgentHost::WillCreateURLLoaderFactory(
+ RenderFrameHostImpl* rfh,
+ bool is_navigation,
+ network::mojom::URLLoaderFactoryRequest* target_factory_request) {
+ FrameTreeNode* frame_tree_node = rfh->frame_tree_node();
+ base::UnguessableToken frame_token = frame_tree_node->devtools_frame_token();
+ frame_tree_node = GetFrameTreeNodeAncestor(frame_tree_node);
+ RenderFrameDevToolsAgentHost* agent_host = FindAgentHost(frame_tree_node);
+ if (!agent_host)
+ return false;
+ int process_id = is_navigation ? 0 : rfh->GetProcess()->GetID();
+ for (auto* network : protocol::NetworkHandler::ForAgentHost(agent_host)) {
+ if (network->MaybeCreateProxyForInterception(frame_token, process_id,
+ target_factory_request)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// static
void RenderFrameDevToolsAgentHost::OnNavigationRequestWillBeSent(
const NavigationRequest& navigation_request) {
DispatchToAgents(navigation_request.frame_tree_node(),
@@ -342,7 +367,9 @@ WebContents* RenderFrameDevToolsAgentHost::GetWebContents() {
return web_contents();
}
-void RenderFrameDevToolsAgentHost::AttachSession(DevToolsSession* session) {
+bool RenderFrameDevToolsAgentHost::AttachSession(DevToolsSession* session) {
+ if (session->restricted() && !IsFrameHostAllowedForRestrictedSessions())
+ return false;
session->SetRenderer(frame_host_ ? frame_host_->GetProcess()->GetID()
: ChildProcessHost::kInvalidUniqueID,
frame_host_);
@@ -361,26 +388,34 @@ void RenderFrameDevToolsAgentHost::AttachSession(DevToolsSession* session) {
session->AddHandler(base::WrapUnique(new protocol::SchemaHandler()));
session->AddHandler(base::WrapUnique(new protocol::ServiceWorkerHandler()));
session->AddHandler(base::WrapUnique(new protocol::StorageHandler()));
- session->AddHandler(
- base::WrapUnique(new protocol::TargetHandler(false /* browser_only */)));
- session->AddHandler(base::WrapUnique(new protocol::TracingHandler(
- protocol::TracingHandler::Renderer,
- frame_tree_node_ ? frame_tree_node_->frame_tree_node_id() : 0,
- GetIOContext())));
+ if (!session->restricted()) {
+ session->AddHandler(base::WrapUnique(
+ new protocol::TargetHandler(false /* browser_only */)));
+ }
session->AddHandler(
base::WrapUnique(new protocol::PageHandler(emulation_handler)));
session->AddHandler(base::WrapUnique(new protocol::SecurityHandler()));
+ if (!frame_tree_node_ || !frame_tree_node_->parent()) {
+ session->AddHandler(base::WrapUnique(
+ new protocol::TracingHandler(frame_tree_node_, GetIOContext())));
+ }
if (EnsureAgent())
session->AttachToAgent(agent_ptr_);
if (sessions().size() == 1) {
- frame_trace_recorder_.reset(new DevToolsFrameTraceRecorder());
+ // Taking screenshots using the video capture API is done in TracingHandler.
+ if (!base::FeatureList::IsEnabled(features::kVizDisplayCompositor) &&
+ !base::FeatureList::IsEnabled(
+ features::kUseVideoCaptureApiForDevToolsSnapshots)) {
+ frame_trace_recorder_.reset(new DevToolsFrameTraceRecorder());
+ }
GrantPolicy();
#if defined(OS_ANDROID)
GetWakeLock()->RequestWakeLock();
#endif
}
+ return true;
}
void RenderFrameDevToolsAgentHost::DetachSession(DevToolsSession* session) {
@@ -431,6 +466,9 @@ void RenderFrameDevToolsAgentHost::ReadyToCommitNavigation(
NavigationHandle* navigation_handle) {
NavigationHandleImpl* handle =
static_cast<NavigationHandleImpl*>(navigation_handle);
+ for (auto* tracing : protocol::TracingHandler::ForAgentHost(this))
+ tracing->ReadyToCommitNavigation(handle);
+
if (handle->frame_tree_node() != frame_tree_node_) {
if (ShouldForceCreation() && handle->GetRenderFrameHost() &&
handle->GetRenderFrameHost()->IsCrossProcessSubframe()) {
@@ -487,13 +525,19 @@ void RenderFrameDevToolsAgentHost::UpdateFrameHost(
if (IsAttached())
RevokePolicy();
+
frame_host_ = frame_host;
agent_ptr_.reset();
+
+ if (!IsFrameHostAllowedForRestrictedSessions())
+ ForceDetachRestrictedSessions();
+
if (!render_frame_alive_) {
render_frame_alive_ = true;
for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this))
inspector->TargetReloadedAfterCrash();
}
+
if (IsAttached()) {
GrantPolicy();
for (DevToolsSession* session : sessions()) {
@@ -570,9 +614,12 @@ void RenderFrameDevToolsAgentHost::RenderFrameHostChanged(
}
void RenderFrameDevToolsAgentHost::FrameDeleted(RenderFrameHost* rfh) {
- if (static_cast<RenderFrameHostImpl*>(rfh)->frame_tree_node() ==
- frame_tree_node_) {
- DestroyOnRenderFrameGone(); // |this| may be deleted at this point.
+ RenderFrameHostImpl* host = static_cast<RenderFrameHostImpl*>(rfh);
+ for (auto* tracing : protocol::TracingHandler::ForAgentHost(this))
+ tracing->FrameDeleted(host);
+ if (host->frame_tree_node() == frame_tree_node_) {
+ DestroyOnRenderFrameGone();
+ // |this| may be deleted at this point.
}
}
@@ -587,7 +634,7 @@ void RenderFrameDevToolsAgentHost::DestroyOnRenderFrameGone() {
scoped_refptr<RenderFrameDevToolsAgentHost> protect(this);
if (IsAttached())
RevokePolicy();
- ForceDetachAllClients();
+ ForceDetachAllSessions();
frame_host_ = nullptr;
agent_ptr_.reset();
SetFrameTreeNode(nullptr);
@@ -662,8 +709,6 @@ void RenderFrameDevToolsAgentHost::DidReceiveCompositorFrame() {
->last_frame_metadata();
for (auto* page : protocol::PageHandler::ForAgentHost(this))
page->OnSwapCompositorFrame(metadata.Clone());
- for (auto* input : protocol::InputHandler::ForAgentHost(this))
- input->OnSwapCompositorFrame(metadata);
if (!frame_trace_recorder_)
return;
@@ -674,6 +719,12 @@ void RenderFrameDevToolsAgentHost::DidReceiveCompositorFrame() {
frame_trace_recorder_->OnSwapCompositorFrame(frame_host_, metadata);
}
+void RenderFrameDevToolsAgentHost::OnPageScaleFactorChanged(
+ float page_scale_factor) {
+ for (auto* input : protocol::InputHandler::ForAgentHost(this))
+ input->OnPageScaleFactorChanged(page_scale_factor);
+}
+
void RenderFrameDevToolsAgentHost::DisconnectWebContents() {
navigation_handles_.clear();
SetFrameTreeNode(nullptr);
@@ -822,8 +873,6 @@ void RenderFrameDevToolsAgentHost::SynchronousSwapCompositorFrame(
viz::CompositorFrameMetadata frame_metadata) {
for (auto* page : protocol::PageHandler::ForAgentHost(this))
page->OnSynchronousSwapCompositorFrame(frame_metadata.Clone());
- for (auto* input : protocol::InputHandler::ForAgentHost(this))
- input->OnSwapCompositorFrame(frame_metadata);
if (!frame_trace_recorder_)
return;
@@ -848,4 +897,9 @@ bool RenderFrameDevToolsAgentHost::IsChildFrame() {
return frame_tree_node_ && frame_tree_node_->parent();
}
+bool RenderFrameDevToolsAgentHost::IsFrameHostAllowedForRestrictedSessions() {
+ return !frame_host_ ||
+ (!frame_host_->web_ui() && !frame_host_->pending_web_ui());
+}
+
} // namespace content
diff --git a/chromium/content/browser/devtools/render_frame_devtools_agent_host.h b/chromium/content/browser/devtools/render_frame_devtools_agent_host.h
index 8877e6c3f18..afd61919b40 100644
--- a/chromium/content/browser/devtools/render_frame_devtools_agent_host.h
+++ b/chromium/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -18,7 +18,8 @@
#include "content/common/navigation_params.mojom.h"
#include "content/public/browser/web_contents_observer.h"
#include "net/base/net_errors.h"
-#include "third_party/WebKit/public/web/devtools_agent.mojom.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "third_party/blink/public/web/devtools_agent.mojom.h"
#if defined(OS_ANDROID)
#include "services/device/public/mojom/wake_lock.mojom.h"
@@ -69,6 +70,11 @@ class CONTENT_EXPORT RenderFrameDevToolsAgentHost
static void ApplyOverrides(FrameTreeNode* frame_tree_node,
mojom::BeginNavigationParams* begin_params,
bool* report_raw_headers);
+ static bool WillCreateURLLoaderFactory(
+ RenderFrameHostImpl* rfh,
+ bool is_navigation,
+ network::mojom::URLLoaderFactoryRequest* loader_factory_request);
+
static void OnNavigationRequestWillBeSent(
const NavigationRequest& navigation_request);
static void OnNavigationResponseReceived(
@@ -114,7 +120,7 @@ class CONTENT_EXPORT RenderFrameDevToolsAgentHost
~RenderFrameDevToolsAgentHost() override;
// DevToolsAgentHostImpl overrides.
- void AttachSession(DevToolsSession* session) override;
+ bool AttachSession(DevToolsSession* session) override;
void DetachSession(DevToolsSession* session) override;
void InspectElement(RenderFrameHost* frame_host, int x, int y) override;
void DispatchProtocolMessage(DevToolsSession* session,
@@ -133,8 +139,10 @@ class CONTENT_EXPORT RenderFrameDevToolsAgentHost
void DidDetachInterstitialPage() override;
void OnVisibilityChanged(content::Visibility visibility) override;
void DidReceiveCompositorFrame() override;
+ void OnPageScaleFactorChanged(float page_scale_factor) override;
bool IsChildFrame();
+ bool IsFrameHostAllowedForRestrictedSessions();
void OnSwapCompositorFrame(const IPC::Message& message);
void DestroyOnRenderFrameGone();
diff --git a/chromium/content/browser/devtools/service_worker_devtools_agent_host.cc b/chromium/content/browser/devtools/service_worker_devtools_agent_host.cc
index 71ea6f0d4e7..b4886cc9754 100644
--- a/chromium/content/browser/devtools/service_worker_devtools_agent_host.cc
+++ b/chromium/content/browser/devtools/service_worker_devtools_agent_host.cc
@@ -115,7 +115,7 @@ ServiceWorkerDevToolsAgentHost::~ServiceWorkerDevToolsAgentHost() {
ServiceWorkerDevToolsManager::GetInstance()->AgentHostDestroyed(this);
}
-void ServiceWorkerDevToolsAgentHost::AttachSession(DevToolsSession* session) {
+bool ServiceWorkerDevToolsAgentHost::AttachSession(DevToolsSession* session) {
if (state_ == WORKER_READY) {
if (sessions().size() == 1) {
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
@@ -128,6 +128,7 @@ void ServiceWorkerDevToolsAgentHost::AttachSession(DevToolsSession* session) {
session->AddHandler(base::WrapUnique(new protocol::InspectorHandler()));
session->AddHandler(base::WrapUnique(new protocol::NetworkHandler(GetId())));
session->AddHandler(base::WrapUnique(new protocol::SchemaHandler()));
+ return true;
}
void ServiceWorkerDevToolsAgentHost::DetachSession(DevToolsSession* session) {
diff --git a/chromium/content/browser/devtools/service_worker_devtools_agent_host.h b/chromium/content/browser/devtools/service_worker_devtools_agent_host.h
index 59af14400fa..456e9938e8e 100644
--- a/chromium/content/browser/devtools/service_worker_devtools_agent_host.h
+++ b/chromium/content/browser/devtools/service_worker_devtools_agent_host.h
@@ -14,7 +14,7 @@
#include "base/unguessable_token.h"
#include "content/browser/devtools/devtools_agent_host_impl.h"
#include "content/browser/devtools/service_worker_devtools_manager.h"
-#include "third_party/WebKit/public/web/devtools_agent.mojom.h"
+#include "third_party/blink/public/web/devtools_agent.mojom.h"
namespace content {
@@ -47,7 +47,7 @@ class ServiceWorkerDevToolsAgentHost : public DevToolsAgentHostImpl {
bool Close() override;
// DevToolsAgentHostImpl overrides.
- void AttachSession(DevToolsSession* session) override;
+ bool AttachSession(DevToolsSession* session) override;
void DetachSession(DevToolsSession* session) override;
void DispatchProtocolMessage(DevToolsSession* session,
const std::string& message) override;
diff --git a/chromium/content/browser/devtools/service_worker_devtools_manager.h b/chromium/content/browser/devtools/service_worker_devtools_manager.h
index a660f6a1410..1018d40705a 100644
--- a/chromium/content/browser/devtools/service_worker_devtools_manager.h
+++ b/chromium/content/browser/devtools/service_worker_devtools_manager.h
@@ -16,7 +16,7 @@
#include "base/observer_list.h"
#include "base/unguessable_token.h"
#include "content/common/content_export.h"
-#include "third_party/WebKit/public/web/devtools_agent.mojom.h"
+#include "third_party/blink/public/web/devtools_agent.mojom.h"
#include "url/gurl.h"
namespace network {
diff --git a/chromium/content/browser/devtools/shared_worker_devtools_agent_host.cc b/chromium/content/browser/devtools/shared_worker_devtools_agent_host.cc
index e4e0d316406..485edd42a67 100644
--- a/chromium/content/browser/devtools/shared_worker_devtools_agent_host.cc
+++ b/chromium/content/browser/devtools/shared_worker_devtools_agent_host.cc
@@ -66,13 +66,14 @@ bool SharedWorkerDevToolsAgentHost::Close() {
return true;
}
-void SharedWorkerDevToolsAgentHost::AttachSession(DevToolsSession* session) {
+bool SharedWorkerDevToolsAgentHost::AttachSession(DevToolsSession* session) {
session->AddHandler(std::make_unique<protocol::InspectorHandler>());
session->AddHandler(std::make_unique<protocol::NetworkHandler>(GetId()));
session->AddHandler(std::make_unique<protocol::SchemaHandler>());
session->SetRenderer(worker_host_ ? worker_host_->process_id() : -1, nullptr);
if (state_ == WORKER_READY)
session->AttachToAgent(EnsureAgent());
+ return true;
}
void SharedWorkerDevToolsAgentHost::DetachSession(DevToolsSession* session) {
diff --git a/chromium/content/browser/devtools/shared_worker_devtools_agent_host.h b/chromium/content/browser/devtools/shared_worker_devtools_agent_host.h
index 15c5de57b59..6a1d800795b 100644
--- a/chromium/content/browser/devtools/shared_worker_devtools_agent_host.h
+++ b/chromium/content/browser/devtools/shared_worker_devtools_agent_host.h
@@ -8,7 +8,7 @@
#include "base/macros.h"
#include "base/unguessable_token.h"
#include "content/browser/devtools/devtools_agent_host_impl.h"
-#include "third_party/WebKit/public/web/devtools_agent.mojom.h"
+#include "third_party/blink/public/web/devtools_agent.mojom.h"
namespace content {
@@ -33,7 +33,7 @@ class SharedWorkerDevToolsAgentHost : public DevToolsAgentHostImpl {
bool Close() override;
// DevToolsAgentHostImpl overrides.
- void AttachSession(DevToolsSession* session) override;
+ bool AttachSession(DevToolsSession* session) override;
void DetachSession(DevToolsSession* session) override;
void DispatchProtocolMessage(DevToolsSession* session,
const std::string& message) override;