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_http_handler_impl.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <algorithm>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <utility>
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/compiler_specific.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/json/json_writer.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/stl_util.h"
17f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/devtools/devtools_browser_target.h"
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/browser/devtools/devtools_manager.h"
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/browser/devtools/devtools_protocol.h"
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/browser/devtools/devtools_protocol_constants.h"
243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/browser/devtools/devtools_system_info_handler.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/devtools/devtools_tracing_handler.h"
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/browser/devtools/tethering_handler.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/common/devtools_messages.h"
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/devtools_agent_host.h"
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/devtools_http_handler_delegate.h"
314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/devtools_target.h"
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/common/content_client.h"
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/common/url_constants.h"
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/public/common/user_agent.h"
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "grit/devtools_resources_map.h"
361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "net/base/escape.h"
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/io_buffer.h"
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/ip_endpoint.h"
3946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "net/base/net_errors.h"
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/server/http_server_request_info.h"
41a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "net/server/http_server_response_info.h"
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "net/socket/server_socket.h"
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if defined(OS_ANDROID)
45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/android/build_info.h"
46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif
47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace content {
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const base::FilePath::CharType kDevToolsActivePortFileName[] =
5346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    FILE_PATH_LITERAL("DevToolsActivePort");
5446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
5568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kDevToolsHandlerThreadName[] = "Chrome_DevToolsHandlerThread";
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kThumbUrlPrefix[] = "/thumb/";
5868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kPageUrlPrefix[] = "/devtools/page/";
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kTargetIdField[] = "id";
6146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const char kTargetParentIdField[] = "parentId";
6268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kTargetTypeField[] = "type";
6368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kTargetTitleField[] = "title";
6468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kTargetDescriptionField[] = "description";
6568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kTargetUrlField[] = "url";
6668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kTargetThumbnailUrlField[] = "thumbnailUrl";
6768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kTargetFaviconUrlField[] = "faviconUrl";
6868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kTargetWebSocketDebuggerUrlField[] = "webSocketDebuggerUrl";
6968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kTargetDevtoolsFrontendUrlField[] = "devtoolsFrontendUrl";
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Maximum write buffer size of devtools http/websocket connectinos.
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst int32 kSendBufferSizeForDevTools = 100 * 1024 * 1024;  // 100Mb
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
7403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// An internal implementation of DevToolsAgentHostClient that delegates
7503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// messages sent to a DebuggerShell instance.
7603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)class DevToolsAgentHostClientImpl : public DevToolsAgentHostClient {
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
7803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DevToolsAgentHostClientImpl(base::MessageLoop* message_loop,
7903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                              net::HttpServer* server,
8003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                              int connection_id,
8103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                              DevToolsAgentHost* agent_host)
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : message_loop_(message_loop),
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        server_(server),
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        connection_id_(connection_id),
8503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        agent_host_(agent_host) {
8603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    agent_host_->AttachClient(this);
8703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  virtual ~DevToolsAgentHostClientImpl() {
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (agent_host_.get())
9103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      agent_host_->DetachClient();
9203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  virtual void AgentHostClosed(
9503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      DevToolsAgentHost* agent_host,
9603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      bool replaced_with_another_client) OVERRIDE {
9703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    DCHECK(agent_host == agent_host_.get());
9803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    agent_host_ = NULL;
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    base::DictionaryValue notification;
101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    notification.SetString(
10203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        devtools::Inspector::detached::kParamReason,
10303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        replaced_with_another_client ?
10403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)            "replaced_with_devtools" : "target_closed");
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string response = DevToolsProtocol::CreateNotification(
106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        devtools::Inspector::detached::kName,
107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        notification.DeepCopy())->Serialize();
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    message_loop_->PostTask(
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&net::HttpServer::SendOverWebSocket,
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   base::Unretained(server_),
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   connection_id_,
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   response));
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    message_loop_->PostTask(
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        base::Bind(&net::HttpServer::Close,
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   base::Unretained(server_),
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   connection_id_));
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  virtual void DispatchProtocolMessage(
12303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      DevToolsAgentHost* agent_host, const std::string& message) OVERRIDE {
12403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    DCHECK(agent_host == agent_host_.get());
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    message_loop_->PostTask(
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&net::HttpServer::SendOverWebSocket,
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   base::Unretained(server_),
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   connection_id_,
13003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                   message));
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  void OnMessage(const std::string& message) {
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (agent_host_.get())
13503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      agent_host_->DispatchProtocolMessage(message);
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::MessageLoop* const message_loop_;
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  net::HttpServer* const server_;
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const int connection_id_;
14203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  scoped_refptr<DevToolsAgentHost> agent_host_;
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)static bool TimeComparator(const DevToolsTarget* target1,
1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                           const DevToolsTarget* target2) {
1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return target1->GetLastActivityTime() > target2->GetLastActivityTime();
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool DevToolsHttpHandler::IsSupportedProtocolVersion(
154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& version) {
1550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return devtools::IsSupportedProtocolVersion(version);
156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// static
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int DevToolsHttpHandler::GetFrontendResourceId(const std::string& name) {
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < kDevtoolsResourcesSize; ++i) {
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (name == kDevtoolsResources[i].name)
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return kDevtoolsResources[i].value;
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return -1;
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DevToolsHttpHandler* DevToolsHttpHandler::Start(
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_ptr<ServerSocketFactory> server_socket_factory,
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& frontend_url,
17146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    DevToolsHttpHandlerDelegate* delegate,
17246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const base::FilePath& active_port_output_directory) {
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DevToolsHttpHandlerImpl* http_handler =
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      new DevToolsHttpHandlerImpl(server_socket_factory.Pass(),
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  frontend_url,
17646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                  delegate,
17746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                  active_port_output_directory);
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  http_handler->Start();
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return http_handler;
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciDevToolsHttpHandler::ServerSocketFactory::ServerSocketFactory(
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::string& address,
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int port,
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int backlog)
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : address_(address),
1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      port_(port),
1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      backlog_(backlog) {
1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciDevToolsHttpHandler::ServerSocketFactory::~ServerSocketFactory() {
1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciscoped_ptr<net::ServerSocket>
1951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciDevToolsHttpHandler::ServerSocketFactory::CreateAndListen() const {
1961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<net::ServerSocket> socket = Create();
1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (socket &&
1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      socket->ListenWithAddressAndPort(address_, port_, backlog_) == net::OK) {
1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return socket.Pass();
2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return scoped_ptr<net::ServerSocket>();
2021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DevToolsHttpHandlerImpl::~DevToolsHttpHandlerImpl() {
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Stop() must be called prior to destruction.
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(server_.get() == NULL);
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(thread_.get() == NULL);
2094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  STLDeleteValues(&target_map_);
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::Start() {
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (thread_)
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_.reset(new base::Thread(kDevToolsHandlerThreadName));
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostTask(
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::FILE, FROM_HERE,
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&DevToolsHttpHandlerImpl::StartHandlerThread, this));
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Runs on FILE thread.
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::StartHandlerThread() {
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Thread::Options options;
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  options.message_loop_type = base::MessageLoop::TYPE_IO;
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!thread_->StartWithOptions(options)) {
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostTask(
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::UI, FROM_HERE,
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&DevToolsHttpHandlerImpl::ResetHandlerThread, this));
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_->message_loop()->PostTask(
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&DevToolsHttpHandlerImpl::Init, this));
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::ResetHandlerThread() {
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_.reset();
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::ResetHandlerThreadAndRelease() {
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ResetHandlerThread();
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Release();
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::Stop() {
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!thread_)
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostTaskAndReply(
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::FILE, FROM_HERE,
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&DevToolsHttpHandlerImpl::StopHandlerThread, this),
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&DevToolsHttpHandlerImpl::ResetHandlerThreadAndRelease, this));
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid DevToolsHttpHandlerImpl::StopWithoutRelease() {
2561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!thread_)
2571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
2581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  BrowserThread::PostTaskAndReply(
2591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      BrowserThread::FILE, FROM_HERE,
2601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&DevToolsHttpHandlerImpl::StopHandlerThread, this),
2611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&DevToolsHttpHandlerImpl::ResetHandlerThread, this));
2621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)GURL DevToolsHttpHandlerImpl::GetFrontendURL() {
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net::IPEndPoint ip_address;
2661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (server_ && server_->GetLocalAddress(&ip_address))
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return GURL();
268a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return GURL(std::string("http://") + ip_address.ToString() + frontend_url_);
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static std::string PathWithoutParams(const std::string& path) {
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t query_position = path.find("?");
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (query_position != std::string::npos)
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return path.substr(0, query_position);
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return path;
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static std::string GetMimeType(const std::string& filename) {
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (EndsWith(filename, ".html", false)) {
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return "text/html";
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (EndsWith(filename, ".css", false)) {
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return "text/css";
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (EndsWith(filename, ".js", false)) {
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return "application/javascript";
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (EndsWith(filename, ".png", false)) {
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return "image/png";
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (EndsWith(filename, ".gif", false)) {
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return "image/gif";
289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else if (EndsWith(filename, ".json", false)) {
290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return "application/json";
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  LOG(ERROR) << "GetMimeType doesn't know mime type for: "
293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)             << filename
294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)             << " text/plain will be returned";
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NOTREACHED();
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return "text/plain";
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnHttpRequest(
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int connection_id,
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const net::HttpServerRequestInfo& info) {
3021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  server_->SetSendBufferSize(connection_id, kSendBufferSizeForDevTools);
3031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (info.path.find("/json") == 0) {
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostTask(
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::UI,
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&DevToolsHttpHandlerImpl::OnJsonRequestUI,
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   this,
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   connection_id,
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   info));
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (info.path.find(kThumbUrlPrefix) == 0) {
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Thumbnail request.
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string target_id = info.path.substr(strlen(kThumbUrlPrefix));
3184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DevToolsTarget* target = GetTarget(target_id);
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    GURL page_url;
3204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (target)
321010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      page_url = target->GetURL();
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostTask(
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::UI,
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&DevToolsHttpHandlerImpl::OnThumbnailRequestUI,
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   this,
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   connection_id,
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   page_url));
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (info.path == "" || info.path == "/") {
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Discovery page request.
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostTask(
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::UI,
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&DevToolsHttpHandlerImpl::OnDiscoveryPageRequestUI,
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   this,
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   connection_id));
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (info.path.find("/devtools/") != 0) {
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    server_->Send404(connection_id);
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string filename = PathWithoutParams(info.path.substr(10));
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string mime_type = GetMimeType(filename);
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath frontend_dir = delegate_->GetDebugFrontendDir();
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!frontend_dir.empty()) {
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath path = frontend_dir.AppendASCII(filename);
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string data;
35558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    base::ReadFileToString(path, &data);
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    server_->Send200(connection_id, data, mime_type);
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (delegate_->BundlesFrontendResources()) {
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int resource_id = DevToolsHttpHandler::GetFrontendResourceId(filename);
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (resource_id != -1) {
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::StringPiece data = GetContentClient()->GetDataResource(
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              resource_id, ui::SCALE_FACTOR_NONE);
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      server_->Send200(connection_id, data.as_string(), mime_type);
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  server_->Send404(connection_id);
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnWebSocketRequest(
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int connection_id,
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const net::HttpServerRequestInfo& request) {
3747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  std::string browser_prefix = "/devtools/browser";
3757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t browser_pos = request.path.find(browser_prefix);
3767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (browser_pos == 0) {
377116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_refptr<DevToolsBrowserTarget> browser_target =
378116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        new DevToolsBrowserTarget(server_.get(), connection_id);
379116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    browser_target->RegisterDomainHandler(
3802385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        devtools::Tracing::kName,
381cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        new DevToolsTracingHandler(DevToolsTracingHandler::Browser),
3822385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        true /* handle on UI thread */);
383116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    browser_target->RegisterDomainHandler(
3841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        devtools::Tethering::kName,
3852385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        new TetheringHandler(delegate_.get()),
3862385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        false /* handle on this thread */);
387116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    browser_target->RegisterDomainHandler(
3883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        devtools::SystemInfo::kName,
3893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        new DevToolsSystemInfoHandler(),
3903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        true /* handle on UI thread */);
391116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    browser_targets_[connection_id] = browser_target;
3927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    server_->SetSendBufferSize(connection_id, kSendBufferSizeForDevTools);
3947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    server_->AcceptWebSocket(connection_id, request);
3957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
3967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
3977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostTask(
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::UI,
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &DevToolsHttpHandlerImpl::OnWebSocketRequestUI,
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          this,
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          connection_id,
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          request));
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnWebSocketMessage(
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int connection_id,
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& data) {
411116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  BrowserTargets::iterator it = browser_targets_.find(connection_id);
412116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (it != browser_targets_.end()) {
413116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    it->second->HandleMessage(data);
4147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
4157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
4167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostTask(
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::UI,
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &DevToolsHttpHandlerImpl::OnWebSocketMessageUI,
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          this,
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          connection_id,
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          data));
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnClose(int connection_id) {
428116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  BrowserTargets::iterator it = browser_targets_.find(connection_id);
429116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (it != browser_targets_.end()) {
430116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    it->second->Detach();
431116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    browser_targets_.erase(it);
4327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
4337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
4347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostTask(
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::UI,
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &DevToolsHttpHandlerImpl::OnCloseUI,
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          this,
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          connection_id));
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string DevToolsHttpHandlerImpl::GetFrontendURLInternal(
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string id,
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& host) {
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::StringPrintf(
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "%s%sws=%s%s%s",
449a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      frontend_url_.c_str(),
450a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      frontend_url_.find("?") == std::string::npos ? "?" : "&",
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      host.c_str(),
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      kPageUrlPrefix,
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      id.c_str());
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static bool ParseJsonPath(
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& path,
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string* command,
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string* target_id) {
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Fall back to list in case of empty query.
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (path.empty()) {
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *command = "list";
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (path.find("/") != 0) {
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Malformed command.
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *command = path.substr(1);
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t separator_pos = command->find("/");
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (separator_pos != std::string::npos) {
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *target_id = command->substr(separator_pos + 1);
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *command = command->substr(0, separator_pos);
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnJsonRequestUI(
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int connection_id,
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const net::HttpServerRequestInfo& info) {
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Trim /json
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string path = info.path.substr(5);
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Trim fragment and query
4881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  std::string query;
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t query_pos = path.find("?");
4901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (query_pos != std::string::npos) {
4911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    query = path.substr(query_pos + 1);
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    path = path.substr(0, query_pos);
4931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t fragment_pos = path.find("#");
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (fragment_pos != std::string::npos)
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    path = path.substr(0, fragment_pos);
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string command;
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string target_id;
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!ParseJsonPath(path, &command, &target_id)) {
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SendJson(connection_id,
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             net::HTTP_NOT_FOUND,
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             NULL,
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             "Malformed query: " + info.path);
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (command == "version") {
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue version;
5110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    version.SetString("Protocol-Version", devtools::kProtocolVersion);
512a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    version.SetString("WebKit-Version", GetWebKitVersion());
513a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    version.SetString("Browser", GetContentClient()->GetProduct());
514a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    version.SetString("User-Agent", GetContentClient()->GetUserAgent());
515f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if defined(OS_ANDROID)
516f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    version.SetString("Android-Package",
517f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        base::android::BuildInfo::GetInstance()->package_name());
518f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif
519c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SendJson(connection_id, net::HTTP_OK, &version, std::string());
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (command == "list") {
524a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    std::string host = info.headers["host"];
5254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    AddRef();  // Balanced in OnTargetListReceived.
5261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DevToolsManagerDelegate* manager_delegate =
5271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        DevToolsManager::GetInstance()->delegate();
5281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (manager_delegate) {
5291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      manager_delegate->EnumerateTargets(
5301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          base::Bind(&DevToolsHttpHandlerImpl::OnTargetListReceived,
5311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                     this, connection_id, host));
5321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else {
5331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      DevToolsManagerDelegate::TargetList empty_list;
5341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      OnTargetListReceived(connection_id, host, empty_list);
5351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (command == "new") {
5401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    GURL url(net::UnescapeURLComponent(
5411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        query, net::UnescapeRule::URL_SPECIAL_CHARS));
5421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (!url.is_valid())
543f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      url = GURL(url::kAboutBlankURL);
5441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_ptr<DevToolsTarget> target;
5451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DevToolsManagerDelegate* manager_delegate =
5461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        DevToolsManager::GetInstance()->delegate();
5471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (manager_delegate)
5481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      target = manager_delegate->CreateNewTarget(url);
5494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (!target) {
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SendJson(connection_id,
5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               net::HTTP_INTERNAL_SERVER_ERROR,
5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               NULL,
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               "Could not create new page");
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
556a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    std::string host = info.headers["host"];
5574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    scoped_ptr<base::DictionaryValue> dictionary(
5584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        SerializeTarget(*target.get(), host));
559c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SendJson(connection_id, net::HTTP_OK, dictionary.get(), std::string());
5604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string target_id = target->GetId();
5614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    target_map_[target_id] = target.release();
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (command == "activate" || command == "close") {
5664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DevToolsTarget* target = GetTarget(target_id);
5674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (!target) {
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SendJson(connection_id,
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               net::HTTP_NOT_FOUND,
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               NULL,
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               "No such target id: " + target_id);
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (command == "activate") {
5764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (target->Activate()) {
5774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        SendJson(connection_id, net::HTTP_OK, NULL, "Target activated");
5784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      } else {
5794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        SendJson(connection_id,
5804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 net::HTTP_INTERNAL_SERVER_ERROR,
5814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 NULL,
5824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 "Could not activate target id: " + target_id);
5834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      }
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (command == "close") {
5884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (target->Close()) {
5894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        SendJson(connection_id, net::HTTP_OK, NULL, "Target is closing");
5904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      } else {
5914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        SendJson(connection_id,
5924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 net::HTTP_INTERNAL_SERVER_ERROR,
5934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 NULL,
5944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 "Could not close target id: " + target_id);
5954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      }
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SendJson(connection_id,
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           net::HTTP_NOT_FOUND,
6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           NULL,
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           "Unknown command: " + command);
6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return;
6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnTargetListReceived(
6074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    int connection_id,
6084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string& host,
6091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const DevToolsManagerDelegate::TargetList& targets) {
6101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DevToolsManagerDelegate::TargetList sorted_targets = targets;
6114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::sort(sorted_targets.begin(), sorted_targets.end(), TimeComparator);
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  STLDeleteValues(&target_map_);
6144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::ListValue list_value;
6151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (DevToolsManagerDelegate::TargetList::const_iterator it =
6164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      sorted_targets.begin(); it != sorted_targets.end(); ++it) {
6174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DevToolsTarget* target = *it;
6184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    target_map_[target->GetId()] = target;
6194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    list_value.Append(SerializeTarget(*target, host));
6204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
6214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SendJson(connection_id, net::HTTP_OK, &list_value, std::string());
6224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Release();  // Balanced in OnJsonRequestUI.
6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)DevToolsTarget* DevToolsHttpHandlerImpl::GetTarget(const std::string& id) {
6264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  TargetMap::const_iterator it = target_map_.find(id);
6274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (it == target_map_.end())
6284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return NULL;
6294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return it->second;
6302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnThumbnailRequestUI(
6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int connection_id, const GURL& page_url) {
6341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DevToolsManagerDelegate* manager_delegate =
6351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      DevToolsManager::GetInstance()->delegate();
6361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::string data =
6371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      manager_delegate ? manager_delegate->GetPageThumbnailData(page_url) : "";
6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!data.empty())
6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Send200(connection_id, data, "image/png");
6402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
6412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Send404(connection_id);
6422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnDiscoveryPageRequestUI(int connection_id) {
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string response = delegate_->GetDiscoveryPageHTML();
6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Send200(connection_id, response, "text/html; charset=UTF-8");
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnWebSocketRequestUI(
6502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int connection_id,
6512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const net::HttpServerRequestInfo& request) {
652c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!thread_)
6532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
6542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t pos = request.path.find(kPageUrlPrefix);
6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (pos != 0) {
6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Send404(connection_id);
6582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
6592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string page_id = request.path.substr(strlen(kPageUrlPrefix));
6624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DevToolsTarget* target = GetTarget(page_id);
6634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_refptr<DevToolsAgentHost> agent =
6644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      target ? target->GetAgentHost() : NULL;
6651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!agent.get()) {
6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Send500(connection_id, "No such target id: " + page_id);
6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
6682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
670c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (agent->IsAttached()) {
6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Send500(connection_id,
6722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "Target with given id is being inspected: " + page_id);
6732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
6742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DevToolsAgentHostClientImpl* client_host = new DevToolsAgentHostClientImpl(
6771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      thread_->message_loop(), server_.get(), connection_id, agent.get());
67803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  connection_to_client_ui_[connection_id] = client_host;
6792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AcceptWebSocket(connection_id, request);
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnWebSocketMessageUI(
6842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int connection_id,
6852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& data) {
68603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ConnectionToClientMap::iterator it =
68703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      connection_to_client_ui_.find(connection_id);
68803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (it == connection_to_client_ui_.end())
6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
69103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DevToolsAgentHostClientImpl* client =
69203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      static_cast<DevToolsAgentHostClientImpl*>(it->second);
69303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  client->OnMessage(data);
6942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::OnCloseUI(int connection_id) {
69703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ConnectionToClientMap::iterator it =
69803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      connection_to_client_ui_.find(connection_id);
69903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (it != connection_to_client_ui_.end()) {
70003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    DevToolsAgentHostClientImpl* client =
70103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        static_cast<DevToolsAgentHostClientImpl*>(it->second);
70203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    delete client;
70303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    connection_to_client_ui_.erase(connection_id);
7042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DevToolsHttpHandlerImpl::DevToolsHttpHandlerImpl(
7081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_ptr<ServerSocketFactory> server_socket_factory,
7092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& frontend_url,
71046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    DevToolsHttpHandlerDelegate* delegate,
71146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const base::FilePath& active_port_output_directory)
712a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : frontend_url_(frontend_url),
7131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      server_socket_factory_(server_socket_factory.Pass()),
71446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      delegate_(delegate),
71546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      active_port_output_directory_(active_port_output_directory) {
716a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (frontend_url_.empty())
7171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    frontend_url_ = "/devtools/devtools.html";
7182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Balanced in ResetHandlerThreadAndRelease().
7202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddRef();
7212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Runs on the handler thread
7242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::Init() {
7251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<net::ServerSocket> server_socket =
7261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      server_socket_factory_->CreateAndListen();
7271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!server_socket) {
7281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    LOG(ERROR) << "Cannot start http server for devtools. Stop devtools.";
7291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    BrowserThread::PostTask(
7301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        BrowserThread::UI, FROM_HERE,
7311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        base::Bind(&DevToolsHttpHandlerImpl::StopWithoutRelease, this));
7321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
7331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
7341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
7351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  server_.reset(new net::HttpServer(server_socket.Pass(), this));
73646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!active_port_output_directory_.empty())
73746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    WriteActivePortToUserProfile();
7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Runs on the handler thread
7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::Teardown() {
7421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  server_.reset(NULL);
7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Runs on FILE thread to make sure that it is serialized against
7462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// {Start|Stop}HandlerThread and to allow calling pthread_join.
7472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::StopHandlerThread() {
7482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!thread_->message_loop())
7492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
7502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_->message_loop()->PostTask(
7512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
7522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&DevToolsHttpHandlerImpl::Teardown, this));
7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Thread::Stop joins the thread.
7542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_->Stop();
7552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
75746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void DevToolsHttpHandlerImpl::WriteActivePortToUserProfile() {
75846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(!active_port_output_directory_.empty());
75946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  net::IPEndPoint endpoint;
76046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  int err;
76146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if ((err = server_->GetLocalAddress(&endpoint)) != net::OK) {
76246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    LOG(ERROR) << "Error " << err << " getting local address";
76346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
76446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
76546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
76646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Write this port to a well-known file in the profile directory
76746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // so Telemetry can pick it up.
76846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::FilePath path = active_port_output_directory_.Append(
76946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      kDevToolsActivePortFileName);
770f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::string port_string = base::IntToString(endpoint.port());
771f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (base::WriteFile(path, port_string.c_str(), port_string.length()) < 0) {
77246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    LOG(ERROR) << "Error writing DevTools active port to file";
77346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
77446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
77546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
7762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::SendJson(int connection_id,
7772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       net::HttpStatusCode status_code,
7782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       base::Value* value,
7792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       const std::string& message) {
780c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!thread_)
7812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
7822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Serialize value and message.
7842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string json_value;
7852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (value) {
7862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::JSONWriter::WriteWithOptions(value,
7872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       base::JSONWriter::OPTIONS_PRETTY_PRINT,
7882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       &json_value);
7892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string json_message;
7912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::Value> message_object(new base::StringValue(message));
7922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::JSONWriter::Write(message_object.get(), &json_message);
7932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
794a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  net::HttpServerResponseInfo response(status_code);
795a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  response.SetBody(json_value + message, "application/json; charset=UTF-8");
7962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_->message_loop()->PostTask(
7982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
799a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      base::Bind(&net::HttpServer::SendResponse,
8001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 base::Unretained(server_.get()),
8012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 connection_id,
802a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch                 response));
8032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::Send200(int connection_id,
8062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      const std::string& data,
8072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      const std::string& mime_type) {
808c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!thread_)
8092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
8102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_->message_loop()->PostTask(
8112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
8122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&net::HttpServer::Send200,
8131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 base::Unretained(server_.get()),
8142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 connection_id,
8152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 data,
8162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 mime_type));
8172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::Send404(int connection_id) {
820c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!thread_)
8212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
8222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_->message_loop()->PostTask(
8232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
8241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&net::HttpServer::Send404,
8251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 base::Unretained(server_.get()),
8261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 connection_id));
8272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::Send500(int connection_id,
8302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      const std::string& message) {
831c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!thread_)
8322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
8332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_->message_loop()->PostTask(
8342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
8351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&net::HttpServer::Send500,
8361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 base::Unretained(server_.get()),
8371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 connection_id,
8382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 message));
8392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DevToolsHttpHandlerImpl::AcceptWebSocket(
8422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int connection_id,
8432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const net::HttpServerRequestInfo& request) {
844c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!thread_)
8452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
8462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  thread_->message_loop()->PostTask(
8472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
8481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&net::HttpServer::SetSendBufferSize,
8491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 base::Unretained(server_.get()),
8501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 connection_id,
8511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 kSendBufferSizeForDevTools));
8521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  thread_->message_loop()->PostTask(
8531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      FROM_HERE,
8541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&net::HttpServer::AcceptWebSocket,
8551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 base::Unretained(server_.get()),
8561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 connection_id,
8571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 request));
8582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)base::DictionaryValue* DevToolsHttpHandlerImpl::SerializeTarget(
8614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const DevToolsTarget& target,
8622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& host) {
8632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dictionary = new base::DictionaryValue;
8642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string id = target.GetId();
8662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dictionary->SetString(kTargetIdField, id);
86746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  std::string parent_id = target.GetParentId();
86846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!parent_id.empty())
86946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    dictionary->SetString(kTargetParentIdField, parent_id);
8704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  dictionary->SetString(kTargetTypeField, target.GetType());
8711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  dictionary->SetString(kTargetTitleField,
8721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                        net::EscapeForHTML(target.GetTitle()));
8734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  dictionary->SetString(kTargetDescriptionField, target.GetDescription());
8742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
875010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  GURL url = target.GetURL();
8764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  dictionary->SetString(kTargetUrlField, url.spec());
8772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
878010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  GURL favicon_url = target.GetFaviconURL();
8794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (favicon_url.is_valid())
8804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    dictionary->SetString(kTargetFaviconUrlField, favicon_url.spec());
8812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DevToolsManagerDelegate* manager_delegate =
8831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      DevToolsManager::GetInstance()->delegate();
8841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (manager_delegate &&
8851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      !manager_delegate->GetPageThumbnailData(url).empty()) {
8864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    dictionary->SetString(kTargetThumbnailUrlField,
8874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                          std::string(kThumbUrlPrefix) + id);
8882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!target.IsAttached()) {
8914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    dictionary->SetString(kTargetWebSocketDebuggerUrlField,
8924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                          base::StringPrintf("ws://%s%s%s",
8934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                             host.c_str(),
8944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                             kPageUrlPrefix,
8954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                             id.c_str()));
8964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    std::string devtools_frontend_url = GetFrontendURLInternal(
8974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        id.c_str(),
8984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        host);
8994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    dictionary->SetString(
9004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        kTargetDevtoolsFrontendUrlField, devtools_frontend_url);
9014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
9022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return dictionary;
9042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace content
907