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 "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/json/json_reader.h" |
9 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
10 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
| 12 #include "base/values.h" |
11 #include "content/browser/child_process_security_policy_impl.h" | 13 #include "content/browser/child_process_security_policy_impl.h" |
12 #include "content/browser/devtools/devtools_frame_trace_recorder.h" | 14 #include "content/browser/devtools/devtools_frame_trace_recorder.h" |
13 #include "content/browser/devtools/devtools_protocol_handler.h" | 15 #include "content/browser/devtools/devtools_protocol_handler.h" |
14 #include "content/browser/devtools/protocol/dom_handler.h" | 16 #include "content/browser/devtools/protocol/dom_handler.h" |
15 #include "content/browser/devtools/protocol/emulation_handler.h" | 17 #include "content/browser/devtools/protocol/emulation_handler.h" |
16 #include "content/browser/devtools/protocol/input_handler.h" | 18 #include "content/browser/devtools/protocol/input_handler.h" |
17 #include "content/browser/devtools/protocol/inspector_handler.h" | 19 #include "content/browser/devtools/protocol/inspector_handler.h" |
18 #include "content/browser/devtools/protocol/io_handler.h" | 20 #include "content/browser/devtools/protocol/io_handler.h" |
19 #include "content/browser/devtools/protocol/network_handler.h" | 21 #include "content/browser/devtools/protocol/network_handler.h" |
20 #include "content/browser/devtools/protocol/page_handler.h" | 22 #include "content/browser/devtools/protocol/page_handler.h" |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
92 void Reattach(FrameHostHolder* old); | 94 void Reattach(FrameHostHolder* old); |
93 void Detach(); | 95 void Detach(); |
94 void DispatchProtocolMessage(int session_id, | 96 void DispatchProtocolMessage(int session_id, |
95 int call_id, | 97 int call_id, |
96 const std::string& message); | 98 const std::string& message); |
97 void InspectElement(int x, int y); | 99 void InspectElement(int x, int y); |
98 void ProcessChunkedMessageFromAgent(const DevToolsMessageChunk& chunk); | 100 void ProcessChunkedMessageFromAgent(const DevToolsMessageChunk& chunk); |
99 void Suspend(); | 101 void Suspend(); |
100 void Resume(); | 102 void Resume(); |
101 | 103 |
| 104 bool suspended() const { return suspended_; } |
| 105 const std::string& last_loading_frame_id() const { |
| 106 return last_loading_frame_id_; |
| 107 } |
| 108 |
102 private: | 109 private: |
103 void GrantPolicy(); | 110 void GrantPolicy(); |
104 void RevokePolicy(); | 111 void RevokePolicy(); |
105 void SendMessageToClient(int session_id, const std::string& message); | 112 void SendMessageToClient(int session_id, const std::string& message); |
106 | 113 |
107 RenderFrameDevToolsAgentHost* agent_; | 114 RenderFrameDevToolsAgentHost* agent_; |
108 RenderFrameHostImpl* host_; | 115 RenderFrameHostImpl* host_; |
109 bool attached_; | 116 bool attached_; |
110 bool suspended_; | 117 bool suspended_; |
111 DevToolsMessageChunkProcessor chunk_processor_; | 118 DevToolsMessageChunkProcessor chunk_processor_; |
112 // <session_id, message> | 119 // <session_id, message> |
113 std::vector<std::pair<int, std::string>> pending_messages_; | 120 std::vector<std::pair<int, std::string>> pending_messages_; |
114 // <call_id> -> <session_id, message> | 121 // <call_id> -> <session_id, message> |
115 std::map<int, std::pair<int, std::string>> sent_messages_; | 122 std::map<int, std::pair<int, std::string>> sent_messages_; |
| 123 std::string last_loading_frame_id_; |
116 }; | 124 }; |
117 | 125 |
118 RenderFrameDevToolsAgentHost::FrameHostHolder::FrameHostHolder( | 126 RenderFrameDevToolsAgentHost::FrameHostHolder::FrameHostHolder( |
119 RenderFrameDevToolsAgentHost* agent, RenderFrameHostImpl* host) | 127 RenderFrameDevToolsAgentHost* agent, RenderFrameHostImpl* host) |
120 : agent_(agent), | 128 : agent_(agent), |
121 host_(host), | 129 host_(host), |
122 attached_(false), | 130 attached_(false), |
123 suspended_(false), | 131 suspended_(false), |
124 chunk_processor_(base::Bind( | 132 chunk_processor_(base::Bind( |
125 &RenderFrameDevToolsAgentHost::FrameHostHolder::SendMessageToClient, | 133 &RenderFrameDevToolsAgentHost::FrameHostHolder::SendMessageToClient, |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 } | 221 } |
214 | 222 |
215 void RenderFrameDevToolsAgentHost::FrameHostHolder::SendMessageToClient( | 223 void RenderFrameDevToolsAgentHost::FrameHostHolder::SendMessageToClient( |
216 int session_id, | 224 int session_id, |
217 const std::string& message) { | 225 const std::string& message) { |
218 sent_messages_.erase(chunk_processor_.last_call_id()); | 226 sent_messages_.erase(chunk_processor_.last_call_id()); |
219 if (suspended_) | 227 if (suspended_) |
220 pending_messages_.push_back(std::make_pair(session_id, message)); | 228 pending_messages_.push_back(std::make_pair(session_id, message)); |
221 else | 229 else |
222 agent_->SendMessageToClient(session_id, message); | 230 agent_->SendMessageToClient(session_id, message); |
| 231 |
| 232 // Store frameId when the frame starts loading to use it in case if the |
| 233 // pending frame host is discarded. |
| 234 if (last_loading_frame_id_.empty() && |
| 235 message.find("Page.frameStartedLoading") != std::string::npos) { |
| 236 scoped_ptr<base::Value> message_content = base::JSONReader::Read(message); |
| 237 base::DictionaryValue* message_dict; |
| 238 if (message_content && message_content->GetAsDictionary(&message_dict)) { |
| 239 base::DictionaryValue* params; |
| 240 if (message_dict->GetDictionary("params", ¶ms)) |
| 241 params->GetString("frameId", &last_loading_frame_id_); |
| 242 } |
| 243 } |
223 } | 244 } |
224 | 245 |
225 void RenderFrameDevToolsAgentHost::FrameHostHolder::Suspend() { | 246 void RenderFrameDevToolsAgentHost::FrameHostHolder::Suspend() { |
226 suspended_ = true; | 247 suspended_ = true; |
227 } | 248 } |
228 | 249 |
229 void RenderFrameDevToolsAgentHost::FrameHostHolder::Resume() { | 250 void RenderFrameDevToolsAgentHost::FrameHostHolder::Resume() { |
230 suspended_ = false; | 251 suspended_ = false; |
231 for (const auto& pair : pending_messages_) | 252 for (const auto& pair : pending_messages_) |
232 agent_->SendMessageToClient(pair.first, pair.second); | 253 agent_->SendMessageToClient(pair.first, pair.second); |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
383 void RenderFrameDevToolsAgentHost::SetPending(RenderFrameHostImpl* host) { | 404 void RenderFrameDevToolsAgentHost::SetPending(RenderFrameHostImpl* host) { |
384 DCHECK(!pending_); | 405 DCHECK(!pending_); |
385 current_frame_crashed_ = false; | 406 current_frame_crashed_ = false; |
386 pending_.reset(new FrameHostHolder(this, host)); | 407 pending_.reset(new FrameHostHolder(this, host)); |
387 if (IsAttached()) | 408 if (IsAttached()) |
388 pending_->Reattach(current_.get()); | 409 pending_->Reattach(current_.get()); |
389 | 410 |
390 // Can only be null in constructor. | 411 // Can only be null in constructor. |
391 if (current_) | 412 if (current_) |
392 current_->Suspend(); | 413 current_->Suspend(); |
393 pending_->Suspend(); | 414 // Don't suspend pending_ as it may break clients. |
394 | 415 |
395 UpdateProtocolHandlers(host); | 416 UpdateProtocolHandlers(host); |
396 } | 417 } |
397 | 418 |
398 void RenderFrameDevToolsAgentHost::CommitPending() { | 419 void RenderFrameDevToolsAgentHost::CommitPending() { |
399 DCHECK(pending_); | 420 DCHECK(pending_); |
400 current_frame_crashed_ = false; | 421 current_frame_crashed_ = false; |
401 | 422 |
402 if (!ShouldCreateDevToolsFor(pending_->host())) { | 423 if (!ShouldCreateDevToolsFor(pending_->host())) { |
403 DestroyOnRenderFrameGone(); | 424 DestroyOnRenderFrameGone(); |
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
717 } | 738 } |
718 | 739 |
719 void RenderFrameDevToolsAgentHost::DidFailProvisionalLoad( | 740 void RenderFrameDevToolsAgentHost::DidFailProvisionalLoad( |
720 RenderFrameHost* render_frame_host, | 741 RenderFrameHost* render_frame_host, |
721 const GURL& validated_url, | 742 const GURL& validated_url, |
722 int error_code, | 743 int error_code, |
723 const base::string16& error_description, | 744 const base::string16& error_description, |
724 bool was_ignored_by_handler) { | 745 bool was_ignored_by_handler) { |
725 if (browser_side_navigation) | 746 if (browser_side_navigation) |
726 return; | 747 return; |
727 if (pending_ && pending_->host() == render_frame_host) | 748 if (pending_ && pending_->host() == render_frame_host) { |
| 749 // When a pending cross-process navigation gets cancelled, the client does |
| 750 // not receive frameStoppedLoading event, which can cause problems with |
| 751 // further operation. Forge the event to avoid that. |
| 752 if (!pending_->suspended() && !pending_->last_loading_frame_id().empty()) { |
| 753 SendMessageToClient( |
| 754 session_id(), |
| 755 "{\"method\":\"Page.frameStoppedLoading\",\"params\":" |
| 756 "{\"frameId\":\"" + pending_->last_loading_frame_id() + "\"}}"); |
| 757 } |
| 758 |
728 DiscardPending(); | 759 DiscardPending(); |
| 760 } |
729 } | 761 } |
730 | 762 |
731 void RenderFrameDevToolsAgentHost:: | 763 void RenderFrameDevToolsAgentHost:: |
732 DispatchBufferedProtocolMessagesIfNecessary() { | 764 DispatchBufferedProtocolMessagesIfNecessary() { |
733 if (in_navigation_ == 0 && in_navigation_protocol_message_buffer_.size()) { | 765 if (in_navigation_ == 0 && in_navigation_protocol_message_buffer_.size()) { |
734 DCHECK(current_); | 766 DCHECK(current_); |
735 for (const auto& pair : in_navigation_protocol_message_buffer_) { | 767 for (const auto& pair : in_navigation_protocol_message_buffer_) { |
736 current_->DispatchProtocolMessage(pair.second.first, pair.first, | 768 current_->DispatchProtocolMessage(pair.second.first, pair.first, |
737 pair.second.second); | 769 pair.second.second); |
738 } | 770 } |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
863 } | 895 } |
864 | 896 |
865 bool RenderFrameDevToolsAgentHost::MatchesMyTreeNode( | 897 bool RenderFrameDevToolsAgentHost::MatchesMyTreeNode( |
866 NavigationHandle* navigation_handle) { | 898 NavigationHandle* navigation_handle) { |
867 return frame_tree_node_ == | 899 return frame_tree_node_ == |
868 static_cast<NavigationHandleImpl*>(navigation_handle) | 900 static_cast<NavigationHandleImpl*>(navigation_handle) |
869 ->frame_tree_node(); | 901 ->frame_tree_node(); |
870 } | 902 } |
871 | 903 |
872 } // namespace content | 904 } // namespace content |
OLD | NEW |