Add 'did_proceed' and 'repeat_visit' to ClientMalwareReportRequest to track CTR.
[chromium-blink-merge.git] / components / web_view / frame_devtools_agent.cc
blobb11a946e501d4bf826f3bcf87e5dc1e3ee162671
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.
5 #include "components/web_view/frame_devtools_agent.h"
7 #include <string.h>
9 #include <vector>
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/values.h"
16 #include "components/web_view/frame_devtools_agent_delegate.h"
17 #include "mojo/application/public/cpp/application_impl.h"
18 #include "mojo/services/network/public/interfaces/url_loader.mojom.h"
19 #include "url/gurl.h"
21 namespace web_view {
23 using devtools_service::DevToolsAgentClientPtr;
24 using devtools_service::DevToolsAgentPtr;
25 using devtools_service::DevToolsRegistryPtr;
27 using mojo::String;
29 namespace {
31 void StringToVector(const std::string& in, std::vector<uint8_t>* out) {
32 out->resize(in.size());
33 if (!in.empty())
34 memcpy(&out->front(), in.c_str(), in.size());
37 } // namespace
39 // This class is used by FrameDevToolsAgent to relay client messages from the
40 // frame to the DevTools service.
41 class FrameDevToolsAgent::FrameDevToolsAgentClient
42 : public devtools_service::DevToolsAgentClient {
43 public:
44 FrameDevToolsAgentClient(FrameDevToolsAgent* owner,
45 DevToolsAgentClientPtr forward_client)
46 : owner_(owner), binding_(this), forward_client_(forward_client.Pass()) {
47 forward_client_.set_connection_error_handler(base::Bind(
48 &FrameDevToolsAgent::OnForwardClientClosed, base::Unretained(owner_)));
49 if (owner_->forward_agent_)
50 OnAttachedFrame();
53 ~FrameDevToolsAgentClient() override {}
55 void OnAttachedFrame() {
56 DCHECK(owner_->forward_agent_);
58 if (binding_.is_bound())
59 binding_.Close();
61 DevToolsAgentClientPtr client;
62 binding_.Bind(&client);
63 owner_->forward_agent_->SetClient(client.Pass());
66 private:
67 // DevToolsAgentClient implementation.
68 void DispatchProtocolMessage(int32_t call_id,
69 const String& message,
70 const String& state) override {
71 DCHECK(forward_client_);
72 owner_->OnReceivedClientMessage(call_id, message, state);
73 // The state is used to persist state across frame navigations. There is no
74 // need to forward it.
75 forward_client_->DispatchProtocolMessage(call_id, message, String());
78 FrameDevToolsAgent* const owner_;
79 mojo::Binding<DevToolsAgentClient> binding_;
80 // The DevToolsAgentClient interface provided by the DevTools service. This
81 // class will forward DevToolsAgentClient method calls it receives to
82 // |forward_client_|.
83 DevToolsAgentClientPtr forward_client_;
85 DISALLOW_COPY_AND_ASSIGN(FrameDevToolsAgentClient);
88 FrameDevToolsAgent::FrameDevToolsAgent(mojo::ApplicationImpl* app,
89 FrameDevToolsAgentDelegate* delegate)
90 : app_(app),
91 delegate_(delegate),
92 id_(base::GenerateGUID()),
93 binding_(this) {
94 DCHECK(app_);
95 DCHECK(delegate_);
98 FrameDevToolsAgent::~FrameDevToolsAgent() {}
100 void FrameDevToolsAgent::AttachFrame(
101 DevToolsAgentPtr forward_agent,
102 Frame::ClientPropertyMap* devtools_properties) {
103 RegisterAgentIfNecessary();
104 forward_agent_ = forward_agent.Pass();
106 StringToVector(id_, &(*devtools_properties)["devtools-id"]);
107 if (client_impl_) {
108 StringToVector(state_, &(*devtools_properties)["devtools-state"]);
109 client_impl_->OnAttachedFrame();
112 // This follows Chrome's logic and relies on the fact that call IDs increase
113 // monotonously so iterating over |pending_messages_| preserves the order in
114 // which they were received.
115 for (const auto& item : pending_messages_)
116 forward_agent_->DispatchProtocolMessage(item.second);
119 void FrameDevToolsAgent::RegisterAgentIfNecessary() {
120 if (binding_.is_bound())
121 return;
123 mojo::URLRequestPtr request(mojo::URLRequest::New());
124 request->url = "mojo:devtools_service";
125 DevToolsRegistryPtr devtools_registry;
126 app_->ConnectToService(request.Pass(), &devtools_registry);
128 DevToolsAgentPtr agent;
129 binding_.Bind(&agent);
130 devtools_registry->RegisterAgent(id_, agent.Pass());
133 void FrameDevToolsAgent::HandlePageNavigateRequest(
134 const base::DictionaryValue* request) {
135 std::string method;
136 if (!request->GetString("method", &method) || method != "Page.navigate")
137 return;
139 std::string url_string;
140 if (!request->GetString("params.url", &url_string))
141 return;
143 GURL url(url_string);
144 if (!url.is_valid())
145 return;
147 // Stop sending messages to the old frame which will be navigated away soon.
148 // However, we don't reset |client_impl_| because we want to receive responses
149 // and events from the old frame in the meantime.
150 forward_agent_.reset();
152 delegate_->HandlePageNavigateRequest(url);
155 void FrameDevToolsAgent::SetClient(DevToolsAgentClientPtr client) {
156 client_impl_.reset(new FrameDevToolsAgentClient(this, client.Pass()));
159 void FrameDevToolsAgent::DispatchProtocolMessage(const String& message) {
160 // TODO(yzshen): Consider refactoring and reusing the existing DevTools
161 // protocol parsing code.
163 scoped_ptr<base::Value> value = base::JSONReader::Read(message.get());
164 base::DictionaryValue* command = nullptr;
165 if (!value || !value->GetAsDictionary(&command)) {
166 VLOG(1) << "Unable to parse DevTools message: " << message;
167 return;
170 int call_id = -1;
171 if (!command->GetInteger("id", &call_id)) {
172 VLOG(1) << "Call Id not found in a DevTools request message: " << message;
173 return;
176 pending_messages_[call_id] = message;
178 HandlePageNavigateRequest(command);
180 if (forward_agent_)
181 forward_agent_->DispatchProtocolMessage(message);
184 void FrameDevToolsAgent::OnReceivedClientMessage(int32_t call_id,
185 const String& message,
186 const String& state) {
187 if (!state.is_null() && state.size() > 0)
188 state_ = state;
190 pending_messages_.erase(call_id);
193 void FrameDevToolsAgent::OnForwardClientClosed() {
194 client_impl_.reset();
195 state_.clear();
196 pending_messages_.clear();
199 } // namespace web_view