// Copyright 2016 The Chromium Authors // 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_SESSION_H_ #define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_SESSION_H_ #include #include #include #include #include #include "base/containers/flat_map.h" #include "base/containers/span.h" #include "base/memory/weak_ptr.h" #include "content/browser/devtools/protocol/protocol.h" #include "content/public/browser/devtools_agent_host_client_channel.h" #include "content/public/browser/devtools_external_agent_proxy.h" #include "mojo/public/cpp/bindings/associated_receiver.h" #include "mojo/public/cpp/bindings/associated_remote.h" #include "mojo/public/cpp/bindings/remote.h" #include "third_party/blink/public/mojom/devtools/devtools_agent.mojom.h" namespace content { class DevToolsAgentHostClient; class DevToolsAgentHostImpl; class DevToolsExternalAgentProxyDelegate; namespace protocol { class DevToolsDomainHandler; class AuditsHandler; class DOMHandler; class EmulationHandler; class InputHandler; class InspectorHandler; class IOHandler; class OverlayHandler; class NetworkHandler; class FetchHandler; class StorageHandler; class TargetHandler; class PageHandler; class TracingHandler; class LogHandler; class WebAuthnHandler; } class DevToolsSession : public protocol::FrontendChannel, public blink::mojom::DevToolsSessionHost, public DevToolsExternalAgentProxy, public content::DevToolsAgentHostClientChannel { public: // For sessions attached to the Tab target, the mode is set to TabTarget. // For other sessions, the mode is inherited from the parent. // This is used as an indication that the client has opted in into using // tab targets and lets backend use the new logic of target discovery: // - auto-attach on frame targets will not auto-attach subframes (these // will be instead attached to the Tab targets) // - certain features that depend on MPArch support will not be disabled // (BFCache, Prerender) enum class Mode { kSupportsTabTarget, kDoesNotSupportTabTarget, }; // For root sessions (see also private constructor for children). DevToolsSession(DevToolsAgentHostClient* client, Mode mode); ~DevToolsSession() override; void SetAgentHost(DevToolsAgentHostImpl* agent_host); void SetRuntimeResumeCallback(base::OnceClosure runtime_resume); bool IsWaitingForDebuggerOnStart() const; void Dispose(); // content::DevToolsAgentHostClientChannel implementation. content::DevToolsAgentHost* GetAgentHost() override; content::DevToolsAgentHostClient* GetClient() override; DevToolsSession* GetRootSession(); // 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); template Handler* CreateAndAddHandler(Args&&... args) { if (!IsDomainAvailableToUntrustedClient() && !client_->IsTrusted()) { return nullptr; } auto handler = std::make_unique(std::forward(args)...); Handler* handler_ptr = handler.get(); AddHandler(std::move(handler)); return handler_ptr; } void TurnIntoExternalProxy(DevToolsExternalAgentProxyDelegate* delegate); void AttachToAgent(blink::mojom::DevToolsAgent* agent, bool force_using_io_session); void DispatchProtocolMessage(base::span message); void SuspendSendingMessagesToAgent(); void ResumeSendingMessagesToAgent(); void ClearPendingMessages(bool did_crash); using HandlersMap = base::flat_map>; HandlersMap& handlers() { return handlers_; } DevToolsSession* AttachChildSession(const std::string& session_id, DevToolsAgentHostImpl* agent_host, DevToolsAgentHostClient* client, Mode mode); void DetachChildSession(const std::string& session_id); bool HasChildSession(const std::string& session_id); Mode session_mode() const { return mode_; } private: struct PendingMessage { int call_id; std::string method; std::vector payload; PendingMessage() = delete; PendingMessage(const PendingMessage&) = delete; PendingMessage& operator=(const PendingMessage&) = delete; PendingMessage(PendingMessage&&); PendingMessage(int call_id, crdtp::span method, crdtp::span payload); ~PendingMessage(); }; // For child sessions. DevToolsSession(DevToolsAgentHostClient* client, const std::string& session_id, DevToolsSession* parent, Mode mode); void MojoConnectionDestroyed(); void DispatchToAgent(const PendingMessage& message); void HandleCommand(base::span message); void HandleCommandInternal(crdtp::Dispatchable dispatchable, base::span message); void DispatchProtocolMessageInternal(crdtp::Dispatchable dispatchable, base::span message); // protocol::FrontendChannel implementation. void SendProtocolResponse( int call_id, std::unique_ptr message) override; void SendProtocolNotification( std::unique_ptr message) override; void FlushProtocolNotifications() override; void FallThrough(int call_id, crdtp::span method, crdtp::span message) override; // content::DevToolsAgentHostClientChannel implementation. void DispatchProtocolMessageToClient(std::vector message) override; // blink::mojom::DevToolsSessionHost implementation. void DispatchProtocolResponse( blink::mojom::DevToolsMessagePtr message, int call_id, blink::mojom::DevToolsSessionStatePtr updates) override; void DispatchProtocolNotification( blink::mojom::DevToolsMessagePtr message, blink::mojom::DevToolsSessionStatePtr updates) override; // DevToolsExternalAgentProxy implementation. void DispatchOnClientHost(base::span message) override; void ConnectionClosed() override; // Merges the |updates| received from the renderer into session_state_cookie_. void ApplySessionStateUpdates(blink::mojom::DevToolsSessionStatePtr updates); template bool IsDomainAvailableToUntrustedClient() { return std::disjunction_v, std::is_same, std::is_same, std::is_same, std::is_same, std::is_same, std::is_same, std::is_same, std::is_same, std::is_same, std::is_same, std::is_same, std::is_same, std::is_same, std::is_same>; } void AddHandler(std::unique_ptr handler); DevToolsAgentHostClient* const client_; DevToolsSession* const root_session_ = nullptr; const std::string session_id_; // empty if this is the root session. const Mode mode_; mojo::AssociatedReceiver receiver_{this}; mojo::AssociatedRemote session_; mojo::Remote io_session_; bool use_io_session_{false}; DevToolsAgentHostImpl* agent_host_ = nullptr; bool browser_only_ = false; HandlersMap handlers_; std::unique_ptr dispatcher_{ new protocol::UberDispatcher(this)}; bool suspended_sending_messages_to_agent_ = false; // Messages that were sent to the agent or queued after suspending. std::list pending_messages_; // Pending messages that were sent and are thus waiting for a response. base::flat_map::iterator> waiting_for_response_; // |session_state_cookie_| always corresponds to a state before // any of the waiting for response messages have been handled. // |session_state_cookie_| is nullptr before first attach. blink::mojom::DevToolsSessionStatePtr session_state_cookie_; base::flat_map child_sessions_; base::OnceClosure runtime_resume_; DevToolsExternalAgentProxyDelegate* proxy_delegate_ = nullptr; base::WeakPtrFactory weak_factory_{this}; }; } // namespace content #endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_SESSION_H_