Add a FrameHostMsg_BeginNavigation IPC
[chromium-blink-merge.git] / content / browser / devtools / devtools_browser_target.cc
blobb050152d2e405d80b063e5b6863831fb6a7d3480
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
3 // found in the LICENSE file.
5 #include "content/browser/devtools/devtools_browser_target.h"
7 #include "base/bind.h"
8 #include "base/lazy_instance.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/stl_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/values.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "net/server/http_server.h"
18 namespace content {
20 DevToolsBrowserTarget::DevToolsBrowserTarget(
21 net::HttpServer* http_server,
22 int connection_id)
23 : message_loop_proxy_(base::MessageLoopProxy::current()),
24 http_server_(http_server),
25 connection_id_(connection_id),
26 weak_factory_(this) {
29 void DevToolsBrowserTarget::RegisterDomainHandler(
30 const std::string& domain,
31 DevToolsProtocol::Handler* handler,
32 bool handle_on_ui_thread) {
33 DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current());
35 DCHECK(handlers_.find(domain) == handlers_.end());
36 handlers_[domain] = handler;
37 if (handle_on_ui_thread) {
38 handle_on_ui_thread_.insert(domain);
39 handler->SetNotifier(base::Bind(&DevToolsBrowserTarget::RespondFromUIThread,
40 weak_factory_.GetWeakPtr()));
41 } else {
42 handler->SetNotifier(base::Bind(&DevToolsBrowserTarget::Respond,
43 base::Unretained(this)));
47 typedef std::map<std::string, DevToolsBrowserTarget*> DomainMap;
48 base::LazyInstance<DomainMap>::Leaky g_used_domains = LAZY_INSTANCE_INITIALIZER;
50 void DevToolsBrowserTarget::HandleMessage(const std::string& data) {
51 DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current());
52 std::string error_response;
53 scoped_refptr<DevToolsProtocol::Command> command =
54 DevToolsProtocol::ParseCommand(data, &error_response);
55 if (!command) {
56 Respond(error_response);
57 return;
60 DomainHandlerMap::iterator it = handlers_.find(command->domain());
61 if (it == handlers_.end()) {
62 Respond(command->NoSuchMethodErrorResponse()->Serialize());
63 return;
65 DomainMap& used_domains(g_used_domains.Get());
66 std::string domain = command->domain();
67 DomainMap::iterator jt = used_domains.find(domain);
68 if (jt == used_domains.end()) {
69 used_domains[domain] = this;
70 } else if (jt->second != this) {
71 std::string message =
72 base::StringPrintf("'%s' is held by another connection",
73 domain.c_str());
74 Respond(command->ServerErrorResponse(message)->Serialize());
75 return;
78 DevToolsProtocol::Handler* handler = it->second;
79 bool handle_directly = handle_on_ui_thread_.find(domain) ==
80 handle_on_ui_thread_.end();
81 if (handle_directly) {
82 scoped_refptr<DevToolsProtocol::Response> response =
83 handler->HandleCommand(command);
84 if (response && response->is_async_promise())
85 return;
86 if (response)
87 Respond(response->Serialize());
88 else
89 Respond(command->NoSuchMethodErrorResponse()->Serialize());
90 return;
93 BrowserThread::PostTask(
94 BrowserThread::UI,
95 FROM_HERE,
96 base::Bind(&DevToolsBrowserTarget::HandleCommandOnUIThread,
97 this,
98 handler,
99 command));
102 void DevToolsBrowserTarget::Detach() {
103 DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current());
104 DCHECK(http_server_);
106 http_server_ = NULL;
108 DomainMap& used_domains(g_used_domains.Get());
109 for (DomainMap::iterator it = used_domains.begin();
110 it != used_domains.end();) {
111 if (it->second == this) {
112 DomainMap::iterator to_erase = it;
113 ++it;
114 used_domains.erase(to_erase);
115 } else {
116 ++it;
120 std::vector<DevToolsProtocol::Handler*> ui_handlers;
121 for (std::set<std::string>::iterator domain_it = handle_on_ui_thread_.begin();
122 domain_it != handle_on_ui_thread_.end();
123 ++domain_it) {
124 DomainHandlerMap::iterator handler_it = handlers_.find(*domain_it);
125 CHECK(handler_it != handlers_.end());
126 ui_handlers.push_back(handler_it->second);
127 handlers_.erase(handler_it);
130 STLDeleteValues(&handlers_);
132 BrowserThread::PostTask(
133 BrowserThread::UI,
134 FROM_HERE,
135 base::Bind(&DevToolsBrowserTarget::DeleteHandlersOnUIThread,
136 this,
137 ui_handlers));
140 DevToolsBrowserTarget::~DevToolsBrowserTarget() {
141 // DCHECK that Detach has been called or no handler has ever been registered.
142 DCHECK(handlers_.empty());
145 void DevToolsBrowserTarget::HandleCommandOnUIThread(
146 DevToolsProtocol::Handler* handler,
147 scoped_refptr<DevToolsProtocol::Command> command) {
148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
149 scoped_refptr<DevToolsProtocol::Response> response =
150 handler->HandleCommand(command);
151 if (response && response->is_async_promise())
152 return;
154 if (response)
155 RespondFromUIThread(response->Serialize());
156 else
157 RespondFromUIThread(command->NoSuchMethodErrorResponse()->Serialize());
160 void DevToolsBrowserTarget::DeleteHandlersOnUIThread(
161 std::vector<DevToolsProtocol::Handler*> handlers) {
162 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
163 STLDeleteElements(&handlers);
166 void DevToolsBrowserTarget::Respond(const std::string& message) {
167 DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current());
168 if (!http_server_)
169 return;
170 http_server_->SendOverWebSocket(connection_id_, message);
173 void DevToolsBrowserTarget::RespondFromUIThread(const std::string& message) {
174 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
175 message_loop_proxy_->PostTask(
176 FROM_HERE,
177 base::Bind(&DevToolsBrowserTarget::Respond, this, message));
180 } // namespace content