| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/devtools/render_frame_devtools_agent_host.h" | 5 #include "content/browser/devtools/render_frame_devtools_agent_host.h" |
| 6 | 6 |
| 7 #include <tuple> | 7 #include <tuple> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/containers/flat_map.h" |
| 10 #include "base/guid.h" | 11 #include "base/guid.h" |
| 11 #include "base/json/json_reader.h" | 12 #include "base/json/json_reader.h" |
| 12 #include "base/lazy_instance.h" | 13 #include "base/lazy_instance.h" |
| 13 #include "base/memory/ptr_util.h" | 14 #include "base/memory/ptr_util.h" |
| 14 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
| 15 #include "build/build_config.h" | 16 #include "build/build_config.h" |
| 16 #include "content/browser/bad_message.h" | 17 #include "content/browser/bad_message.h" |
| 17 #include "content/browser/child_process_security_policy_impl.h" | 18 #include "content/browser/child_process_security_policy_impl.h" |
| 18 #include "content/browser/devtools/devtools_frame_trace_recorder.h" | 19 #include "content/browser/devtools/devtools_frame_trace_recorder.h" |
| 19 #include "content/browser/devtools/devtools_manager.h" | 20 #include "content/browser/devtools/devtools_manager.h" |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 public: | 112 public: |
| 112 FrameHostHolder( | 113 FrameHostHolder( |
| 113 RenderFrameDevToolsAgentHost* agent, RenderFrameHostImpl* host); | 114 RenderFrameDevToolsAgentHost* agent, RenderFrameHostImpl* host); |
| 114 ~FrameHostHolder(); | 115 ~FrameHostHolder(); |
| 115 | 116 |
| 116 RenderFrameHostImpl* host() const { return host_; } | 117 RenderFrameHostImpl* host() const { return host_; } |
| 117 | 118 |
| 118 void Attach(DevToolsSession* session); | 119 void Attach(DevToolsSession* session); |
| 119 void Reattach(FrameHostHolder* old); | 120 void Reattach(FrameHostHolder* old); |
| 120 void Detach(int session_id); | 121 void Detach(int session_id); |
| 122 void Disconnect(); |
| 121 void DispatchProtocolMessage(int session_id, | 123 void DispatchProtocolMessage(int session_id, |
| 122 int call_id, | 124 int call_id, |
| 123 const std::string& method, | 125 const std::string& method, |
| 124 const std::string& message); | 126 const std::string& message); |
| 125 void InspectElement(int session_id, int x, int y); | 127 void InspectElement(int session_id, int x, int y); |
| 126 bool ProcessChunkedMessageFromAgent(const DevToolsMessageChunk& chunk); | 128 bool ProcessChunkedMessageFromAgent(const DevToolsMessageChunk& chunk); |
| 127 void Suspend(); | 129 void Suspend(); |
| 128 void Resume(); | 130 void Resume(); |
| 129 | 131 |
| 130 private: | 132 private: |
| 131 void GrantPolicy(); | 133 void GrantPolicy(); |
| 132 void RevokePolicy(); | 134 void RevokePolicy(); |
| 133 void SendMessageToClient(int session_id, const std::string& message); | 135 void SendChunkedMessage(int session_id, const std::string& message); |
| 136 |
| 137 struct MethodAndMessage { |
| 138 std::string method; |
| 139 std::string message; |
| 140 }; |
| 141 |
| 142 struct SessionInfo { |
| 143 std::unique_ptr<DevToolsMessageChunkProcessor> chunk_processor; |
| 144 std::vector<std::string> pending_messages; |
| 145 // <call_id> -> MethodAndMessage |
| 146 std::map<int, MethodAndMessage> sent_messages; |
| 147 // These are sent messages for which we got a reply while suspended. |
| 148 std::map<int, MethodAndMessage> |
| 149 sent_messages_whose_reply_came_while_suspended; |
| 150 }; |
| 134 | 151 |
| 135 RenderFrameDevToolsAgentHost* agent_; | 152 RenderFrameDevToolsAgentHost* agent_; |
| 136 RenderFrameHostImpl* host_; | 153 RenderFrameHostImpl* host_; |
| 137 bool attached_; | |
| 138 bool suspended_; | 154 bool suspended_; |
| 139 DevToolsMessageChunkProcessor chunk_processor_; | 155 bool disconnected_; |
| 140 // <session_id, message> | 156 base::flat_map<int, SessionInfo> session_infos_; |
| 141 std::vector<std::pair<int, std::string>> pending_messages_; | |
| 142 // <call_id> -> PendingMessage | |
| 143 std::map<int, PendingMessage> sent_messages_; | |
| 144 // These are sent messages for which we got a reply while suspended. | |
| 145 std::map<int, PendingMessage> sent_messages_whose_reply_came_while_suspended_; | |
| 146 }; | 157 }; |
| 147 | 158 |
| 148 RenderFrameDevToolsAgentHost::FrameHostHolder::FrameHostHolder( | 159 RenderFrameDevToolsAgentHost::FrameHostHolder::FrameHostHolder( |
| 149 RenderFrameDevToolsAgentHost* agent, RenderFrameHostImpl* host) | 160 RenderFrameDevToolsAgentHost* agent, |
| 150 : agent_(agent), | 161 RenderFrameHostImpl* host) |
| 151 host_(host), | 162 : agent_(agent), host_(host), suspended_(false), disconnected_(false) { |
| 152 attached_(false), | |
| 153 suspended_(false), | |
| 154 chunk_processor_(base::Bind( | |
| 155 &RenderFrameDevToolsAgentHost::FrameHostHolder::SendMessageToClient, | |
| 156 base::Unretained(this))) { | |
| 157 DCHECK(agent_); | 163 DCHECK(agent_); |
| 158 DCHECK(host_); | 164 DCHECK(host_); |
| 159 } | 165 } |
| 160 | 166 |
| 161 RenderFrameDevToolsAgentHost::FrameHostHolder::~FrameHostHolder() { | 167 RenderFrameDevToolsAgentHost::FrameHostHolder::~FrameHostHolder() { |
| 162 if (attached_) | 168 if (!disconnected_ && !session_infos_.empty()) |
| 163 RevokePolicy(); | 169 RevokePolicy(); |
| 164 } | 170 } |
| 165 | 171 |
| 166 void RenderFrameDevToolsAgentHost::FrameHostHolder::Attach( | 172 void RenderFrameDevToolsAgentHost::FrameHostHolder::Attach( |
| 167 DevToolsSession* session) { | 173 DevToolsSession* session) { |
| 168 host_->Send(new DevToolsAgentMsg_Attach( | 174 host_->Send(new DevToolsAgentMsg_Attach( |
| 169 host_->GetRoutingID(), agent_->GetId(), session->session_id())); | 175 host_->GetRoutingID(), agent_->GetId(), session->session_id())); |
| 170 GrantPolicy(); | 176 GrantPolicy(); |
| 171 attached_ = true; | 177 SessionInfo& info = session_infos_[session->session_id()]; |
| 178 info.chunk_processor.reset(new DevToolsMessageChunkProcessor(base::Bind( |
| 179 &RenderFrameDevToolsAgentHost::FrameHostHolder::SendChunkedMessage, |
| 180 base::Unretained(this)))); |
| 172 } | 181 } |
| 173 | 182 |
| 174 void RenderFrameDevToolsAgentHost::FrameHostHolder::Reattach( | 183 void RenderFrameDevToolsAgentHost::FrameHostHolder::Reattach( |
| 175 FrameHostHolder* old) { | 184 FrameHostHolder* old) { |
| 176 if (old) | 185 int session_id = agent_->session()->session_id(); |
| 177 chunk_processor_.set_state_cookie(old->chunk_processor_.state_cookie()); | 186 SessionInfo& info = session_infos_[session_id]; |
| 187 info.chunk_processor.reset(new DevToolsMessageChunkProcessor(base::Bind( |
| 188 &RenderFrameDevToolsAgentHost::FrameHostHolder::SendChunkedMessage, |
| 189 base::Unretained(this)))); |
| 190 SessionInfo* old_info = nullptr; |
| 191 if (old) { |
| 192 auto it = old->session_infos_.find(session_id); |
| 193 old_info = it != old->session_infos_.end() ? &(it->second) : nullptr; |
| 194 } |
| 195 if (old_info) |
| 196 info.chunk_processor->set_state_cookie( |
| 197 old_info->chunk_processor->state_cookie()); |
| 178 host_->Send(new DevToolsAgentMsg_Reattach( | 198 host_->Send(new DevToolsAgentMsg_Reattach( |
| 179 host_->GetRoutingID(), agent_->GetId(), agent_->session()->session_id(), | 199 host_->GetRoutingID(), agent_->GetId(), session_id, |
| 180 chunk_processor_.state_cookie())); | 200 info.chunk_processor->state_cookie())); |
| 181 if (old) { | 201 if (old_info) { |
| 182 if (IsBrowserSideNavigationEnabled()) { | 202 if (IsBrowserSideNavigationEnabled()) { |
| 183 for (const auto& pair : | 203 for (const auto& pair : |
| 184 old->sent_messages_whose_reply_came_while_suspended_) { | 204 old_info->sent_messages_whose_reply_came_while_suspended) { |
| 185 DispatchProtocolMessage(pair.second.session_id, pair.first, | 205 DispatchProtocolMessage(session_id, pair.first, pair.second.method, |
| 186 pair.second.method, pair.second.message); | 206 pair.second.message); |
| 187 } | 207 } |
| 188 } | 208 } |
| 189 for (const auto& pair : old->sent_messages_) { | 209 for (const auto& pair : old_info->sent_messages) { |
| 190 DispatchProtocolMessage(pair.second.session_id, pair.first, | 210 DispatchProtocolMessage(session_id, pair.first, pair.second.method, |
| 191 pair.second.method, pair.second.message); | 211 pair.second.message); |
| 192 } | 212 } |
| 193 } | 213 } |
| 194 GrantPolicy(); | 214 GrantPolicy(); |
| 195 attached_ = true; | |
| 196 } | 215 } |
| 197 | 216 |
| 198 void RenderFrameDevToolsAgentHost::FrameHostHolder::Detach(int session_id) { | 217 void RenderFrameDevToolsAgentHost::FrameHostHolder::Detach(int session_id) { |
| 199 host_->Send(new DevToolsAgentMsg_Detach(host_->GetRoutingID(), session_id)); | 218 host_->Send(new DevToolsAgentMsg_Detach(host_->GetRoutingID(), session_id)); |
| 200 RevokePolicy(); | 219 RevokePolicy(); |
| 201 attached_ = false; | 220 session_infos_.erase(session_id); |
| 221 } |
| 222 |
| 223 void RenderFrameDevToolsAgentHost::FrameHostHolder::Disconnect() { |
| 224 for (auto& it : session_infos_) |
| 225 host_->Send(new DevToolsAgentMsg_Detach(host_->GetRoutingID(), it.first)); |
| 226 RevokePolicy(); |
| 227 disconnected_ = true; |
| 202 } | 228 } |
| 203 | 229 |
| 204 void RenderFrameDevToolsAgentHost::FrameHostHolder::GrantPolicy() { | 230 void RenderFrameDevToolsAgentHost::FrameHostHolder::GrantPolicy() { |
| 205 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadRawCookies( | 231 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadRawCookies( |
| 206 host_->GetProcess()->GetID()); | 232 host_->GetProcess()->GetID()); |
| 207 } | 233 } |
| 208 | 234 |
| 209 void RenderFrameDevToolsAgentHost::FrameHostHolder::RevokePolicy() { | 235 void RenderFrameDevToolsAgentHost::FrameHostHolder::RevokePolicy() { |
| 210 bool process_has_agents = false; | 236 bool process_has_agents = false; |
| 211 RenderProcessHost* process_host = host_->GetProcess(); | 237 RenderProcessHost* process_host = host_->GetProcess(); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 228 process_host->GetID()); | 254 process_host->GetID()); |
| 229 } | 255 } |
| 230 } | 256 } |
| 231 void RenderFrameDevToolsAgentHost::FrameHostHolder::DispatchProtocolMessage( | 257 void RenderFrameDevToolsAgentHost::FrameHostHolder::DispatchProtocolMessage( |
| 232 int session_id, | 258 int session_id, |
| 233 int call_id, | 259 int call_id, |
| 234 const std::string& method, | 260 const std::string& method, |
| 235 const std::string& message) { | 261 const std::string& message) { |
| 236 host_->Send(new DevToolsAgentMsg_DispatchOnInspectorBackend( | 262 host_->Send(new DevToolsAgentMsg_DispatchOnInspectorBackend( |
| 237 host_->GetRoutingID(), session_id, call_id, method, message)); | 263 host_->GetRoutingID(), session_id, call_id, method, message)); |
| 238 sent_messages_[call_id] = { session_id, method, message }; | 264 session_infos_[session_id].sent_messages[call_id] = {method, message}; |
| 239 } | 265 } |
| 240 | 266 |
| 241 void RenderFrameDevToolsAgentHost::FrameHostHolder::InspectElement( | 267 void RenderFrameDevToolsAgentHost::FrameHostHolder::InspectElement( |
| 242 int session_id, int x, int y) { | 268 int session_id, int x, int y) { |
| 243 DCHECK(attached_); | 269 DCHECK(session_infos_.find(session_id) != session_infos_.end()); |
| 244 host_->Send(new DevToolsAgentMsg_InspectElement( | 270 host_->Send(new DevToolsAgentMsg_InspectElement( |
| 245 host_->GetRoutingID(), session_id, x, y)); | 271 host_->GetRoutingID(), session_id, x, y)); |
| 246 } | 272 } |
| 247 | 273 |
| 248 bool | 274 bool |
| 249 RenderFrameDevToolsAgentHost::FrameHostHolder::ProcessChunkedMessageFromAgent( | 275 RenderFrameDevToolsAgentHost::FrameHostHolder::ProcessChunkedMessageFromAgent( |
| 250 const DevToolsMessageChunk& chunk) { | 276 const DevToolsMessageChunk& chunk) { |
| 251 return chunk_processor_.ProcessChunkedMessageFromAgent(chunk); | 277 auto it = session_infos_.find(chunk.session_id); |
| 278 if (it != session_infos_.end()) |
| 279 return it->second.chunk_processor->ProcessChunkedMessageFromAgent(chunk); |
| 280 return false; |
| 252 } | 281 } |
| 253 | 282 |
| 254 void RenderFrameDevToolsAgentHost::FrameHostHolder::SendMessageToClient( | 283 void RenderFrameDevToolsAgentHost::FrameHostHolder::SendChunkedMessage( |
| 255 int session_id, | 284 int session_id, |
| 256 const std::string& message) { | 285 const std::string& message) { |
| 257 int id = chunk_processor_.last_call_id(); | 286 auto it = session_infos_.find(session_id); |
| 258 PendingMessage sent_message = sent_messages_[id]; | 287 if (it == session_infos_.end()) |
| 259 sent_messages_.erase(id); | 288 return; |
| 289 SessionInfo& info = it->second; |
| 290 int id = info.chunk_processor->last_call_id(); |
| 291 MethodAndMessage sent_message = info.sent_messages[id]; |
| 292 info.sent_messages.erase(id); |
| 260 if (suspended_) { | 293 if (suspended_) { |
| 261 sent_messages_whose_reply_came_while_suspended_[id] = sent_message; | 294 info.sent_messages_whose_reply_came_while_suspended[id] = sent_message; |
| 262 pending_messages_.push_back(std::make_pair(session_id, message)); | 295 info.pending_messages.push_back(message); |
| 263 } else { | 296 } else { |
| 264 agent_->SendMessageToClient(session_id, message); | 297 // Filter any messages from previous sessions. |
| 298 if (agent_->session() && agent_->session()->session_id() == session_id) |
| 299 agent_->session()->SendMessageToClient(message); |
| 265 // |this| may be deleted at this point. | 300 // |this| may be deleted at this point. |
| 266 } | 301 } |
| 267 } | 302 } |
| 268 | 303 |
| 269 void RenderFrameDevToolsAgentHost::FrameHostHolder::Suspend() { | 304 void RenderFrameDevToolsAgentHost::FrameHostHolder::Suspend() { |
| 270 suspended_ = true; | 305 suspended_ = true; |
| 271 } | 306 } |
| 272 | 307 |
| 273 void RenderFrameDevToolsAgentHost::FrameHostHolder::Resume() { | 308 void RenderFrameDevToolsAgentHost::FrameHostHolder::Resume() { |
| 274 suspended_ = false; | 309 suspended_ = false; |
| 275 for (const auto& pair : pending_messages_) | 310 for (auto& it : session_infos_) { |
| 276 agent_->SendMessageToClient(pair.first, pair.second); | 311 SessionInfo& info = it.second; |
| 277 std::vector<std::pair<int, std::string>> empty; | 312 if (agent_->session() && agent_->session()->session_id() == it.first) { |
| 278 pending_messages_.swap(empty); | 313 for (const std::string& message : info.pending_messages) |
| 279 sent_messages_whose_reply_came_while_suspended_.clear(); | 314 agent_->session()->SendMessageToClient(message); |
| 315 } |
| 316 std::vector<std::string> empty; |
| 317 info.pending_messages.swap(empty); |
| 318 info.sent_messages_whose_reply_came_while_suspended.clear(); |
| 319 } |
| 280 } | 320 } |
| 281 | 321 |
| 282 // RenderFrameDevToolsAgentHost ------------------------------------------------ | 322 // RenderFrameDevToolsAgentHost ------------------------------------------------ |
| 283 | 323 |
| 284 // static | 324 // static |
| 285 scoped_refptr<DevToolsAgentHost> | 325 scoped_refptr<DevToolsAgentHost> |
| 286 DevToolsAgentHost::GetOrCreateFor(RenderFrameHost* frame_host) { | 326 DevToolsAgentHost::GetOrCreateFor(RenderFrameHost* frame_host) { |
| 287 while (frame_host && !ShouldCreateDevToolsFor(frame_host)) | 327 while (frame_host && !ShouldCreateDevToolsFor(frame_host)) |
| 288 frame_host = frame_host->GetParent(); | 328 frame_host = frame_host->GetParent(); |
| 289 DCHECK(frame_host); | 329 DCHECK(frame_host); |
| (...skipping 679 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 969 handlers_frame_host_ = host; | 1009 handlers_frame_host_ = host; |
| 970 if (session()) | 1010 if (session()) |
| 971 session()->SetRenderFrameHost(host); | 1011 session()->SetRenderFrameHost(host); |
| 972 } | 1012 } |
| 973 | 1013 |
| 974 void RenderFrameDevToolsAgentHost::DisconnectWebContents() { | 1014 void RenderFrameDevToolsAgentHost::DisconnectWebContents() { |
| 975 if (pending_) | 1015 if (pending_) |
| 976 DiscardPending(); | 1016 DiscardPending(); |
| 977 UpdateProtocolHandlers(nullptr); | 1017 UpdateProtocolHandlers(nullptr); |
| 978 disconnected_ = std::move(current_); | 1018 disconnected_ = std::move(current_); |
| 979 if (session()) | 1019 disconnected_->Disconnect(); |
| 980 disconnected_->Detach(session()->session_id()); | |
| 981 frame_tree_node_ = nullptr; | 1020 frame_tree_node_ = nullptr; |
| 982 in_navigation_protocol_message_buffer_.clear(); | 1021 in_navigation_protocol_message_buffer_.clear(); |
| 983 navigating_handles_.clear(); | 1022 navigating_handles_.clear(); |
| 984 pending_handle_ = nullptr; | 1023 pending_handle_ = nullptr; |
| 985 WebContentsObserver::Observe(nullptr); | 1024 WebContentsObserver::Observe(nullptr); |
| 986 } | 1025 } |
| 987 | 1026 |
| 988 void RenderFrameDevToolsAgentHost::ConnectWebContents(WebContents* wc) { | 1027 void RenderFrameDevToolsAgentHost::ConnectWebContents(WebContents* wc) { |
| 989 // CommitPending may destruct |this|. | 1028 // CommitPending may destruct |this|. |
| 990 scoped_refptr<RenderFrameDevToolsAgentHost> protect(this); | 1029 scoped_refptr<RenderFrameDevToolsAgentHost> protect(this); |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1165 RenderFrameHost* host) { | 1204 RenderFrameHost* host) { |
| 1166 return (current_ && current_->host() == host) || | 1205 return (current_ && current_->host() == host) || |
| 1167 (pending_ && pending_->host() == host); | 1206 (pending_ && pending_->host() == host); |
| 1168 } | 1207 } |
| 1169 | 1208 |
| 1170 bool RenderFrameDevToolsAgentHost::IsChildFrame() { | 1209 bool RenderFrameDevToolsAgentHost::IsChildFrame() { |
| 1171 return current_ && current_->host()->GetParent(); | 1210 return current_ && current_->host()->GetParent(); |
| 1172 } | 1211 } |
| 1173 | 1212 |
| 1174 } // namespace content | 1213 } // namespace content |
| OLD | NEW |