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(net::HttpServer
* http_server
,
22 : message_loop_proxy_(base::MessageLoopProxy::current()),
23 http_server_(http_server
),
24 connection_id_(connection_id
),
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()));
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
);
55 Respond(error_response
);
59 DomainHandlerMap::iterator it
= handlers_
.find(command
->domain());
60 if (it
== handlers_
.end()) {
61 Respond(command
->NoSuchMethodErrorResponse()->Serialize());
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) {
71 base::StringPrintf("'%s' is held by another connection",
73 Respond(command
->ServerErrorResponse(message
)->Serialize());
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())
86 Respond(response
->Serialize());
88 Respond(command
->NoSuchMethodErrorResponse()->Serialize());
92 BrowserThread::PostTask(
95 base::Bind(&DevToolsBrowserTarget::HandleCommandOnUIThread
,
101 void DevToolsBrowserTarget::Detach() {
102 DCHECK_EQ(message_loop_proxy_
, base::MessageLoopProxy::current());
103 DCHECK(http_server_
);
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
;
113 used_domains
.erase(to_erase
);
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();
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(
134 base::Bind(&DevToolsBrowserTarget::DeleteHandlersOnUIThread
,
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())
154 RespondFromUIThread(response
->Serialize());
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());
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(
176 base::Bind(&DevToolsBrowserTarget::Respond
, this, message
));
179 } // namespace content