DevTools: handle Page.reload on the browser side with RenderDocument
- when RenderDocument is on, do not fall through in Page.reload handler; - instead, pass script_to_evaluate_on_load to InspectorPageAgent in new render frame at construction time via AttachDevToolsSession() method; - handle breakpoint unpause and script termination by an out-of-band method of DevToolsSession. - get rid of using InspectorAgentState for storing the script to evaluate on load, as the RenderDocument code path does not require this anymore; - the latter also takes care of a security sensitive race between reload and navigation to a different URL, so PageReloadScriptInjection is going away too. This resolves a race between the page reload initiated by PageHandler::reload() on the browser side and and a round-trip to renderer resulting from fall-through of PageHandler::reload() intended to set script to evaluate on load in the agent state cookie, which occurs with RenderDocument enabled. Bug: 357977710 Change-Id: Ice796b829b56b514d38b787aea826d04d69f3c76 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6261689 Reviewed-by: Philip Pfaffe <pfaffe@chromium.org> Reviewed-by: Nasko Oskov <nasko@chromium.org> Commit-Queue: Andrey Kosyakov <caseq@chromium.org> Reviewed-by: Nate Chapin <japhet@chromium.org> Reviewed-by: Maks Orlovich <morlovich@chromium.org> Reviewed-by: Lucas Radaelli <lucasradaelli@google.com> Cr-Commit-Position: refs/heads/main@{#1424660}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
71e25625ce
commit
98fc1edbcc
content
browser
devtools
services
services/accessibility/features/devtools
os_devtools_agent.ccos_devtools_agent.hos_devtools_session.ccos_devtools_session.hos_devtools_unittest.cc
third_party/blink
@ -197,8 +197,8 @@ void DevToolsSession::AttachToAgent(blink::mojom::DevToolsAgent* agent,
|
||||
receiver_.BindNewEndpointAndPassRemote(),
|
||||
session_.BindNewEndpointAndPassReceiver(),
|
||||
io_session_.BindNewPipeAndPassReceiver(), session_state_cookie_.Clone(),
|
||||
client_->UsesBinaryProtocol(), client_->IsTrusted(), session_id_,
|
||||
IsWaitingForDebuggerOnStart());
|
||||
script_to_evaluate_on_load_, client_->UsesBinaryProtocol(),
|
||||
client_->IsTrusted(), session_id_, IsWaitingForDebuggerOnStart());
|
||||
session_.set_disconnect_handler(base::BindOnce(
|
||||
&DevToolsSession::MojoConnectionDestroyed, base::Unretained(this)));
|
||||
|
||||
@ -206,6 +206,9 @@ void DevToolsSession::AttachToAgent(blink::mojom::DevToolsAgent* agent,
|
||||
if (!session_state_cookie_)
|
||||
session_state_cookie_ = blink::mojom::DevToolsSessionState::New();
|
||||
|
||||
// Only use script_to_evaluate_on_load_ once.
|
||||
script_to_evaluate_on_load_.clear();
|
||||
|
||||
// We're attaching to a new agent while suspended; therefore, messages that
|
||||
// have been sent previously either need to be terminated or re-sent once we
|
||||
// resume, as we will not get any responses from the old agent at this point.
|
||||
@ -482,6 +485,7 @@ void DevToolsSession::ResumeSendingMessagesToAgent() {
|
||||
void DevToolsSession::ClearPendingMessages(bool did_crash) {
|
||||
for (auto it = pending_messages_.begin(); it != pending_messages_.end();) {
|
||||
const PendingMessage& message = *it;
|
||||
// TODO(caseq): remove when non-RenderDocument code paths are gone.
|
||||
if (message.method == "Page.reload") {
|
||||
++it;
|
||||
continue;
|
||||
@ -640,4 +644,9 @@ void DevToolsSession::RemoveObserver(ChildObserver* obs) {
|
||||
child_observers_.RemoveObserver(obs);
|
||||
}
|
||||
|
||||
void DevToolsSession::PrepareForReload(std::string script_to_evaluate_on_load) {
|
||||
script_to_evaluate_on_load_ = std::move(script_to_evaluate_on_load);
|
||||
io_session_->UnpauseAndTerminate();
|
||||
}
|
||||
|
||||
} // namespace content
|
||||
|
@ -129,6 +129,11 @@ class DevToolsSession : public protocol::FrontendChannel,
|
||||
void AddObserver(ChildObserver* obs);
|
||||
void RemoveObserver(ChildObserver* obs);
|
||||
|
||||
base::RepeatingCallback<void(std::string)> MakePrepareForReloadCallback() {
|
||||
return base::BindRepeating(&DevToolsSession::PrepareForReload,
|
||||
base::Unretained(this));
|
||||
}
|
||||
|
||||
private:
|
||||
struct PendingMessage {
|
||||
int call_id;
|
||||
@ -211,6 +216,7 @@ class DevToolsSession : public protocol::FrontendChannel,
|
||||
std::is_same<T, protocol::WebAuthnHandler>>;
|
||||
}
|
||||
void AddHandler(std::unique_ptr<protocol::DevToolsDomainHandler> handler);
|
||||
void PrepareForReload(std::string script_to_evaluate_on_load);
|
||||
|
||||
const raw_ptr<DevToolsAgentHostClient> client_;
|
||||
const raw_ptr<DevToolsSession> root_session_ = nullptr;
|
||||
@ -239,13 +245,13 @@ class DevToolsSession : public protocol::FrontendChannel,
|
||||
// any of the waiting for response messages have been handled.
|
||||
// |session_state_cookie_| is nullptr before first attach.
|
||||
blink::mojom::DevToolsSessionStatePtr session_state_cookie_;
|
||||
std::string script_to_evaluate_on_load_;
|
||||
|
||||
base::flat_map<std::string, raw_ptr<DevToolsSession, CtnExperimental>>
|
||||
child_sessions_;
|
||||
base::OnceClosure runtime_resume_;
|
||||
raw_ptr<DevToolsExternalAgentProxyDelegate> proxy_delegate_ = nullptr;
|
||||
base::ObserverList<ChildObserver, true, false> child_observers_;
|
||||
|
||||
base::WeakPtrFactory<DevToolsSession> weak_factory_{this};
|
||||
};
|
||||
|
||||
|
@ -464,12 +464,14 @@ struct PageHandler::PendingScreenshotRequest {
|
||||
gfx::Size requested_image_size;
|
||||
};
|
||||
|
||||
PageHandler::PageHandler(EmulationHandler* emulation_handler,
|
||||
BrowserHandler* browser_handler,
|
||||
bool allow_unsafe_operations,
|
||||
bool is_trusted,
|
||||
std::optional<url::Origin> navigation_initiator_origin,
|
||||
bool may_read_local_files)
|
||||
PageHandler::PageHandler(
|
||||
EmulationHandler* emulation_handler,
|
||||
BrowserHandler* browser_handler,
|
||||
bool allow_unsafe_operations,
|
||||
bool is_trusted,
|
||||
std::optional<url::Origin> navigation_initiator_origin,
|
||||
bool may_read_local_files,
|
||||
base::RepeatingCallback<void(std::string)> prepare_for_reload_callback)
|
||||
: DevToolsDomainHandler(Page::Metainfo::domainName),
|
||||
allow_unsafe_operations_(allow_unsafe_operations),
|
||||
is_trusted_(is_trusted),
|
||||
@ -484,7 +486,8 @@ PageHandler::PageHandler(EmulationHandler* emulation_handler,
|
||||
frames_in_flight_(0),
|
||||
host_(nullptr),
|
||||
emulation_handler_(emulation_handler),
|
||||
browser_handler_(browser_handler) {
|
||||
browser_handler_(browser_handler),
|
||||
prepare_for_reload_callback_(std::move(prepare_for_reload_callback)) {
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
constexpr auto kScreencastPixelFormat = media::PIXEL_FORMAT_I420;
|
||||
#else
|
||||
@ -696,13 +699,27 @@ void PageHandler::Reload(std::optional<bool> bypassCache,
|
||||
}
|
||||
}
|
||||
|
||||
// It is important to fallback before triggering reload, so that
|
||||
// renderer could prepare beforehand.
|
||||
callback->fallThrough();
|
||||
outermost_main_frame->frame_tree()->controller().Reload(
|
||||
bypassCache.value_or(false) ? ReloadType::BYPASSING_CACHE
|
||||
: ReloadType::NORMAL,
|
||||
false);
|
||||
const auto reload_type = bypassCache.value_or(false)
|
||||
? ReloadType::BYPASSING_CACHE
|
||||
: ReloadType::NORMAL;
|
||||
NavigationController& navigation_controller =
|
||||
outermost_main_frame->frame_tree()->controller();
|
||||
// For RenderDocument, the path is different: we don't fall through to the
|
||||
// renderer and process `scriptToEvaluateOnLoad` in the browser instead.
|
||||
const bool handle_reload_on_browser_side =
|
||||
outermost_main_frame->ShouldChangeRenderFrameHostOnSameSiteNavigation();
|
||||
if (handle_reload_on_browser_side) {
|
||||
have_pending_reload_ = true;
|
||||
pending_script_to_evaluate_on_load_ =
|
||||
script_to_evaluate_on_load.value_or("");
|
||||
navigation_controller.Reload(reload_type, false);
|
||||
callback->sendSuccess();
|
||||
} else {
|
||||
// It is important to fallback before triggering reload, so that
|
||||
// renderer could prepare beforehand.
|
||||
callback->fallThrough();
|
||||
navigation_controller.Reload(reload_type, false);
|
||||
}
|
||||
}
|
||||
|
||||
static network::mojom::ReferrerPolicy ParsePolicyFromString(
|
||||
@ -2295,6 +2312,20 @@ void PageHandler::IsPrerenderingAllowed(bool& is_allowed) {
|
||||
is_allowed &= is_prerendering_allowed_;
|
||||
}
|
||||
|
||||
void PageHandler::ReadyToCommitNavigation(
|
||||
NavigationRequest* navigation_request) {
|
||||
if (navigation_request->GetReloadType() == ReloadType::NONE) {
|
||||
// Disregard pending reload if the navigation being committed is not a
|
||||
// reload.
|
||||
have_pending_reload_ = false;
|
||||
pending_script_to_evaluate_on_load_.clear();
|
||||
} else if (have_pending_reload_) {
|
||||
prepare_for_reload_callback_.Run(
|
||||
std::move(pending_script_to_evaluate_on_load_));
|
||||
have_pending_reload_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
Response PageHandler::SetPrerenderingAllowed(bool is_allowed) {
|
||||
Response response = AssureTopLevelActiveFrame();
|
||||
if (response.IsError()) {
|
||||
|
@ -62,12 +62,14 @@ class PageHandler : public DevToolsDomainHandler,
|
||||
public RenderWidgetHostObserver,
|
||||
public download::DownloadItem::Observer {
|
||||
public:
|
||||
PageHandler(EmulationHandler* emulation_handler,
|
||||
BrowserHandler* browser_handler,
|
||||
bool allow_unsafe_operations,
|
||||
bool is_trusted,
|
||||
std::optional<url::Origin> navigation_initiator_origin,
|
||||
bool may_read_local_files);
|
||||
PageHandler(
|
||||
EmulationHandler* emulation_handler,
|
||||
BrowserHandler* browser_handler,
|
||||
bool allow_unsafe_operations,
|
||||
bool is_trusted,
|
||||
std::optional<url::Origin> navigation_initiator_origin,
|
||||
bool may_read_local_files,
|
||||
base::RepeatingCallback<void(std::string)> prepare_for_reload_callback);
|
||||
|
||||
PageHandler(const PageHandler&) = delete;
|
||||
PageHandler& operator=(const PageHandler&) = delete;
|
||||
@ -113,6 +115,7 @@ class PageHandler : public DevToolsDomainHandler,
|
||||
const BackForwardCacheCanStoreTreeResult* tree_result);
|
||||
|
||||
void IsPrerenderingAllowed(bool& is_allowed);
|
||||
void ReadyToCommitNavigation(NavigationRequest* navigation_request);
|
||||
|
||||
Response Enable(
|
||||
std::optional<bool> enable_file_chooser_opened_event) override;
|
||||
@ -270,6 +273,9 @@ class PageHandler : public DevToolsDomainHandler,
|
||||
pending_downloads_;
|
||||
|
||||
bool is_prerendering_allowed_ = true;
|
||||
base::RepeatingCallback<void(std::string)> prepare_for_reload_callback_;
|
||||
bool have_pending_reload_ = false;
|
||||
std::string pending_script_to_evaluate_on_load_;
|
||||
|
||||
base::WeakPtrFactory<PageHandler> weak_factory_{this};
|
||||
};
|
||||
|
@ -391,7 +391,8 @@ bool RenderFrameDevToolsAgentHost::AttachSession(DevToolsSession* session) {
|
||||
session->GetClient()->AllowUnsafeOperations(),
|
||||
session->GetClient()->IsTrusted(),
|
||||
session->GetClient()->GetNavigationInitiatorOrigin(),
|
||||
session->GetClient()->MayReadLocalFiles());
|
||||
session->GetClient()->MayReadLocalFiles(),
|
||||
session->MakePrepareForReloadCallback());
|
||||
session->CreateAndAddHandler<protocol::SecurityHandler>();
|
||||
if (!frame_tree_node_ || !frame_tree_node_->parent()) {
|
||||
DevToolsSession* root_session = session->GetRootSession();
|
||||
@ -456,8 +457,12 @@ void RenderFrameDevToolsAgentHost::ReadyToCommitNavigation(
|
||||
return;
|
||||
}
|
||||
NavigationRequest* request = NavigationRequest::From(navigation_handle);
|
||||
for (auto* tracing : protocol::TracingHandler::ForAgentHost(this))
|
||||
for (auto* tracing : protocol::TracingHandler::ForAgentHost(this)) {
|
||||
tracing->ReadyToCommitNavigation(request);
|
||||
}
|
||||
for (auto* page : protocol::PageHandler::ForAgentHost(this)) {
|
||||
page->ReadyToCommitNavigation(request);
|
||||
}
|
||||
|
||||
if (request->frame_tree_node() != frame_tree_node_) {
|
||||
if (ShouldForceCreation() && request->GetRenderFrameHost() &&
|
||||
|
@ -68,11 +68,13 @@ void AuctionV8DevToolsAgent::AttachDevToolsSession(
|
||||
session_receiver,
|
||||
mojo::PendingReceiver<blink::mojom::DevToolsSession> io_session_receiver,
|
||||
blink::mojom::DevToolsSessionStatePtr reattach_session_state,
|
||||
const std::string& script_to_evaluate_on_load,
|
||||
bool client_expects_binary_responses,
|
||||
bool client_is_trusted,
|
||||
const std::string& session_id,
|
||||
bool session_waits_for_debugger) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(v8_sequence_checker_);
|
||||
CHECK(script_to_evaluate_on_load.empty()); // This is for frames only so far.
|
||||
int context_group_id = receivers_.current_context();
|
||||
ContextGroupInfo& context_group_info = context_groups_[context_group_id];
|
||||
|
||||
|
@ -104,6 +104,7 @@ class AuctionV8DevToolsAgent : public blink::mojom::DevToolsAgent,
|
||||
session_receiver,
|
||||
mojo::PendingReceiver<blink::mojom::DevToolsSession> io_session_receiver,
|
||||
blink::mojom::DevToolsSessionStatePtr reattach_session_state,
|
||||
const std::string& script_to_evaluate_on_load,
|
||||
bool client_expects_binary_responses,
|
||||
bool client_is_trusted,
|
||||
const std::string& session_id,
|
||||
|
@ -129,6 +129,8 @@ class AuctionV8DevToolsSession::IOSession
|
||||
std::vector<uint8_t>(message.begin(), message.end())));
|
||||
}
|
||||
|
||||
void UnpauseAndTerminate() override { NOTREACHED(); }
|
||||
|
||||
private:
|
||||
IOSession(scoped_refptr<DebugCommandQueue> debug_command_queue,
|
||||
RunDispatch v8_thread_dispatch)
|
||||
@ -255,6 +257,11 @@ void AuctionV8DevToolsSession::DispatchProtocolCommand(
|
||||
}
|
||||
}
|
||||
|
||||
void AuctionV8DevToolsSession::UnpauseAndTerminate() {
|
||||
// This is currently only invoked for frame targets.
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
void AuctionV8DevToolsSession::sendResponse(
|
||||
int call_id,
|
||||
std::unique_ptr<v8_inspector::StringBuffer> message) {
|
||||
|
@ -86,6 +86,7 @@ class AuctionV8DevToolsSession : public blink::mojom::DevToolsSession,
|
||||
void DispatchProtocolCommand(int32_t call_id,
|
||||
const std::string& method,
|
||||
base::span<const uint8_t> message) override;
|
||||
void UnpauseAndTerminate() override;
|
||||
|
||||
// V8Inspector::Channel implementation:
|
||||
void sendResponse(
|
||||
|
@ -51,7 +51,8 @@ TestDevToolsAgentClient::TestDevToolsAgentClient(
|
||||
agent_->AttachDevToolsSession(receiver_.BindNewEndpointAndPassRemote(),
|
||||
session_.BindNewEndpointAndPassReceiver(),
|
||||
io_session_.BindNewPipeAndPassReceiver(),
|
||||
nullptr, use_binary_protocol_,
|
||||
nullptr, /*script_to_evaluate_on_load*/ "",
|
||||
use_binary_protocol_,
|
||||
/*client_is_trusted=*/true, session_id_,
|
||||
/*session_waits_for_debugger=*/false);
|
||||
}
|
||||
|
@ -67,11 +67,13 @@ void OSDevToolsAgent::AttachDevToolsSession(
|
||||
session_receiver,
|
||||
mojo::PendingReceiver<blink::mojom::DevToolsSession> io_session_receiver,
|
||||
blink::mojom::DevToolsSessionStatePtr reattach_session_state,
|
||||
const std::string& script_to_evaluate_on_load,
|
||||
bool client_expects_binary_responses,
|
||||
bool client_is_trusted,
|
||||
const std::string& session_id,
|
||||
bool session_waits_for_debugger) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(v8_sequence_checker_);
|
||||
CHECK(script_to_evaluate_on_load.empty()); // This is for frames only so far.
|
||||
|
||||
auto session_destroyed_callback = base::BindOnce(
|
||||
&OSDevToolsAgent::SessionDestroyed, weak_ptr_factory_.GetWeakPtr());
|
||||
|
@ -53,6 +53,7 @@ class OSDevToolsAgent : public blink::mojom::DevToolsAgent,
|
||||
session_receiver,
|
||||
mojo::PendingReceiver<blink::mojom::DevToolsSession> io_session_receiver,
|
||||
blink::mojom::DevToolsSessionStatePtr reattach_session_state,
|
||||
const std::string& script_to_evaluate_on_load,
|
||||
bool client_expects_binary_responses,
|
||||
bool client_is_trusted,
|
||||
const std::string& session_id,
|
||||
|
@ -80,6 +80,8 @@ class OSDevToolsSession::IOSession : public blink::mojom::DevToolsSession {
|
||||
std::vector<uint8_t>(message.begin(), message.end())));
|
||||
}
|
||||
|
||||
void UnpauseAndTerminate() override { NOTREACHED(); }
|
||||
|
||||
private:
|
||||
IOSession(const scoped_refptr<DebugCommandQueue> debug_command_queue,
|
||||
DispatchCallback v8_thread_dispatch)
|
||||
@ -200,6 +202,10 @@ void OSDevToolsSession::DispatchProtocolCommand(
|
||||
}
|
||||
}
|
||||
|
||||
void OSDevToolsSession::UnpauseAndTerminate() {
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
void OSDevToolsSession::sendResponse(
|
||||
int call_id,
|
||||
std::unique_ptr<v8_inspector::StringBuffer> message) {
|
||||
|
@ -63,6 +63,7 @@ class OSDevToolsSession : public blink::mojom::DevToolsSession,
|
||||
void DispatchProtocolCommand(int32_t call_id,
|
||||
const std::string& method,
|
||||
base::span<const uint8_t> message) override;
|
||||
void UnpauseAndTerminate() override;
|
||||
|
||||
// V8Inspector::Channel
|
||||
void sendResponse(
|
||||
|
@ -270,7 +270,8 @@ class OSDevToolsTest : public testing::Test {
|
||||
fake_session_host_.receiver.BindNewEndpointAndPassRemote(),
|
||||
session_remote_.BindNewEndpointAndPassReceiver(),
|
||||
io_session_remote_.BindNewPipeAndPassReceiver(),
|
||||
std::move(reattach_session_state_), /*client_expects_binary*/ true,
|
||||
std::move(reattach_session_state_), /*script_to_evaluate_on_load=*/"",
|
||||
/*client_expects_binary=*/true,
|
||||
/*client_is_trusted=*/true, /*session_id=*/"session",
|
||||
/*session_waits_for_debugger=*/false);
|
||||
}
|
||||
|
@ -99,6 +99,7 @@ interface DevToolsAgent {
|
||||
pending_associated_receiver<DevToolsSession> session,
|
||||
pending_receiver<DevToolsSession> io_session,
|
||||
DevToolsSessionState? reattach_session_state,
|
||||
string script_to_evaluate_on_load,
|
||||
bool client_expects_binary_responses,
|
||||
bool client_is_trusted,
|
||||
string session_id,
|
||||
@ -167,6 +168,9 @@ interface DevToolsSession {
|
||||
DispatchProtocolCommand(int32 call_id,
|
||||
string method,
|
||||
mojo_base.mojom.ReadOnlyBuffer message);
|
||||
|
||||
// Disables all breakpoints and terminates script currently executing.
|
||||
UnpauseAndTerminate();
|
||||
};
|
||||
|
||||
// A peer of DevToolsSession representing a remote debugging client
|
||||
|
@ -358,7 +358,7 @@ void WebDevToolsAgentImpl::AttachSession(DevToolsSession* session,
|
||||
|
||||
auto* page_agent = session->CreateAndAppend<InspectorPageAgent>(
|
||||
inspected_frames, this, resource_content_loader_.Get(),
|
||||
session->V8Session());
|
||||
session->V8Session(), session->script_to_evaluate_on_load());
|
||||
|
||||
session->CreateAndAppend<InspectorLogAgent>(
|
||||
&inspected_frames->Root()->GetPage()->GetConsoleMessageStorage(),
|
||||
|
@ -149,7 +149,6 @@ blink_core_tests_inspector = [
|
||||
"inspector_ghost_rules_test.cc",
|
||||
"inspector_highlight_test.cc",
|
||||
"inspector_history_test.cc",
|
||||
"inspector_page_agent_unittest.cc",
|
||||
"inspector_preload_agent_unittest.cc",
|
||||
"inspector_media_context_impl_unittest.cc",
|
||||
"inspector_session_state_test.cc",
|
||||
|
@ -118,6 +118,7 @@ class DevToolsAgent::IOAgent : public mojom::blink::DevToolsAgent {
|
||||
main_session,
|
||||
mojo::PendingReceiver<mojom::blink::DevToolsSession> io_session,
|
||||
mojom::blink::DevToolsSessionStatePtr reattach_session_state,
|
||||
const WTF::String& script_to_evaluate_on_load,
|
||||
bool client_expects_binary_responses,
|
||||
bool client_is_trusted,
|
||||
const WTF::String& session_id,
|
||||
@ -128,8 +129,9 @@ class DevToolsAgent::IOAgent : public mojom::blink::DevToolsAgent {
|
||||
&::blink::DevToolsAgent::AttachDevToolsSessionImpl,
|
||||
MakeUnwrappingCrossThreadWeakHandle(agent_), std::move(host),
|
||||
std::move(main_session), std::move(io_session),
|
||||
std::move(reattach_session_state), client_expects_binary_responses,
|
||||
client_is_trusted, session_id, session_waits_for_debugger));
|
||||
std::move(reattach_session_state), script_to_evaluate_on_load,
|
||||
client_expects_binary_responses, client_is_trusted, session_id,
|
||||
session_waits_for_debugger));
|
||||
}
|
||||
|
||||
void InspectElement(const gfx::Point& point) override {
|
||||
@ -257,6 +259,7 @@ void DevToolsAgent::AttachDevToolsSessionImpl(
|
||||
session_receiver,
|
||||
mojo::PendingReceiver<mojom::blink::DevToolsSession> io_session_receiver,
|
||||
mojom::blink::DevToolsSessionStatePtr reattach_session_state,
|
||||
const WTF::String& script_to_evaluate_on_load,
|
||||
bool client_expects_binary_responses,
|
||||
bool client_is_trusted,
|
||||
const WTF::String& session_id,
|
||||
@ -266,8 +269,8 @@ void DevToolsAgent::AttachDevToolsSessionImpl(
|
||||
DevToolsSession* session = MakeGarbageCollected<DevToolsSession>(
|
||||
this, std::move(host), std::move(session_receiver),
|
||||
std::move(io_session_receiver), std::move(reattach_session_state),
|
||||
client_expects_binary_responses, client_is_trusted, session_id,
|
||||
session_waits_for_debugger,
|
||||
script_to_evaluate_on_load, client_expects_binary_responses,
|
||||
client_is_trusted, session_id, session_waits_for_debugger,
|
||||
// crbug.com/333093232: Mojo ignores the task runner passed to Bind for
|
||||
// channel associated interfaces but uses it for disconnect. Since
|
||||
// devtools relies on a disconnect handler for detaching and is sensitive
|
||||
@ -293,6 +296,7 @@ void DevToolsAgent::AttachDevToolsSession(
|
||||
session_receiver,
|
||||
mojo::PendingReceiver<mojom::blink::DevToolsSession> io_session_receiver,
|
||||
mojom::blink::DevToolsSessionStatePtr reattach_session_state,
|
||||
const WTF::String& script_to_evaluate_on_load,
|
||||
bool client_expects_binary_responses,
|
||||
bool client_is_trusted,
|
||||
const WTF::String& session_id,
|
||||
@ -304,14 +308,15 @@ void DevToolsAgent::AttachDevToolsSession(
|
||||
AttachDevToolsSessionImpl(
|
||||
std::move(host), std::move(session_receiver),
|
||||
std::move(io_session_receiver), std::move(reattach_session_state),
|
||||
client_expects_binary_responses, client_is_trusted, session_id,
|
||||
script_to_evaluate_on_load, client_expects_binary_responses,
|
||||
client_is_trusted, session_id,
|
||||
/* session_waits_for_debugger */ false);
|
||||
} else {
|
||||
io_agent_->AttachDevToolsSession(
|
||||
std::move(host), std::move(session_receiver),
|
||||
std::move(io_session_receiver), std::move(reattach_session_state),
|
||||
client_expects_binary_responses, client_is_trusted, session_id,
|
||||
session_waits_for_debugger);
|
||||
script_to_evaluate_on_load, client_expects_binary_responses,
|
||||
client_is_trusted, session_id, session_waits_for_debugger);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,6 +98,7 @@ class CORE_EXPORT DevToolsAgent : public GarbageCollected<DevToolsAgent>,
|
||||
main_session,
|
||||
mojo::PendingReceiver<mojom::blink::DevToolsSession> io_session,
|
||||
mojom::blink::DevToolsSessionStatePtr reattach_session_state,
|
||||
const WTF::String& script_to_evaluate_on_load,
|
||||
bool client_expects_binary_responses,
|
||||
bool client_is_trusted,
|
||||
const WTF::String& session_id,
|
||||
@ -130,6 +131,7 @@ class CORE_EXPORT DevToolsAgent : public GarbageCollected<DevToolsAgent>,
|
||||
main_session,
|
||||
mojo::PendingReceiver<mojom::blink::DevToolsSession> io_session,
|
||||
mojom::blink::DevToolsSessionStatePtr reattach_session_state,
|
||||
const WTF::String& script_to_evaluate_on_load,
|
||||
bool client_expects_binary_responses,
|
||||
bool client_is_trusted,
|
||||
const WTF::String& session_id,
|
||||
|
@ -128,6 +128,12 @@ class DevToolsSession::IOSession : public mojom::blink::DevToolsSession {
|
||||
}
|
||||
}
|
||||
|
||||
void UnpauseAndTerminate() override {
|
||||
inspector_task_runner_->AppendTask(
|
||||
CrossThreadBindOnce(&::blink::DevToolsSession::UnpauseAndTerminate,
|
||||
MakeUnwrappingCrossThreadWeakHandle(session_)));
|
||||
}
|
||||
|
||||
private:
|
||||
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
|
||||
scoped_refptr<InspectorTaskRunner> inspector_task_runner_;
|
||||
@ -143,6 +149,7 @@ DevToolsSession::DevToolsSession(
|
||||
main_receiver,
|
||||
mojo::PendingReceiver<mojom::blink::DevToolsSession> io_receiver,
|
||||
mojom::blink::DevToolsSessionStatePtr reattach_session_state,
|
||||
const String& script_to_evaluate_on_load,
|
||||
bool client_expects_binary_responses,
|
||||
bool client_is_trusted,
|
||||
const String& session_id,
|
||||
@ -155,6 +162,7 @@ DevToolsSession::DevToolsSession(
|
||||
client_is_trusted_(client_is_trusted),
|
||||
v8_session_state_(kV8StateKey),
|
||||
v8_session_state_cbor_(&v8_session_state_, /*default_value=*/{}),
|
||||
script_to_evaluate_on_load_(script_to_evaluate_on_load),
|
||||
session_id_(session_id),
|
||||
session_waits_for_debugger_(session_waits_for_debugger) {
|
||||
receiver_.Bind(std::move(main_receiver), mojo_task_runner);
|
||||
@ -277,9 +285,8 @@ void DevToolsSession::DispatchProtocolCommandImpl(
|
||||
}
|
||||
|
||||
void DevToolsSession::DidStartProvisionalLoad(LocalFrame* frame) {
|
||||
if (v8_session_ && agent_->inspected_frames_->Root() == frame) {
|
||||
v8_session_->setSkipAllPauses(true);
|
||||
v8_session_->resume(true /* terminate on resume */);
|
||||
if (agent_->inspected_frames_->Root() == frame) {
|
||||
UnpauseAndTerminate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -433,4 +440,12 @@ blink::mojom::blink::DevToolsMessagePtr DevToolsSession::FinalizeMessage(
|
||||
return mojo_msg;
|
||||
}
|
||||
|
||||
void DevToolsSession::UnpauseAndTerminate() {
|
||||
if (!v8_session_) {
|
||||
return;
|
||||
}
|
||||
v8_session_->setSkipAllPauses(true);
|
||||
v8_session_->resume(true /* terminate on resume */);
|
||||
}
|
||||
|
||||
} // namespace blink
|
||||
|
@ -62,6 +62,7 @@ class CORE_EXPORT DevToolsSession : public GarbageCollected<DevToolsSession>,
|
||||
main_receiver,
|
||||
mojo::PendingReceiver<mojom::blink::DevToolsSession> io_receiver,
|
||||
mojom::blink::DevToolsSessionStatePtr reattach_session_state,
|
||||
const String& script_to_evaluate_on_load,
|
||||
bool client_expects_binary_responses,
|
||||
bool client_is_trusted,
|
||||
const String& session_id,
|
||||
@ -97,6 +98,10 @@ class CORE_EXPORT DevToolsSession : public GarbageCollected<DevToolsSession>,
|
||||
void PaintTiming(Document* document, const char* name, double timestamp);
|
||||
void DomContentLoadedEventFired(LocalFrame*);
|
||||
|
||||
const String& script_to_evaluate_on_load() const {
|
||||
return script_to_evaluate_on_load_;
|
||||
}
|
||||
|
||||
private:
|
||||
class IOSession;
|
||||
|
||||
@ -104,6 +109,8 @@ class CORE_EXPORT DevToolsSession : public GarbageCollected<DevToolsSession>,
|
||||
void DispatchProtocolCommand(int call_id,
|
||||
const String& method,
|
||||
base::span<const uint8_t> message) override;
|
||||
void UnpauseAndTerminate() override;
|
||||
|
||||
void DispatchProtocolCommandImpl(int call_id,
|
||||
const String& method,
|
||||
base::span<const uint8_t> message);
|
||||
@ -174,6 +181,7 @@ class CORE_EXPORT DevToolsSession : public GarbageCollected<DevToolsSession>,
|
||||
const bool client_is_trusted_;
|
||||
InspectorAgentState v8_session_state_;
|
||||
InspectorAgentState::Bytes v8_session_state_cbor_;
|
||||
String script_to_evaluate_on_load_;
|
||||
const String session_id_;
|
||||
// This is only relevant until the initial attach to v8 and is never reset
|
||||
// once the session stops waiting.
|
||||
|
@ -481,47 +481,12 @@ String InspectorPageAgent::CachedResourceTypeJson(
|
||||
return ResourceTypeJson(ToResourceType(cached_resource.GetType()));
|
||||
}
|
||||
|
||||
InspectorPageAgent::PageReloadScriptInjection::PageReloadScriptInjection(
|
||||
InspectorAgentState& agent_state)
|
||||
: pending_script_to_evaluate_on_load_once_(&agent_state,
|
||||
/*default_value=*/{}),
|
||||
target_url_for_pending_script_(&agent_state,
|
||||
/*default_value=*/{}) {}
|
||||
|
||||
void InspectorPageAgent::PageReloadScriptInjection::clear() {
|
||||
script_to_evaluate_on_load_once_ = {};
|
||||
pending_script_to_evaluate_on_load_once_.Set({});
|
||||
target_url_for_pending_script_.Set({});
|
||||
}
|
||||
|
||||
void InspectorPageAgent::PageReloadScriptInjection::SetPending(
|
||||
String script,
|
||||
const KURL& target_url) {
|
||||
pending_script_to_evaluate_on_load_once_.Set(script);
|
||||
target_url_for_pending_script_.Set(target_url.GetString().GetString());
|
||||
}
|
||||
|
||||
void InspectorPageAgent::PageReloadScriptInjection::PromoteToLoadOnce() {
|
||||
script_to_evaluate_on_load_once_ =
|
||||
pending_script_to_evaluate_on_load_once_.Get();
|
||||
target_url_for_active_script_ = target_url_for_pending_script_.Get();
|
||||
pending_script_to_evaluate_on_load_once_.Set({});
|
||||
target_url_for_pending_script_.Set({});
|
||||
}
|
||||
|
||||
String InspectorPageAgent::PageReloadScriptInjection::GetScriptForInjection(
|
||||
const KURL& target_url) {
|
||||
if (target_url_for_active_script_ == target_url.GetString()) {
|
||||
return script_to_evaluate_on_load_once_;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
InspectorPageAgent::InspectorPageAgent(
|
||||
InspectedFrames* inspected_frames,
|
||||
Client* client,
|
||||
InspectorResourceContentLoader* resource_content_loader,
|
||||
v8_inspector::V8InspectorSession* v8_session)
|
||||
v8_inspector::V8InspectorSession* v8_session,
|
||||
const String& script_to_evaluate_on_load)
|
||||
: inspected_frames_(inspected_frames),
|
||||
v8_session_(v8_session),
|
||||
client_(client),
|
||||
@ -545,7 +510,7 @@ InspectorPageAgent::InspectorPageAgent(
|
||||
standard_font_size_(&agent_state_, /*default_value=*/0),
|
||||
fixed_font_size_(&agent_state_, /*default_value=*/0),
|
||||
script_font_families_cbor_(&agent_state_, std::vector<uint8_t>()),
|
||||
script_injection_on_load_(agent_state_) {}
|
||||
pending_script_injection_on_load_(script_to_evaluate_on_load) {}
|
||||
|
||||
void InspectorPageAgent::Restore() {
|
||||
if (enabled_.Get()) {
|
||||
@ -591,7 +556,8 @@ protocol::Response InspectorPageAgent::enable(
|
||||
protocol::Response InspectorPageAgent::disable() {
|
||||
agent_state_.ClearAllFields();
|
||||
pending_isolated_worlds_.clear();
|
||||
script_injection_on_load_.clear();
|
||||
script_injection_on_load_once_ = {};
|
||||
pending_script_injection_on_load_ = {};
|
||||
instrumenting_agents_->RemoveInspectorPageAgent(this);
|
||||
inspector_resource_content_loader_->Cancel(
|
||||
resource_content_loader_client_id_);
|
||||
@ -729,9 +695,8 @@ protocol::Response InspectorPageAgent::reload(
|
||||
.ToString() != loader_id->Ascii()) {
|
||||
return protocol::Response::InvalidParams("Document already navigated");
|
||||
}
|
||||
script_injection_on_load_.SetPending(
|
||||
optional_script_to_evaluate_on_load.value_or(""),
|
||||
inspected_frames_->Root()->Loader().GetDocumentLoader()->Url());
|
||||
pending_script_injection_on_load_ =
|
||||
optional_script_to_evaluate_on_load.value_or("");
|
||||
v8_session_->setSkipAllPauses(true);
|
||||
v8_session_->resume(true /* terminate on resume */);
|
||||
return protocol::Response::Success();
|
||||
@ -1096,11 +1061,10 @@ void InspectorPageAgent::DidCreateMainWorldContext(LocalFrame* frame) {
|
||||
EvaluateScriptOnNewDocument(*frame, key);
|
||||
}
|
||||
|
||||
String script = script_injection_on_load_.GetScriptForInjection(
|
||||
frame->Loader().GetDocumentLoader()->Url());
|
||||
if (script.empty()) {
|
||||
if (script_injection_on_load_once_.empty()) {
|
||||
return;
|
||||
}
|
||||
String script = std::move(script_injection_on_load_once_);
|
||||
ScriptState* script_state = ToScriptStateForMainWorld(frame);
|
||||
if (!script_state || !v8_session_) {
|
||||
return;
|
||||
@ -1159,7 +1123,8 @@ void InspectorPageAgent::LoadEventFired(LocalFrame* frame) {
|
||||
|
||||
void InspectorPageAgent::WillCommitLoad(LocalFrame*, DocumentLoader* loader) {
|
||||
if (loader->GetFrame() == inspected_frames_->Root()) {
|
||||
script_injection_on_load_.PromoteToLoadOnce();
|
||||
script_injection_on_load_once_ =
|
||||
std::move(pending_script_injection_on_load_);
|
||||
}
|
||||
GetFrontend()->frameNavigated(BuildObjectForFrame(loader->GetFrame()),
|
||||
protocol::Page::NavigationTypeEnum::Navigation);
|
||||
|
@ -93,22 +93,6 @@ class CORE_EXPORT InspectorPageAgent final
|
||||
kOtherResource
|
||||
};
|
||||
|
||||
class CORE_EXPORT PageReloadScriptInjection {
|
||||
private:
|
||||
String script_to_evaluate_on_load_once_;
|
||||
String target_url_for_active_script_;
|
||||
InspectorAgentState::String pending_script_to_evaluate_on_load_once_;
|
||||
InspectorAgentState::String target_url_for_pending_script_;
|
||||
|
||||
public:
|
||||
explicit PageReloadScriptInjection(InspectorAgentState&);
|
||||
|
||||
void clear();
|
||||
void SetPending(String script, const KURL& target_url);
|
||||
void PromoteToLoadOnce();
|
||||
String GetScriptForInjection(const KURL& target_url);
|
||||
};
|
||||
|
||||
static bool CachedResourceContent(const Resource*,
|
||||
String* result,
|
||||
bool* base64_encoded,
|
||||
@ -126,7 +110,8 @@ class CORE_EXPORT InspectorPageAgent final
|
||||
InspectorPageAgent(InspectedFrames*,
|
||||
Client*,
|
||||
InspectorResourceContentLoader*,
|
||||
v8_inspector::V8InspectorSession*);
|
||||
v8_inspector::V8InspectorSession*,
|
||||
const String& script_to_evaluate_on_load);
|
||||
InspectorPageAgent(const InspectorPageAgent&) = delete;
|
||||
InspectorPageAgent& operator=(const InspectorPageAgent&) = delete;
|
||||
|
||||
@ -356,7 +341,8 @@ class CORE_EXPORT InspectorPageAgent final
|
||||
InspectorAgentState::Integer standard_font_size_;
|
||||
InspectorAgentState::Integer fixed_font_size_;
|
||||
InspectorAgentState::Bytes script_font_families_cbor_;
|
||||
PageReloadScriptInjection script_injection_on_load_;
|
||||
String script_injection_on_load_once_;
|
||||
String pending_script_injection_on_load_;
|
||||
};
|
||||
|
||||
} // namespace blink
|
||||
|
@ -1,57 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "third_party/blink/renderer/core/inspector/inspector_page_agent.h"
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "third_party/blink/renderer/core/inspector/inspector_session_state.h"
|
||||
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
|
||||
|
||||
class PageReloadScriptInjectionTest : public testing::Test {
|
||||
protected:
|
||||
blink::mojom::blink::DevToolsSessionStatePtr session_state_cookie_;
|
||||
blink::InspectorAgentState agent_state_;
|
||||
blink::InspectorPageAgent::PageReloadScriptInjection injection_;
|
||||
blink::InspectorSessionState state_;
|
||||
|
||||
public:
|
||||
PageReloadScriptInjectionTest()
|
||||
: agent_state_("page"),
|
||||
injection_(agent_state_),
|
||||
state_(session_state_cookie_.Clone()) {}
|
||||
|
||||
void SetUp() override { agent_state_.InitFrom(&state_); }
|
||||
};
|
||||
|
||||
TEST_F(PageReloadScriptInjectionTest, PromotesScript) {
|
||||
blink::KURL url("http://example.com");
|
||||
injection_.SetPending("script", url);
|
||||
ASSERT_TRUE(injection_.GetScriptForInjection(url).empty());
|
||||
injection_.PromoteToLoadOnce();
|
||||
ASSERT_EQ(injection_.GetScriptForInjection(url), "script");
|
||||
injection_.PromoteToLoadOnce();
|
||||
ASSERT_TRUE(injection_.GetScriptForInjection(url).empty());
|
||||
}
|
||||
|
||||
TEST_F(PageReloadScriptInjectionTest, ClearsScript) {
|
||||
blink::KURL url("http://example.com");
|
||||
injection_.SetPending("script", url);
|
||||
injection_.clear();
|
||||
injection_.PromoteToLoadOnce();
|
||||
ASSERT_TRUE(injection_.GetScriptForInjection(url).empty());
|
||||
|
||||
injection_.SetPending("script", url);
|
||||
injection_.PromoteToLoadOnce();
|
||||
ASSERT_EQ(injection_.GetScriptForInjection(url), "script");
|
||||
injection_.clear();
|
||||
ASSERT_TRUE(injection_.GetScriptForInjection(url).empty());
|
||||
}
|
||||
|
||||
TEST_F(PageReloadScriptInjectionTest, ChecksLoaderId) {
|
||||
blink::KURL url("http://example.com");
|
||||
blink::KURL url2("about:blank");
|
||||
injection_.SetPending("script", url);
|
||||
injection_.PromoteToLoadOnce();
|
||||
ASSERT_TRUE(injection_.GetScriptForInjection(url2).empty());
|
||||
}
|
Reference in New Issue
Block a user