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. 4 5 #include "content/browser/devtools/devtools_browser_target.h" 6 7 #include "base/bind.h" 8 #include "base/location.h" 9 #include "base/logging.h" 10 #include "base/message_loop/message_loop_proxy.h" 11 #include "base/values.h" 12 #include "content/public/browser/browser_thread.h" 13 #include "net/server/http_server.h" 14 15 namespace content { 16 17 DevToolsBrowserTarget::DevToolsBrowserTarget( 18 base::MessageLoopProxy* message_loop_proxy, 19 net::HttpServer* http_server, 20 int connection_id) 21 : message_loop_proxy_(message_loop_proxy), 22 http_server_(http_server), 23 connection_id_(connection_id), 24 handlers_deleter_(&handlers_), 25 weak_factory_(this) { 26 } 27 28 void DevToolsBrowserTarget::RegisterDomainHandler( 29 const std::string& domain, 30 DevToolsProtocol::Handler* handler, 31 bool handle_on_ui_thread) { 32 DCHECK(handlers_.find(domain) == handlers_.end()); 33 handlers_[domain] = handler; 34 if (handle_on_ui_thread) { 35 handle_on_ui_thread_.insert(domain); 36 handler->SetNotifier(base::Bind(&DevToolsBrowserTarget::RespondFromUIThread, 37 weak_factory_.GetWeakPtr())); 38 } else { 39 handler->SetNotifier(base::Bind(&DevToolsBrowserTarget::Respond, 40 base::Unretained(this))); 41 } 42 } 43 44 void DevToolsBrowserTarget::HandleMessage(const std::string& data) { 45 std::string error_response; 46 scoped_refptr<DevToolsProtocol::Command> command = 47 DevToolsProtocol::ParseCommand(data, &error_response); 48 if (!command) { 49 Respond(error_response); 50 return; 51 } 52 53 DomainHandlerMap::iterator it = handlers_.find(command->domain()); 54 if (it == handlers_.end()) { 55 Respond(command->NoSuchMethodErrorResponse()->Serialize()); 56 return; 57 } 58 59 DevToolsProtocol::Handler* handler = it->second; 60 bool handle_directly = handle_on_ui_thread_.find(command->domain()) == 61 handle_on_ui_thread_.end(); 62 if (handle_directly) { 63 scoped_refptr<DevToolsProtocol::Response> response = 64 handler->HandleCommand(command); 65 if (response && response->is_async_promise()) 66 return; 67 if (response) 68 Respond(response->Serialize()); 69 else 70 Respond(command->NoSuchMethodErrorResponse()->Serialize()); 71 return; 72 } 73 74 BrowserThread::PostTask( 75 BrowserThread::UI, 76 FROM_HERE, 77 base::Bind(&DevToolsBrowserTarget::HandleCommandOnUIThread, 78 this, 79 handler, 80 command)); 81 } 82 83 void DevToolsBrowserTarget::Detach() { 84 message_loop_proxy_ = NULL; 85 http_server_ = NULL; 86 87 std::vector<DevToolsProtocol::Handler*> ui_handlers; 88 for (std::set<std::string>::iterator domain_it = handle_on_ui_thread_.begin(); 89 domain_it != handle_on_ui_thread_.end(); 90 ++domain_it) { 91 DomainHandlerMap::iterator handler_it = handlers_.find(*domain_it); 92 CHECK(handler_it != handlers_.end()); 93 ui_handlers.push_back(handler_it->second); 94 handlers_.erase(handler_it); 95 } 96 97 BrowserThread::PostTask( 98 BrowserThread::UI, 99 FROM_HERE, 100 base::Bind(&DevToolsBrowserTarget::DeleteHandlersOnUIThread, 101 this, 102 ui_handlers)); 103 } 104 105 DevToolsBrowserTarget::~DevToolsBrowserTarget() { 106 } 107 108 void DevToolsBrowserTarget::HandleCommandOnUIThread( 109 DevToolsProtocol::Handler* handler, 110 scoped_refptr<DevToolsProtocol::Command> command) { 111 scoped_refptr<DevToolsProtocol::Response> response = 112 handler->HandleCommand(command); 113 if (response && response->is_async_promise()) 114 return; 115 116 if (response) 117 RespondFromUIThread(response->Serialize()); 118 else 119 RespondFromUIThread(command->NoSuchMethodErrorResponse()->Serialize()); 120 } 121 122 void DevToolsBrowserTarget::DeleteHandlersOnUIThread( 123 std::vector<DevToolsProtocol::Handler*> handlers) { 124 STLDeleteElements(&handlers); 125 } 126 127 void DevToolsBrowserTarget::Respond(const std::string& message) { 128 if (!http_server_) 129 return; 130 http_server_->SendOverWebSocket(connection_id_, message); 131 } 132 133 void DevToolsBrowserTarget::RespondFromUIThread(const std::string& message) { 134 if (!message_loop_proxy_) 135 return; 136 message_loop_proxy_->PostTask( 137 FROM_HERE, 138 base::Bind(&DevToolsBrowserTarget::Respond, this, message)); 139 } 140 141 } // namespace content 142