Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / devtools / devtools_browser_target.cc
blob2fe1014a8ce580a6928d63c167863e1ce8323682
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(net::HttpServer* http_server,
21 int connection_id)
22 : message_loop_proxy_(base::MessageLoopProxy::current()),
23 http_server_(http_server),
24 connection_id_(connection_id),
25 weak_factory_(this) {
28 void DevToolsBrowserTarget::RegisterDomainHandler(
29 const std::string& domain,
30 DevToolsProtocol::Handler* handler,
31 bool handle_on_ui_thread) {
32 DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current());
34 DCHECK(handlers_.find(domain) == handlers_.end());
35 handlers_[domain] = handler;
36 if (handle_on_ui_thread) {
37 handle_on_ui_thread_.insert(domain);
38 handler->SetNotifier(base::Bind(&DevToolsBrowserTarget::RespondFromUIThread,
39 weak_factory_.GetWeakPtr()));
40 } else {
41 handler->SetNotifier(base::Bind(&DevToolsBrowserTarget::Respond,
42 base::Unretained(this)));
46 typedef std::map<std::string, DevToolsBrowserTarget*> DomainMap;
47 base::LazyInstance<DomainMap>::Leaky g_used_domains = LAZY_INSTANCE_INITIALIZER;
49 void DevToolsBrowserTarget::HandleMessage(const std::string& data) {
50 DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current());
51 std::string error_response;
52 scoped_refptr<DevToolsProtocol::Command> command =
53 DevToolsProtocol::ParseCommand(data, &error_response);
54 if (!command.get()) {
55 Respond(error_response);
56 return;
59 DomainHandlerMap::iterator it = handlers_.find(command->domain());
60 if (it == handlers_.end()) {
61 Respond(command->NoSuchMethodErrorResponse()->Serialize());
62 return;
64 DomainMap& used_domains(g_used_domains.Get());
65 std::string domain = command->domain();
66 DomainMap::iterator jt = used_domains.find(domain);
67 if (jt == used_domains.end()) {
68 used_domains[domain] = this;
69 } else if (jt->second != this) {
70 std::string message =
71 base::StringPrintf("'%s' is held by another connection",
72 domain.c_str());
73 Respond(command->ServerErrorResponse(message)->Serialize());
74 return;
77 DevToolsProtocol::Handler* handler = it->second;
78 bool handle_directly = handle_on_ui_thread_.find(domain) ==
79 handle_on_ui_thread_.end();
80 if (handle_directly) {
81 scoped_refptr<DevToolsProtocol::Response> response =
82 handler->HandleCommand(command);
83 if (response.get() && response->is_async_promise())
84 return;
85 if (response.get())
86 Respond(response->Serialize());
87 else
88 Respond(command->NoSuchMethodErrorResponse()->Serialize());
89 return;
92 BrowserThread::PostTask(
93 BrowserThread::UI,
94 FROM_HERE,
95 base::Bind(&DevToolsBrowserTarget::HandleCommandOnUIThread,
96 this,
97 handler,
98 command));
101 void DevToolsBrowserTarget::Detach() {
102 DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current());
103 DCHECK(http_server_);
105 http_server_ = NULL;
107 DomainMap& used_domains(g_used_domains.Get());
108 for (DomainMap::iterator it = used_domains.begin();
109 it != used_domains.end();) {
110 if (it->second == this) {
111 DomainMap::iterator to_erase = it;
112 ++it;
113 used_domains.erase(to_erase);
114 } else {
115 ++it;
119 std::vector<DevToolsProtocol::Handler*> ui_handlers;
120 for (std::set<std::string>::iterator domain_it = handle_on_ui_thread_.begin();
121 domain_it != handle_on_ui_thread_.end();
122 ++domain_it) {
123 DomainHandlerMap::iterator handler_it = handlers_.find(*domain_it);
124 CHECK(handler_it != handlers_.end());
125 ui_handlers.push_back(handler_it->second);
126 handlers_.erase(handler_it);
129 STLDeleteValues(&handlers_);
131 BrowserThread::PostTask(
132 BrowserThread::UI,
133 FROM_HERE,
134 base::Bind(&DevToolsBrowserTarget::DeleteHandlersOnUIThread,
135 this,
136 ui_handlers));
139 DevToolsBrowserTarget::~DevToolsBrowserTarget() {
140 // DCHECK that Detach has been called or no handler has ever been registered.
141 DCHECK(handlers_.empty());
144 void DevToolsBrowserTarget::HandleCommandOnUIThread(
145 DevToolsProtocol::Handler* handler,
146 scoped_refptr<DevToolsProtocol::Command> command) {
147 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
148 scoped_refptr<DevToolsProtocol::Response> response =
149 handler->HandleCommand(command);
150 if (response.get() && response->is_async_promise())
151 return;
153 if (response.get())
154 RespondFromUIThread(response->Serialize());
155 else
156 RespondFromUIThread(command->NoSuchMethodErrorResponse()->Serialize());
159 void DevToolsBrowserTarget::DeleteHandlersOnUIThread(
160 std::vector<DevToolsProtocol::Handler*> handlers) {
161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
162 STLDeleteElements(&handlers);
165 void DevToolsBrowserTarget::Respond(const std::string& message) {
166 DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current());
167 if (!http_server_)
168 return;
169 http_server_->SendOverWebSocket(connection_id_, message);
172 void DevToolsBrowserTarget::RespondFromUIThread(const std::string& message) {
173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
174 message_loop_proxy_->PostTask(
175 FROM_HERE,
176 base::Bind(&DevToolsBrowserTarget::Respond, this, message));
179 } // namespace content