Give names to all utility processes.
[chromium-blink-merge.git] / content / shell / browser / shell_devtools_frontend.cc
bloba80490d48438b21ee9ea7e0f14f5646ca87319d2
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
3 // found in the LICENSE file.
5 #include "content/shell/browser/shell_devtools_frontend.h"
7 #include "base/command_line.h"
8 #include "base/json/json_reader.h"
9 #include "base/json/json_writer.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/devtools_http_handler.h"
16 #include "content/public/browser/render_frame_host.h"
17 #include "content/public/browser/render_view_host.h"
18 #include "content/public/browser/web_contents.h"
19 #include "content/public/common/content_client.h"
20 #include "content/shell/browser/shell.h"
21 #include "content/shell/browser/shell_browser_context.h"
22 #include "content/shell/browser/shell_browser_main_parts.h"
23 #include "content/shell/browser/shell_content_browser_client.h"
24 #include "content/shell/browser/shell_devtools_manager_delegate.h"
25 #include "content/shell/browser/webkit_test_controller.h"
26 #include "content/shell/common/shell_switches.h"
27 #include "net/base/io_buffer.h"
28 #include "net/base/net_errors.h"
29 #include "net/http/http_response_headers.h"
30 #include "net/url_request/url_fetcher.h"
31 #include "net/url_request/url_fetcher_response_writer.h"
33 namespace content {
35 namespace {
38 // ResponseWriter -------------------------------------------------------------
40 class ResponseWriter : public net::URLFetcherResponseWriter {
41 public:
42 ResponseWriter(base::WeakPtr<ShellDevToolsFrontend> shell_devtools_,
43 int stream_id);
44 ~ResponseWriter() override;
46 // URLFetcherResponseWriter overrides:
47 int Initialize(const net::CompletionCallback& callback) override;
48 int Write(net::IOBuffer* buffer,
49 int num_bytes,
50 const net::CompletionCallback& callback) override;
51 int Finish(const net::CompletionCallback& callback) override;
53 private:
54 base::WeakPtr<ShellDevToolsFrontend> shell_devtools_;
55 int stream_id_;
57 DISALLOW_COPY_AND_ASSIGN(ResponseWriter);
60 ResponseWriter::ResponseWriter(
61 base::WeakPtr<ShellDevToolsFrontend> shell_devtools,
62 int stream_id)
63 : shell_devtools_(shell_devtools),
64 stream_id_(stream_id) {
67 ResponseWriter::~ResponseWriter() {
70 int ResponseWriter::Initialize(const net::CompletionCallback& callback) {
71 return net::OK;
74 int ResponseWriter::Write(net::IOBuffer* buffer,
75 int num_bytes,
76 const net::CompletionCallback& callback) {
77 base::FundamentalValue* id = new base::FundamentalValue(stream_id_);
78 base::StringValue* chunk =
79 new base::StringValue(std::string(buffer->data(), num_bytes));
81 content::BrowserThread::PostTask(
82 content::BrowserThread::UI, FROM_HERE,
83 base::Bind(&ShellDevToolsFrontend::CallClientFunction,
84 shell_devtools_, "DevToolsAPI.streamWrite",
85 base::Owned(id), base::Owned(chunk), nullptr));
86 return num_bytes;
89 int ResponseWriter::Finish(const net::CompletionCallback& callback) {
90 return net::OK;
93 } // namespace
95 // This constant should be in sync with
96 // the constant at devtools_ui_bindings.cc.
97 const size_t kMaxMessageChunkSize = IPC::Channel::kMaximumMessageSize / 4;
99 // static
100 ShellDevToolsFrontend* ShellDevToolsFrontend::Show(
101 WebContents* inspected_contents) {
102 Shell* shell = Shell::CreateNewWindow(inspected_contents->GetBrowserContext(),
103 GURL(),
104 NULL,
105 gfx::Size());
106 ShellDevToolsFrontend* devtools_frontend = new ShellDevToolsFrontend(
107 shell,
108 inspected_contents);
110 DevToolsHttpHandler* http_handler = ShellContentBrowserClient::Get()
111 ->shell_browser_main_parts()
112 ->devtools_http_handler();
113 shell->LoadURL(http_handler->GetFrontendURL("/devtools/devtools.html"));
115 return devtools_frontend;
118 void ShellDevToolsFrontend::Activate() {
119 frontend_shell_->ActivateContents(web_contents());
122 void ShellDevToolsFrontend::Focus() {
123 web_contents()->Focus();
126 void ShellDevToolsFrontend::InspectElementAt(int x, int y) {
127 if (agent_host_)
128 agent_host_->InspectElement(x, y);
131 void ShellDevToolsFrontend::Close() {
132 frontend_shell_->Close();
135 void ShellDevToolsFrontend::DisconnectFromTarget() {
136 if (!agent_host_)
137 return;
138 agent_host_->DetachClient();
139 agent_host_ = NULL;
142 ShellDevToolsFrontend::ShellDevToolsFrontend(Shell* frontend_shell,
143 WebContents* inspected_contents)
144 : WebContentsObserver(frontend_shell->web_contents()),
145 frontend_shell_(frontend_shell),
146 inspected_contents_(inspected_contents),
147 weak_factory_(this) {
150 ShellDevToolsFrontend::~ShellDevToolsFrontend() {
151 for (const auto& pair : pending_requests_)
152 delete pair.first;
155 void ShellDevToolsFrontend::RenderViewCreated(
156 RenderViewHost* render_view_host) {
157 if (!frontend_host_) {
158 frontend_host_.reset(
159 DevToolsFrontendHost::Create(web_contents()->GetMainFrame(), this));
163 void ShellDevToolsFrontend::DocumentAvailableInMainFrame() {
164 agent_host_ = DevToolsAgentHost::GetOrCreateFor(inspected_contents_);
165 agent_host_->AttachClient(this);
168 void ShellDevToolsFrontend::WebContentsDestroyed() {
169 if (agent_host_)
170 agent_host_->DetachClient();
171 delete this;
174 void ShellDevToolsFrontend::HandleMessageFromDevToolsFrontend(
175 const std::string& message) {
176 if (!agent_host_)
177 return;
178 std::string method;
179 base::ListValue* params = NULL;
180 base::DictionaryValue* dict = NULL;
181 scoped_ptr<base::Value> parsed_message(base::JSONReader::Read(message));
182 if (!parsed_message ||
183 !parsed_message->GetAsDictionary(&dict) ||
184 !dict->GetString("method", &method)) {
185 return;
187 int request_id = 0;
188 dict->GetInteger("id", &request_id);
189 dict->GetList("params", &params);
191 std::string browser_message;
192 if (method == "sendMessageToBrowser" && params &&
193 params->GetSize() == 1 && params->GetString(0, &browser_message)) {
194 agent_host_->DispatchProtocolMessage(browser_message);
195 } else if (method == "loadCompleted") {
196 web_contents()->GetMainFrame()->ExecuteJavaScript(
197 base::ASCIIToUTF16("DevToolsAPI.setUseSoftMenu(true);"));
198 } else if (method == "loadNetworkResource" && params->GetSize() == 3) {
199 // TODO(pfeldman): handle some of the embedder messages in content.
200 std::string url;
201 std::string headers;
202 int stream_id;
203 if (!params->GetString(0, &url) ||
204 !params->GetString(1, &headers) ||
205 !params->GetInteger(2, &stream_id)) {
206 return;
209 GURL gurl(url);
210 if (!gurl.is_valid()) {
211 base::DictionaryValue response;
212 response.SetInteger("statusCode", 404);
213 SendMessageAck(request_id, &response);
214 return;
217 net::URLFetcher* fetcher =
218 net::URLFetcher::Create(gurl, net::URLFetcher::GET, this);
219 pending_requests_[fetcher] = request_id;
220 fetcher->SetRequestContext(web_contents()->GetBrowserContext()->
221 GetRequestContext());
222 fetcher->SetExtraRequestHeaders(headers);
223 fetcher->SaveResponseWithWriter(scoped_ptr<net::URLFetcherResponseWriter>(
224 new ResponseWriter(weak_factory_.GetWeakPtr(), stream_id)));
225 fetcher->Start();
226 return;
227 } else {
228 return;
231 if (request_id)
232 SendMessageAck(request_id, nullptr);
235 void ShellDevToolsFrontend::HandleMessageFromDevToolsFrontendToBackend(
236 const std::string& message) {
237 if (agent_host_)
238 agent_host_->DispatchProtocolMessage(message);
241 void ShellDevToolsFrontend::DispatchProtocolMessage(
242 DevToolsAgentHost* agent_host, const std::string& message) {
244 if (message.length() < kMaxMessageChunkSize) {
245 base::string16 javascript = base::UTF8ToUTF16(
246 "DevToolsAPI.dispatchMessage(" + message + ");");
247 web_contents()->GetMainFrame()->ExecuteJavaScript(javascript);
248 return;
251 base::FundamentalValue total_size(static_cast<int>(message.length()));
252 for (size_t pos = 0; pos < message.length(); pos += kMaxMessageChunkSize) {
253 base::StringValue message_value(message.substr(pos, kMaxMessageChunkSize));
254 std::string param;
255 base::JSONWriter::Write(&message_value, &param);
256 std::string code = "DevToolsAPI.dispatchMessageChunk(" + param + ");";
257 base::string16 javascript = base::UTF8ToUTF16(code);
258 web_contents()->GetMainFrame()->ExecuteJavaScript(javascript);
262 void ShellDevToolsFrontend::OnURLFetchComplete(const net::URLFetcher* source) {
263 // TODO(pfeldman): this is a copy of chrome's devtools_ui_bindings.cc.
264 // We should handle some of the commands including this one in content.
265 DCHECK(source);
266 PendingRequestsMap::iterator it = pending_requests_.find(source);
267 DCHECK(it != pending_requests_.end());
269 base::DictionaryValue response;
270 base::DictionaryValue* headers = new base::DictionaryValue();
271 net::HttpResponseHeaders* rh = source->GetResponseHeaders();
272 response.SetInteger("statusCode", rh ? rh->response_code() : 200);
273 response.Set("headers", headers);
275 void* iterator = NULL;
276 std::string name;
277 std::string value;
278 while (rh && rh->EnumerateHeaderLines(&iterator, &name, &value))
279 headers->SetString(name, value);
281 SendMessageAck(it->second, &response);
282 pending_requests_.erase(it);
283 delete source;
286 void ShellDevToolsFrontend::CallClientFunction(
287 const std::string& function_name,
288 const base::Value* arg1,
289 const base::Value* arg2,
290 const base::Value* arg3) {
291 std::string javascript = function_name + "(";
292 if (arg1) {
293 std::string json;
294 base::JSONWriter::Write(arg1, &json);
295 javascript.append(json);
296 if (arg2) {
297 base::JSONWriter::Write(arg2, &json);
298 javascript.append(", ").append(json);
299 if (arg3) {
300 base::JSONWriter::Write(arg3, &json);
301 javascript.append(", ").append(json);
305 javascript.append(");");
306 web_contents()->GetMainFrame()->ExecuteJavaScript(
307 base::UTF8ToUTF16(javascript));
310 void ShellDevToolsFrontend::SendMessageAck(int request_id,
311 const base::Value* arg) {
312 base::FundamentalValue id_value(request_id);
313 CallClientFunction("DevToolsAPI.embedderMessageAck",
314 &id_value, arg, nullptr);
317 void ShellDevToolsFrontend::AgentHostClosed(
318 DevToolsAgentHost* agent_host, bool replaced) {
319 frontend_shell_->Close();
322 } // namespace content