devtools_client_impl.cc revision 868fa2fe829687343ffae624259930155e16dbd8
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/chromedriver/chrome/devtools_client_impl.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_reader.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_writer.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/strings/stringprintf.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/chromedriver/chrome/log.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/chromedriver/chrome/status.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/chromedriver/net/sync_websocket.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/chromedriver/net/url_request_context_getter.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* kInspectorContextError =
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "Execution context with given id not found.";
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Status ParseInspectorError(const std::string& error_json) {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::Value> error(base::JSONReader::Read(error_json));
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::DictionaryValue* error_dict;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!error || !error->GetAsDictionary(&error_dict))
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Status(kUnknownError, "inspector error with no error message");
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string error_message;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (error_dict->GetString("message", &error_message) &&
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_message == kInspectorContextError) {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Status(kNoSuchExecutionContext);
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Status(kUnknownError, "unhandled inspector error: " + error_json);
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ScopedIncrementer {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit ScopedIncrementer(int* count) : count_(count) {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*count_)++;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~ScopedIncrementer() {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*count_)--;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int* count_;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internal {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InspectorEvent::InspectorEvent() {}
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InspectorEvent::~InspectorEvent() {}
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InspectorCommandResponse::InspectorCommandResponse() {}
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InspectorCommandResponse::~InspectorCommandResponse() {}
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace internal
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DevToolsClientImpl::DevToolsClientImpl(
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SyncWebSocketFactory& factory,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& url,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& id,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FrontendCloserFunc& frontend_closer_func,
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Log* log)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : socket_(factory.Run().Pass()),
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_(url),
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id_(id),
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      frontend_closer_func_(frontend_closer_func),
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      log_(log),
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parser_func_(base::Bind(&internal::ParseInspectorMessage)),
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unnotified_event_(NULL),
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_id_(1),
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stack_count_(0) {}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DevToolsClientImpl::DevToolsClientImpl(
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SyncWebSocketFactory& factory,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& url,
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& id,
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FrontendCloserFunc& frontend_closer_func,
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Log* log,
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ParserFunc& parser_func)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : socket_(factory.Run().Pass()),
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_(url),
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id_(id),
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      frontend_closer_func_(frontend_closer_func),
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      log_(log),
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parser_func_(parser_func),
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unnotified_event_(NULL),
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_id_(1),
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stack_count_(0) {}
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DevToolsClientImpl::~DevToolsClientImpl() {}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DevToolsClientImpl::SetParserFuncForTesting(
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ParserFunc& parser_func) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser_func_ = parser_func;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const std::string& DevToolsClientImpl::GetId() {
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return id_;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Status DevToolsClientImpl::ConnectIfNecessary() {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (stack_count_)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Status(kUnknownError, "cannot connect when nested");
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (socket_->IsConnected())
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Status(kOk);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!socket_->Connect(url_)) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Try to close devtools frontend and then reconnect.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Status status = frontend_closer_func_.Run();
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (status.IsError())
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return status;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!socket_->Connect(url_))
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return Status(kDisconnected, "unable to connect to renderer");
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unnotified_connect_listeners_ = listeners_;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unnotified_event_listeners_.clear();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  response_info_map_.clear();
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Notify all listeners of the new connection. Do this now so that any errors
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that occur are reported now instead of later during some unrelated call.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Also gives listeners a chance to send commands before other clients.
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return EnsureListenersNotifiedOfConnect();
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Status DevToolsClientImpl::SendCommand(
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& method,
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::DictionaryValue& params) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> result;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SendCommandInternal(method, params, &result);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Status DevToolsClientImpl::SendCommandAndGetResult(
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& method,
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::DictionaryValue& params,
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<base::DictionaryValue>* result) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> intermediate_result;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Status status = SendCommandInternal(method, params, &intermediate_result);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.IsError())
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return status;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!intermediate_result)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Status(kUnknownError, "inspector response missing result");
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->reset(intermediate_result.release());
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Status(kOk);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DevToolsClientImpl::AddListener(DevToolsEventListener* listener) {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(listener);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  listeners_.push_back(listener);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Status DevToolsClientImpl::HandleReceivedEvents() {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!socket_->IsConnected())
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Status(kDisconnected, "not connected to DevTools");
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (true) {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!socket_->HasNextMessage())
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return Status(kOk);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Status status = ProcessNextMessage(-1);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (status.IsError())
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return status;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Status DevToolsClientImpl::HandleEventsUntil(
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ConditionalFunc& conditional_func, const base::TimeDelta& timeout) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!socket_->IsConnected())
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Status(kDisconnected, "not connected to DevTools");
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks deadline = base::TimeTicks::Now() + timeout;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (true) {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (base::TimeTicks::Now() >= deadline)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return Status(kTimeout, base::StringPrintf(
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "exceeded %dms", static_cast<int>(timeout.InMilliseconds())));
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!socket_->HasNextMessage()) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bool is_condition_met;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Status status = conditional_func.Run(&is_condition_met);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (status.IsError())
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return status;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (is_condition_met)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return Status(kOk);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // To keep this simple, we don't pass the delta time to
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // ProcessNextMessage. As a result, we may not immediately
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // return after |timeout|ms.
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Status status = ProcessNextMessage(-1);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (status.IsError() && status.code() != kTimeout)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return status;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DevToolsClientImpl::ResponseInfo::ResponseInfo(const std::string& method)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : state(kWaiting), method(method) {}
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DevToolsClientImpl::ResponseInfo::~ResponseInfo() {}
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Status DevToolsClientImpl::SendCommandInternal(
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& method,
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::DictionaryValue& params,
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<base::DictionaryValue>* result) {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!socket_->IsConnected())
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Status(kDisconnected, "not connected to DevTools");
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int command_id = next_id_++;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::DictionaryValue command;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command.SetInteger("id", command_id);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command.SetString("method", method);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command.Set("params", params.DeepCopy());
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string message;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::JSONWriter::Write(&command, &message);
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  log_->AddEntry(Log::kDebug, "sending Inspector command " + message);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!socket_->Send(message))
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Status(kDisconnected, "unable to send message to renderer");
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  linked_ptr<ResponseInfo> response_info =
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      make_linked_ptr(new ResponseInfo(method));
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  response_info_map_[command_id] = response_info;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (response_info->state == kWaiting) {
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Status status = ProcessNextMessage(command_id);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (status.IsError()) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (response_info->state == kReceived)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        response_info_map_.erase(command_id);
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return status;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (response_info->state == kBlocked) {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    response_info->state = kIgnored;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Status(kUnexpectedAlertOpen);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(response_info->state, kReceived);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  internal::InspectorCommandResponse& response = response_info->response;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!response.result)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ParseInspectorError(response.error);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *result = response.result.Pass();
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Status(kOk);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Status DevToolsClientImpl::ProcessNextMessage(int expected_id) {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedIncrementer increment_stack_count(&stack_count_);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Status status = EnsureListenersNotifiedOfConnect();
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.IsError())
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return status;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  status = EnsureListenersNotifiedOfEvent();
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.IsError())
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return status;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  status = EnsureListenersNotifiedOfCommandResponse();
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.IsError())
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return status;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The command response may have already been received or blocked while
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // notifying listeners.
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (expected_id != -1 && response_info_map_[expected_id]->state != kWaiting)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Status(kOk);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string message;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (socket_->ReceiveNextMessage(&message,
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      base::TimeDelta::FromMinutes(1))) {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SyncWebSocket::kOk:
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      log_->AddEntry(Log::kDebug, "received Inspector response " + message);
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SyncWebSocket::kDisconnected:
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      message = "unable to receive message from renderer";
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      log_->AddEntry(Log::kDebug, message);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return Status(kDisconnected, message);
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SyncWebSocket::kTimeout:
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      message = "timed out receiving message from renderer";
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      log_->AddEntry(Log::kDebug, message);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return Status(kTimeout, message);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  internal::InspectorMessageType type;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  internal::InspectorEvent event;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  internal::InspectorCommandResponse response;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!parser_func_.Run(message, expected_id, &type, &event, &response))
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Status(kUnknownError, "bad inspector message: " + message);
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (type == internal::kEventMessageType)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ProcessEvent(event);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(type, internal::kCommandResponseMessageType);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ProcessCommandResponse(response);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Status DevToolsClientImpl::ProcessEvent(const internal::InspectorEvent& event) {
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unnotified_event_listeners_ = listeners_;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unnotified_event_ = &event;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Status status = EnsureListenersNotifiedOfEvent();
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unnotified_event_ = NULL;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.IsError())
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return status;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event.method == "Inspector.detached")
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Status(kDisconnected, "received Inspector.detached event");
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event.method == "Inspector.targetCrashed")
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Status(kDisconnected, "page crashed");
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event.method == "Page.javascriptDialogOpening") {
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // A command may have opened the dialog, which will block the response.
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // To find out which one (if any), do a round trip with a simple command
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to the renderer and afterwards see if any of the commands still haven't
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // received a response.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This relies on the fact that DevTools commands are processed
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // sequentially. This may break if any of the commands are asynchronous.
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If for some reason the round trip command fails, mark all the waiting
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // commands as blocked and return the error. This is better than risking
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // a hang.
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_id = next_id_;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::DictionaryValue enable_params;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    enable_params.SetString("purpose", "detect if alert blocked any cmds");
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Status enable_status = SendCommand("Inspector.enable", enable_params);
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (ResponseInfoMap::const_iterator iter = response_info_map_.begin();
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         iter != response_info_map_.end(); ++iter) {
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (iter->first > max_id)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (iter->second->state == kWaiting)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        iter->second->state = kBlocked;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (enable_status.IsError())
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return status;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Status(kOk);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Status DevToolsClientImpl::ProcessCommandResponse(
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const internal::InspectorCommandResponse& response) {
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (response_info_map_.count(response.id) == 0)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Status(kUnknownError, "unexpected command response");
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  linked_ptr<ResponseInfo> response_info = response_info_map_[response.id];
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (response_info->state == kReceived)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Status(kUnknownError, "received multiple command responses");
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (response_info->state == kIgnored) {
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    response_info_map_.erase(response.id);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    response_info->state = kReceived;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    response_info->response.id = response.id;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    response_info->response.error = response.error;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (response.result)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      response_info->response.result.reset(response.result->DeepCopy());
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (response.result) {
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unnotified_cmd_response_listeners_ = listeners_;
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unnotified_cmd_response_info_ = response_info;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Status status = EnsureListenersNotifiedOfCommandResponse();
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unnotified_cmd_response_info_.reset();
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (status.IsError())
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return status;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Status(kOk);
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Status DevToolsClientImpl::EnsureListenersNotifiedOfConnect() {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (unnotified_connect_listeners_.size()) {
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DevToolsEventListener* listener = unnotified_connect_listeners_.front();
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unnotified_connect_listeners_.pop_front();
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Status status = listener->OnConnected(this);
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (status.IsError())
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return status;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Status(kOk);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Status DevToolsClientImpl::EnsureListenersNotifiedOfEvent() {
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (unnotified_event_listeners_.size()) {
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DevToolsEventListener* listener = unnotified_event_listeners_.front();
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unnotified_event_listeners_.pop_front();
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Status status = listener->OnEvent(
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this, unnotified_event_->method, *unnotified_event_->params);
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (status.IsError())
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return status;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Status(kOk);
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Status DevToolsClientImpl::EnsureListenersNotifiedOfCommandResponse() {
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (unnotified_cmd_response_listeners_.size()) {
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DevToolsEventListener* listener =
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unnotified_cmd_response_listeners_.front();
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unnotified_cmd_response_listeners_.pop_front();
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Status status =
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        listener->OnCommandSuccess(this, unnotified_cmd_response_info_->method);
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (status.IsError())
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return status;
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Status(kOk);
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internal {
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ParseInspectorMessage(
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& message,
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int expected_id,
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InspectorMessageType* type,
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InspectorEvent* event,
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InspectorCommandResponse* command_response) {
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::Value> message_value(base::JSONReader::Read(message));
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::DictionaryValue* message_dict;
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!message_value || !message_value->GetAsDictionary(&message_dict))
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int id;
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!message_dict->HasKey("id")) {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string method;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!message_dict->GetString("method", &method))
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::DictionaryValue* params = NULL;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_dict->GetDictionary("params", &params);
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *type = kEventMessageType;
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    event->method = method;
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (params)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event->params.reset(params->DeepCopy());
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event->params.reset(new base::DictionaryValue());
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (message_dict->GetInteger("id", &id)) {
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::DictionaryValue* unscoped_error = NULL;
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::DictionaryValue* unscoped_result = NULL;
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!message_dict->GetDictionary("error", &unscoped_error) &&
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !message_dict->GetDictionary("result", &unscoped_result))
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *type = kCommandResponseMessageType;
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    command_response->id = id;
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (unscoped_result)
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      command_response->result.reset(unscoped_result->DeepCopy());
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::JSONWriter::Write(unscoped_error, &command_response->error);
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace internal
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)