12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/devtools/devtools_browser_target.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/lazy_instance.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/location.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
12a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "base/stl_util.h"
13116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/strings/stringprintf.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "content/public/browser/browser_thread.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/server/http_server.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace content {
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciDevToolsBrowserTarget::DevToolsBrowserTarget(net::HttpServer* http_server,
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                             int connection_id)
22a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    : message_loop_proxy_(base::MessageLoopProxy::current()),
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      http_server_(http_server),
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      connection_id_(connection_id),
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_factory_(this) {
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsBrowserTarget::RegisterDomainHandler(
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& domain,
307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DevToolsProtocol::Handler* handler,
317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    bool handle_on_ui_thread) {
32a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current());
33a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(handlers_.find(domain) == handlers_.end());
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  handlers_[domain] = handler;
367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (handle_on_ui_thread) {
377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    handle_on_ui_thread_.insert(domain);
387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    handler->SetNotifier(base::Bind(&DevToolsBrowserTarget::RespondFromUIThread,
397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                    weak_factory_.GetWeakPtr()));
407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  } else {
417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    handler->SetNotifier(base::Bind(&DevToolsBrowserTarget::Respond,
427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                    base::Unretained(this)));
437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdochtypedef std::map<std::string, DevToolsBrowserTarget*> DomainMap;
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbase::LazyInstance<DomainMap>::Leaky g_used_domains = LAZY_INSTANCE_INITIALIZER;
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid DevToolsBrowserTarget::HandleMessage(const std::string& data) {
50a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current());
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string error_response;
52bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  scoped_refptr<DevToolsProtocol::Command> command =
53bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      DevToolsProtocol::ParseCommand(data, &error_response);
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!command.get()) {
557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    Respond(error_response);
567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DomainHandlerMap::iterator it = handlers_.find(command->domain());
607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (it == handlers_.end()) {
617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    Respond(command->NoSuchMethodErrorResponse()->Serialize());
627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DomainMap& used_domains(g_used_domains.Get());
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::string domain = command->domain();
66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DomainMap::iterator jt = used_domains.find(domain);
67116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (jt == used_domains.end()) {
68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    used_domains[domain] = this;
69116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else if (jt->second != this) {
70116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    std::string message =
71116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        base::StringPrintf("'%s' is held by another connection",
72116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           domain.c_str());
73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    Respond(command->ServerErrorResponse(message)->Serialize());
74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DevToolsProtocol::Handler* handler = it->second;
78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool handle_directly = handle_on_ui_thread_.find(domain) ==
797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      handle_on_ui_thread_.end();
807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (handle_directly) {
81bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    scoped_refptr<DevToolsProtocol::Response> response =
82bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        handler->HandleCommand(command);
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (response.get() && response->is_async_promise())
84bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      return;
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (response.get())
867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      Respond(response->Serialize());
877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    else
887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      Respond(command->NoSuchMethodErrorResponse()->Serialize());
897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
923240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  BrowserThread::PostTask(
937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      BrowserThread::UI,
947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      FROM_HERE,
957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::Bind(&DevToolsBrowserTarget::HandleCommandOnUIThread,
967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                 this,
977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                 handler,
98bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                 command));
997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid DevToolsBrowserTarget::Detach() {
102a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current());
103a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK(http_server_);
104a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
1057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  http_server_ = NULL;
1067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DomainMap& used_domains(g_used_domains.Get());
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (DomainMap::iterator it = used_domains.begin();
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       it != used_domains.end();) {
110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (it->second == this) {
111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      DomainMap::iterator to_erase = it;
112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ++it;
113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      used_domains.erase(to_erase);
114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    } else {
115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ++it;
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
118116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  std::vector<DevToolsProtocol::Handler*> ui_handlers;
1207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  for (std::set<std::string>::iterator domain_it = handle_on_ui_thread_.begin();
1217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch       domain_it != handle_on_ui_thread_.end();
1227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch       ++domain_it) {
1237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DomainHandlerMap::iterator handler_it = handlers_.find(*domain_it);
1247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    CHECK(handler_it != handlers_.end());
1257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ui_handlers.push_back(handler_it->second);
1267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    handlers_.erase(handler_it);
1277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
1287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
129a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  STLDeleteValues(&handlers_);
130a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
1313240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  BrowserThread::PostTask(
1327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      BrowserThread::UI,
1337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      FROM_HERE,
1347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::Bind(&DevToolsBrowserTarget::DeleteHandlersOnUIThread,
1357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                 this,
1363240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                 ui_handlers));
1377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1397dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochDevToolsBrowserTarget::~DevToolsBrowserTarget() {
140a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // DCHECK that Detach has been called or no handler has ever been registered.
141a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK(handlers_.empty());
1427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid DevToolsBrowserTarget::HandleCommandOnUIThread(
1457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DevToolsProtocol::Handler* handler,
146bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    scoped_refptr<DevToolsProtocol::Command> command) {
147a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
148bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  scoped_refptr<DevToolsProtocol::Response> response =
149bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      handler->HandleCommand(command);
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (response.get() && response->is_async_promise())
151bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    return;
152bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (response.get())
1547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    RespondFromUIThread(response->Serialize());
1557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  else
1567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    RespondFromUIThread(command->NoSuchMethodErrorResponse()->Serialize());
1577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid DevToolsBrowserTarget::DeleteHandlersOnUIThread(
1607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    std::vector<DevToolsProtocol::Handler*> handlers) {
161a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  STLDeleteElements(&handlers);
1637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid DevToolsBrowserTarget::Respond(const std::string& message) {
166a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current());
1677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!http_server_)
1687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
1697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  http_server_->SendOverWebSocket(connection_id_, message);
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid DevToolsBrowserTarget::RespondFromUIThread(const std::string& message) {
173a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  message_loop_proxy_->PostTask(
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
1767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::Bind(&DevToolsBrowserTarget::Respond, this, message));
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace content
180