Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(229)

Side by Side Diff: content/shell/browser/shell_devtools_frontend.cc

Issue 2756623002: DevTools: extract bindings from ShellDevToolsFrontend (Closed)
Patch Set: fixup Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/shell/browser/shell_devtools_frontend.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/shell/browser/shell_devtools_frontend.h" 5 #include "content/shell/browser/shell_devtools_frontend.h"
6 6
7 #include <stddef.h>
8
9 #include "base/json/json_reader.h"
10 #include "base/json/json_writer.h"
11 #include "base/json/string_escape.h"
12 #include "base/macros.h"
13 #include "base/strings/string_number_conversions.h" 7 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/stringprintf.h" 8 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h" 9 #include "base/strings/utf_string_conversions.h"
16 #include "base/values.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/render_frame_host.h"
19 #include "content/public/browser/render_view_host.h"
20 #include "content/public/browser/storage_partition.h"
21 #include "content/public/browser/web_contents.h" 10 #include "content/public/browser/web_contents.h"
22 #include "content/public/common/content_client.h" 11 #include "content/public/browser/web_contents_observer.h"
23 #include "content/shell/browser/shell.h" 12 #include "content/shell/browser/shell.h"
24 #include "content/shell/browser/shell_browser_context.h" 13 #include "content/shell/browser/shell_browser_context.h"
25 #include "content/shell/browser/shell_browser_main_parts.h" 14 #include "content/shell/browser/shell_devtools_bindings.h"
26 #include "content/shell/browser/shell_content_browser_client.h"
27 #include "content/shell/browser/shell_devtools_manager_delegate.h" 15 #include "content/shell/browser/shell_devtools_manager_delegate.h"
28 #include "net/base/io_buffer.h"
29 #include "net/base/net_errors.h"
30 #include "net/http/http_response_headers.h"
31 #include "net/url_request/url_fetcher.h"
32 #include "net/url_request/url_fetcher_response_writer.h"
33
34 #if !defined(OS_ANDROID)
35 #include "content/public/browser/devtools_frontend_host.h"
36 #endif
37 16
38 namespace content { 17 namespace content {
39 18
40 namespace { 19 namespace {
41
42
43 // ResponseWriter -------------------------------------------------------------
44
45 class ResponseWriter : public net::URLFetcherResponseWriter {
46 public:
47 ResponseWriter(base::WeakPtr<ShellDevToolsFrontend> shell_devtools_,
48 int stream_id);
49 ~ResponseWriter() override;
50
51 // URLFetcherResponseWriter overrides:
52 int Initialize(const net::CompletionCallback& callback) override;
53 int Write(net::IOBuffer* buffer,
54 int num_bytes,
55 const net::CompletionCallback& callback) override;
56 int Finish(int net_error, const net::CompletionCallback& callback) override;
57
58 private:
59 base::WeakPtr<ShellDevToolsFrontend> shell_devtools_;
60 int stream_id_;
61
62 DISALLOW_COPY_AND_ASSIGN(ResponseWriter);
63 };
64
65 ResponseWriter::ResponseWriter(
66 base::WeakPtr<ShellDevToolsFrontend> shell_devtools,
67 int stream_id)
68 : shell_devtools_(shell_devtools),
69 stream_id_(stream_id) {
70 }
71
72 ResponseWriter::~ResponseWriter() {
73 }
74
75 int ResponseWriter::Initialize(const net::CompletionCallback& callback) {
76 return net::OK;
77 }
78
79 int ResponseWriter::Write(net::IOBuffer* buffer,
80 int num_bytes,
81 const net::CompletionCallback& callback) {
82 std::string chunk = std::string(buffer->data(), num_bytes);
83 if (!base::IsStringUTF8(chunk))
84 return num_bytes;
85
86 base::Value* id = new base::Value(stream_id_);
87 base::Value* chunkValue = new base::Value(chunk);
88
89 content::BrowserThread::PostTask(
90 content::BrowserThread::UI, FROM_HERE,
91 base::Bind(&ShellDevToolsFrontend::CallClientFunction,
92 shell_devtools_, "DevToolsAPI.streamWrite",
93 base::Owned(id), base::Owned(chunkValue), nullptr));
94 return num_bytes;
95 }
96
97 int ResponseWriter::Finish(int net_error,
98 const net::CompletionCallback& callback) {
99 return net::OK;
100 }
101
102 static GURL GetFrontendURL() { 20 static GURL GetFrontendURL() {
103 int port = ShellDevToolsManagerDelegate::GetHttpHandlerPort(); 21 int port = ShellDevToolsManagerDelegate::GetHttpHandlerPort();
104 return GURL( 22 return GURL(
105 base::StringPrintf("http://127.0.0.1:%d/devtools/inspector.html", port)); 23 base::StringPrintf("http://127.0.0.1:%d/devtools/inspector.html", port));
106 } 24 }
107
108 } // namespace 25 } // namespace
109 26
110 // This constant should be in sync with
111 // the constant at devtools_ui_bindings.cc.
112 const size_t kMaxMessageChunkSize = IPC::Channel::kMaximumMessageSize / 4;
113
114 // static 27 // static
115 ShellDevToolsFrontend* ShellDevToolsFrontend::Show( 28 ShellDevToolsFrontend* ShellDevToolsFrontend::Show(
116 WebContents* inspected_contents) { 29 WebContents* inspected_contents) {
117 Shell* shell = Shell::CreateNewWindow(inspected_contents->GetBrowserContext(), 30 Shell* shell = Shell::CreateNewWindow(inspected_contents->GetBrowserContext(),
118 GURL(), 31 GURL(),
119 NULL, 32 NULL,
120 gfx::Size()); 33 gfx::Size());
121 ShellDevToolsFrontend* devtools_frontend = new ShellDevToolsFrontend( 34 ShellDevToolsFrontend* devtools_frontend =
122 shell, 35 new ShellDevToolsFrontend(shell, inspected_contents);
123 inspected_contents);
124 shell->LoadURL(GetFrontendURL()); 36 shell->LoadURL(GetFrontendURL());
125 return devtools_frontend; 37 return devtools_frontend;
126 } 38 }
127 39
128 void ShellDevToolsFrontend::Activate() { 40 void ShellDevToolsFrontend::Activate() {
129 frontend_shell_->ActivateContents(web_contents()); 41 frontend_shell_->ActivateContents(frontend_shell_->web_contents());
130 } 42 }
131 43
132 void ShellDevToolsFrontend::Focus() { 44 void ShellDevToolsFrontend::Focus() {
133 web_contents()->Focus(); 45 frontend_shell_->web_contents()->Focus();
134 } 46 }
135 47
136 void ShellDevToolsFrontend::InspectElementAt(int x, int y) { 48 void ShellDevToolsFrontend::InspectElementAt(int x, int y) {
137 if (agent_host_) { 49 devtools_bindings_->InspectElementAt(x, y);
138 agent_host_->InspectElement(this, x, y);
139 } else {
140 inspect_element_at_x_ = x;
141 inspect_element_at_y_ = y;
142 }
143 } 50 }
144 51
145 void ShellDevToolsFrontend::Close() { 52 void ShellDevToolsFrontend::Close() {
146 frontend_shell_->Close(); 53 frontend_shell_->Close();
147 } 54 }
148 55
149 void ShellDevToolsFrontend::DisconnectFromTarget() { 56 void ShellDevToolsFrontend::WebContentsDestroyed() {
150 if (!agent_host_) 57 delete this;
151 return;
152 agent_host_->DetachClient(this);
153 agent_host_ = NULL;
154 } 58 }
155 59
156 ShellDevToolsFrontend::ShellDevToolsFrontend(Shell* frontend_shell, 60 ShellDevToolsFrontend::ShellDevToolsFrontend(Shell* frontend_shell,
157 WebContents* inspected_contents) 61 WebContents* inspected_contents)
158 : WebContentsObserver(frontend_shell->web_contents()), 62 : WebContentsObserver(frontend_shell->web_contents()),
159 frontend_shell_(frontend_shell), 63 frontend_shell_(frontend_shell),
160 inspected_contents_(inspected_contents), 64 devtools_bindings_(
161 inspect_element_at_x_(-1), 65 new ShellDevToolsBindings(frontend_shell->web_contents(),
162 inspect_element_at_y_(-1), 66 inspected_contents,
163 weak_factory_(this) { 67 this)) {}
164 }
165 68
166 ShellDevToolsFrontend::~ShellDevToolsFrontend() { 69 ShellDevToolsFrontend::~ShellDevToolsFrontend() {}
167 for (const auto& pair : pending_requests_)
168 delete pair.first;
169 }
170
171 #if !defined(OS_ANDROID)
172 void ShellDevToolsFrontend::RenderViewCreated(
173 RenderViewHost* render_view_host) {
174 if (!frontend_host_) {
175 frontend_host_.reset(DevToolsFrontendHost::Create(
176 web_contents()->GetMainFrame(),
177 base::Bind(&ShellDevToolsFrontend::HandleMessageFromDevToolsFrontend,
178 base::Unretained(this))));
179 }
180 }
181 #endif
182
183 #if defined(OS_ANDROID)
184 void ShellDevToolsFrontend::RenderViewCreated(
185 RenderViewHost* render_view_host) {
186 // No devtools frontend for android
187 }
188 #endif
189
190 void ShellDevToolsFrontend::DocumentAvailableInMainFrame() {
191 agent_host_ = DevToolsAgentHost::GetOrCreateFor(inspected_contents_);
192 agent_host_->AttachClient(this);
193 if (inspect_element_at_x_ != -1) {
194 agent_host_->InspectElement(
195 this, inspect_element_at_x_, inspect_element_at_y_);
196 inspect_element_at_x_ = -1;
197 inspect_element_at_y_ = -1;
198 }
199 }
200
201 void ShellDevToolsFrontend::WebContentsDestroyed() {
202 if (agent_host_)
203 agent_host_->DetachClient(this);
204 delete this;
205 }
206
207 void ShellDevToolsFrontend::SetPreferences(const std::string& json) {
208 preferences_.Clear();
209 if (json.empty())
210 return;
211 base::DictionaryValue* dict = nullptr;
212 std::unique_ptr<base::Value> parsed = base::JSONReader::Read(json);
213 if (!parsed || !parsed->GetAsDictionary(&dict))
214 return;
215 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
216 if (!it.value().IsType(base::Value::Type::STRING))
217 continue;
218 preferences_.SetWithoutPathExpansion(it.key(), it.value().CreateDeepCopy());
219 }
220 }
221
222 void ShellDevToolsFrontend::HandleMessageFromDevToolsFrontend(
223 const std::string& message) {
224 if (!agent_host_)
225 return;
226 std::string method;
227 base::ListValue* params = NULL;
228 base::DictionaryValue* dict = NULL;
229 std::unique_ptr<base::Value> parsed_message = base::JSONReader::Read(message);
230 if (!parsed_message ||
231 !parsed_message->GetAsDictionary(&dict) ||
232 !dict->GetString("method", &method)) {
233 return;
234 }
235 int request_id = 0;
236 dict->GetInteger("id", &request_id);
237 dict->GetList("params", &params);
238
239 if (method == "dispatchProtocolMessage" && params && params->GetSize() == 1) {
240 if (!agent_host_ || !agent_host_->IsAttached())
241 return;
242 std::string protocol_message;
243 if (!params->GetString(0, &protocol_message))
244 return;
245 agent_host_->DispatchProtocolMessage(this, protocol_message);
246 } else if (method == "loadCompleted") {
247 web_contents()->GetMainFrame()->ExecuteJavaScriptForTests(
248 base::ASCIIToUTF16("DevToolsAPI.setUseSoftMenu(true);"));
249 } else if (method == "loadNetworkResource" && params->GetSize() == 3) {
250 // TODO(pfeldman): handle some of the embedder messages in content.
251 std::string url;
252 std::string headers;
253 int stream_id;
254 if (!params->GetString(0, &url) ||
255 !params->GetString(1, &headers) ||
256 !params->GetInteger(2, &stream_id)) {
257 return;
258 }
259
260 GURL gurl(url);
261 if (!gurl.is_valid()) {
262 base::DictionaryValue response;
263 response.SetInteger("statusCode", 404);
264 SendMessageAck(request_id, &response);
265 return;
266 }
267
268 net::URLFetcher* fetcher =
269 net::URLFetcher::Create(gurl, net::URLFetcher::GET, this).release();
270 pending_requests_[fetcher] = request_id;
271 fetcher->SetRequestContext(
272 BrowserContext::GetDefaultStoragePartition(
273 web_contents()->GetBrowserContext())->
274 GetURLRequestContext());
275 fetcher->SetExtraRequestHeaders(headers);
276 fetcher->SaveResponseWithWriter(
277 std::unique_ptr<net::URLFetcherResponseWriter>(
278 new ResponseWriter(weak_factory_.GetWeakPtr(), stream_id)));
279 fetcher->Start();
280 return;
281 } else if (method == "getPreferences") {
282 SendMessageAck(request_id, &preferences_);
283 return;
284 } else if (method == "setPreference") {
285 std::string name;
286 std::string value;
287 if (!params->GetString(0, &name) ||
288 !params->GetString(1, &value)) {
289 return;
290 }
291 preferences_.SetStringWithoutPathExpansion(name, value);
292 } else if (method == "removePreference") {
293 std::string name;
294 if (!params->GetString(0, &name))
295 return;
296 preferences_.RemoveWithoutPathExpansion(name, nullptr);
297 } else if (method == "requestFileSystems") {
298 web_contents()->GetMainFrame()->ExecuteJavaScriptForTests(
299 base::ASCIIToUTF16("DevToolsAPI.fileSystemsLoaded([]);"));
300 } else if (method == "reattach") {
301 agent_host_->DetachClient(this);
302 agent_host_->AttachClient(this);
303 } else {
304 return;
305 }
306
307 if (request_id)
308 SendMessageAck(request_id, nullptr);
309 }
310
311 void ShellDevToolsFrontend::DispatchProtocolMessage(
312 DevToolsAgentHost* agent_host, const std::string& message) {
313
314 if (message.length() < kMaxMessageChunkSize) {
315 std::string param;
316 base::EscapeJSONString(message, true, &param);
317 std::string code = "DevToolsAPI.dispatchMessage(" + param + ");";
318 base::string16 javascript = base::UTF8ToUTF16(code);
319 web_contents()->GetMainFrame()->ExecuteJavaScriptForTests(javascript);
320 return;
321 }
322
323 size_t total_size = message.length();
324 for (size_t pos = 0; pos < message.length(); pos += kMaxMessageChunkSize) {
325 std::string param;
326 base::EscapeJSONString(message.substr(pos, kMaxMessageChunkSize), true,
327 &param);
328 std::string code = "DevToolsAPI.dispatchMessageChunk(" + param + "," +
329 std::to_string(pos ? 0 : total_size) + ");";
330 base::string16 javascript = base::UTF8ToUTF16(code);
331 web_contents()->GetMainFrame()->ExecuteJavaScriptForTests(javascript);
332 }
333 }
334
335 void ShellDevToolsFrontend::OnURLFetchComplete(const net::URLFetcher* source) {
336 // TODO(pfeldman): this is a copy of chrome's devtools_ui_bindings.cc.
337 // We should handle some of the commands including this one in content.
338 DCHECK(source);
339 PendingRequestsMap::iterator it = pending_requests_.find(source);
340 DCHECK(it != pending_requests_.end());
341
342 base::DictionaryValue response;
343 base::DictionaryValue* headers = new base::DictionaryValue();
344 net::HttpResponseHeaders* rh = source->GetResponseHeaders();
345 response.SetInteger("statusCode", rh ? rh->response_code() : 200);
346 response.Set("headers", headers);
347
348 size_t iterator = 0;
349 std::string name;
350 std::string value;
351 while (rh && rh->EnumerateHeaderLines(&iterator, &name, &value))
352 headers->SetString(name, value);
353
354 SendMessageAck(it->second, &response);
355 pending_requests_.erase(it);
356 delete source;
357 }
358
359 void ShellDevToolsFrontend::CallClientFunction(
360 const std::string& function_name,
361 const base::Value* arg1,
362 const base::Value* arg2,
363 const base::Value* arg3) {
364 std::string javascript = function_name + "(";
365 if (arg1) {
366 std::string json;
367 base::JSONWriter::Write(*arg1, &json);
368 javascript.append(json);
369 if (arg2) {
370 base::JSONWriter::Write(*arg2, &json);
371 javascript.append(", ").append(json);
372 if (arg3) {
373 base::JSONWriter::Write(*arg3, &json);
374 javascript.append(", ").append(json);
375 }
376 }
377 }
378 javascript.append(");");
379 web_contents()->GetMainFrame()->ExecuteJavaScriptForTests(
380 base::UTF8ToUTF16(javascript));
381 }
382
383 void ShellDevToolsFrontend::SendMessageAck(int request_id,
384 const base::Value* arg) {
385 base::Value id_value(request_id);
386 CallClientFunction("DevToolsAPI.embedderMessageAck",
387 &id_value, arg, nullptr);
388 }
389
390 void ShellDevToolsFrontend::AgentHostClosed(
391 DevToolsAgentHost* agent_host, bool replaced) {
392 agent_host_ = nullptr;
393 frontend_shell_->Close();
394 }
395 70
396 } // namespace content 71 } // namespace content
OLDNEW
« no previous file with comments | « content/shell/browser/shell_devtools_frontend.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698