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