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"
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"
20 DevToolsBrowserTarget::DevToolsBrowserTarget(
21 net::HttpServer
* http_server
,
23 : message_loop_proxy_(base::MessageLoopProxy::current()),
24 http_server_(http_server
),
25 connection_id_(connection_id
),
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()));
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
);
56 Respond(error_response
);
60 DomainHandlerMap::iterator it
= handlers_
.find(command
->domain());
61 if (it
== handlers_
.end()) {
62 Respond(command
->NoSuchMethodErrorResponse()->Serialize());
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) {
72 base::StringPrintf("'%s' is held by another connection",
74 Respond(command
->ServerErrorResponse(message
)->Serialize());
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())
87 Respond(response
->Serialize());
89 Respond(command
->NoSuchMethodErrorResponse()->Serialize());
93 BrowserThread::PostTask(
96 base::Bind(&DevToolsBrowserTarget::HandleCommandOnUIThread
,
102 void DevToolsBrowserTarget::Detach() {
103 DCHECK_EQ(message_loop_proxy_
, base::MessageLoopProxy::current());
104 DCHECK(http_server_
);
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
;
114 used_domains
.erase(to_erase
);
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();
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(
135 base::Bind(&DevToolsBrowserTarget::DeleteHandlersOnUIThread
,
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())
155 RespondFromUIThread(response
->Serialize());
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());
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(
177 base::Bind(&DevToolsBrowserTarget::Respond
, this, message
));
180 } // namespace content