OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/web_view/frame_devtools_agent.h" | |
6 | |
7 #include <string.h> | |
8 #include <utility> | |
9 #include <vector> | |
10 | |
11 #include "base/bind.h" | |
12 #include "base/guid.h" | |
13 #include "base/json/json_reader.h" | |
14 #include "base/logging.h" | |
15 #include "base/macros.h" | |
16 #include "base/values.h" | |
17 #include "components/web_view/frame_devtools_agent_delegate.h" | |
18 #include "mojo/services/network/public/interfaces/url_loader.mojom.h" | |
19 #include "mojo/shell/public/cpp/shell.h" | |
20 #include "url/gurl.h" | |
21 | |
22 namespace web_view { | |
23 | |
24 using devtools_service::DevToolsAgentClientPtr; | |
25 using devtools_service::DevToolsAgentPtr; | |
26 using devtools_service::DevToolsRegistryPtr; | |
27 | |
28 using mojo::String; | |
29 | |
30 namespace { | |
31 | |
32 void StringToVector(const std::string& in, std::vector<uint8_t>* out) { | |
33 out->resize(in.size()); | |
34 if (!in.empty()) | |
35 memcpy(&out->front(), in.c_str(), in.size()); | |
36 } | |
37 | |
38 } // namespace | |
39 | |
40 // This class is used by FrameDevToolsAgent to relay client messages from the | |
41 // frame to the DevTools service. | |
42 class FrameDevToolsAgent::FrameDevToolsAgentClient | |
43 : public devtools_service::DevToolsAgentClient { | |
44 public: | |
45 FrameDevToolsAgentClient(FrameDevToolsAgent* owner, | |
46 DevToolsAgentClientPtr forward_client) | |
47 : owner_(owner), | |
48 binding_(this), | |
49 forward_client_(std::move(forward_client)) { | |
50 forward_client_.set_connection_error_handler(base::Bind( | |
51 &FrameDevToolsAgent::OnForwardClientClosed, base::Unretained(owner_))); | |
52 if (owner_->forward_agent_) | |
53 OnAttachedFrame(); | |
54 } | |
55 | |
56 ~FrameDevToolsAgentClient() override {} | |
57 | |
58 void OnAttachedFrame() { | |
59 DCHECK(owner_->forward_agent_); | |
60 | |
61 if (binding_.is_bound()) | |
62 binding_.Close(); | |
63 | |
64 owner_->forward_agent_->SetClient(binding_.CreateInterfacePtrAndBind()); | |
65 } | |
66 | |
67 private: | |
68 // DevToolsAgentClient implementation. | |
69 void DispatchProtocolMessage(int32_t call_id, | |
70 const String& message, | |
71 const String& state) override { | |
72 DCHECK(forward_client_); | |
73 owner_->OnReceivedClientMessage(call_id, message, state); | |
74 // The state is used to persist state across frame navigations. There is no | |
75 // need to forward it. | |
76 forward_client_->DispatchProtocolMessage(call_id, message, String()); | |
77 } | |
78 | |
79 FrameDevToolsAgent* const owner_; | |
80 mojo::Binding<DevToolsAgentClient> binding_; | |
81 // The DevToolsAgentClient interface provided by the DevTools service. This | |
82 // class will forward DevToolsAgentClient method calls it receives to | |
83 // |forward_client_|. | |
84 DevToolsAgentClientPtr forward_client_; | |
85 | |
86 DISALLOW_COPY_AND_ASSIGN(FrameDevToolsAgentClient); | |
87 }; | |
88 | |
89 FrameDevToolsAgent::FrameDevToolsAgent(mojo::Shell* shell, | |
90 FrameDevToolsAgentDelegate* delegate) | |
91 : shell_(shell), | |
92 delegate_(delegate), | |
93 id_(base::GenerateGUID()), | |
94 binding_(this) { | |
95 DCHECK(shell_); | |
96 DCHECK(delegate_); | |
97 } | |
98 | |
99 FrameDevToolsAgent::~FrameDevToolsAgent() {} | |
100 | |
101 void FrameDevToolsAgent::AttachFrame( | |
102 DevToolsAgentPtr forward_agent, | |
103 Frame::ClientPropertyMap* devtools_properties) { | |
104 RegisterAgentIfNecessary(); | |
105 forward_agent_ = std::move(forward_agent); | |
106 | |
107 StringToVector(id_, &(*devtools_properties)["devtools-id"]); | |
108 if (client_impl_) { | |
109 StringToVector(state_, &(*devtools_properties)["devtools-state"]); | |
110 client_impl_->OnAttachedFrame(); | |
111 } | |
112 | |
113 // This follows Chrome's logic and relies on the fact that call IDs increase | |
114 // monotonously so iterating over |pending_messages_| preserves the order in | |
115 // which they were received. | |
116 for (const auto& item : pending_messages_) | |
117 forward_agent_->DispatchProtocolMessage(item.second); | |
118 } | |
119 | |
120 void FrameDevToolsAgent::RegisterAgentIfNecessary() { | |
121 if (binding_.is_bound()) | |
122 return; | |
123 | |
124 DevToolsRegistryPtr devtools_registry; | |
125 shell_->ConnectToService("mojo:devtools_service", &devtools_registry); | |
126 | |
127 devtools_registry->RegisterAgent(id_, binding_.CreateInterfacePtrAndBind()); | |
128 } | |
129 | |
130 void FrameDevToolsAgent::HandlePageNavigateRequest( | |
131 const base::DictionaryValue* request) { | |
132 std::string method; | |
133 if (!request->GetString("method", &method) || method != "Page.navigate") | |
134 return; | |
135 | |
136 std::string url_string; | |
137 if (!request->GetString("params.url", &url_string)) | |
138 return; | |
139 | |
140 GURL url(url_string); | |
141 if (!url.is_valid()) | |
142 return; | |
143 | |
144 // Stop sending messages to the old frame which will be navigated away soon. | |
145 // However, we don't reset |client_impl_| because we want to receive responses | |
146 // and events from the old frame in the meantime. | |
147 forward_agent_.reset(); | |
148 | |
149 delegate_->HandlePageNavigateRequest(url); | |
150 } | |
151 | |
152 void FrameDevToolsAgent::SetClient(DevToolsAgentClientPtr client) { | |
153 client_impl_.reset(new FrameDevToolsAgentClient(this, std::move(client))); | |
154 } | |
155 | |
156 void FrameDevToolsAgent::DispatchProtocolMessage(const String& message) { | |
157 // TODO(yzshen): Consider refactoring and reusing the existing DevTools | |
158 // protocol parsing code. | |
159 | |
160 scoped_ptr<base::Value> value = base::JSONReader::Read(message.get()); | |
161 base::DictionaryValue* command = nullptr; | |
162 if (!value || !value->GetAsDictionary(&command)) { | |
163 VLOG(1) << "Unable to parse DevTools message: " << message; | |
164 return; | |
165 } | |
166 | |
167 int call_id = -1; | |
168 if (!command->GetInteger("id", &call_id)) { | |
169 VLOG(1) << "Call Id not found in a DevTools request message: " << message; | |
170 return; | |
171 } | |
172 | |
173 pending_messages_[call_id] = message; | |
174 | |
175 HandlePageNavigateRequest(command); | |
176 | |
177 if (forward_agent_) | |
178 forward_agent_->DispatchProtocolMessage(message); | |
179 } | |
180 | |
181 void FrameDevToolsAgent::OnReceivedClientMessage(int32_t call_id, | |
182 const String& message, | |
183 const String& state) { | |
184 if (!state.is_null() && state.size() > 0) | |
185 state_ = state; | |
186 | |
187 pending_messages_.erase(call_id); | |
188 } | |
189 | |
190 void FrameDevToolsAgent::OnForwardClientClosed() { | |
191 client_impl_.reset(); | |
192 state_.clear(); | |
193 pending_messages_.clear(); | |
194 } | |
195 | |
196 } // namespace web_view | |
OLD | NEW |