Home | History | Annotate | Download | only in devtools
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/browser/devtools/devtools_protocol.h"
      6 
      7 #include "base/json/json_reader.h"
      8 #include "base/json/json_writer.h"
      9 #include "base/strings/stringprintf.h"
     10 
     11 namespace content {
     12 
     13 namespace {
     14 
     15 const char kIdParam[] = "id";
     16 const char kMethodParam[] = "method";
     17 const char kParamsParam[] = "params";
     18 const char kResultParam[] = "result";
     19 const char kErrorParam[] = "error";
     20 const char kErrorCodeParam[] = "code";
     21 const char kErrorMessageParam[] = "message";
     22 const int kNoId = -1;
     23 
     24 // JSON RPC 2.0 spec: http://www.jsonrpc.org/specification#error_object
     25 enum Error {
     26   kErrorParseError = -32700,
     27   kErrorInvalidRequest = -32600,
     28   kErrorNoSuchMethod = -32601,
     29   kErrorInvalidParams = -32602,
     30   kErrorInternalError = -32603
     31 };
     32 
     33 }  // namespace
     34 
     35 using base::Value;
     36 
     37 DevToolsProtocol::Message::~Message() {
     38 }
     39 
     40 DevToolsProtocol::Message::Message(const std::string& method,
     41                                    base::DictionaryValue* params)
     42     : method_(method),
     43       params_(params) {
     44   size_t pos = method.find(".");
     45   if (pos != std::string::npos && pos > 0)
     46     domain_ = method.substr(0, pos);
     47 }
     48 
     49 DevToolsProtocol::Command::~Command() {
     50 }
     51 
     52 std::string DevToolsProtocol::Command::Serialize() {
     53   base::DictionaryValue command;
     54   command.SetInteger(kIdParam, id_);
     55   command.SetString(kMethodParam, method_);
     56   if (params_)
     57     command.Set(kParamsParam, params_->DeepCopy());
     58 
     59   std::string json_command;
     60   base::JSONWriter::Write(&command, &json_command);
     61   return json_command;
     62 }
     63 
     64 scoped_refptr<DevToolsProtocol::Response>
     65 DevToolsProtocol::Command::SuccessResponse(base::DictionaryValue* result) {
     66   return new DevToolsProtocol::Response(id_, result);
     67 }
     68 
     69 scoped_refptr<DevToolsProtocol::Response>
     70 DevToolsProtocol::Command::InternalErrorResponse(const std::string& message) {
     71   return new DevToolsProtocol::Response(id_, kErrorInternalError, message);
     72 }
     73 
     74 scoped_refptr<DevToolsProtocol::Response>
     75 DevToolsProtocol::Command::InvalidParamResponse(const std::string& param) {
     76   std::string message =
     77       base::StringPrintf("Missing or invalid '%s' parameter", param.c_str());
     78   return new DevToolsProtocol::Response(id_, kErrorInvalidParams, message);
     79 }
     80 
     81 scoped_refptr<DevToolsProtocol::Response>
     82 DevToolsProtocol::Command::NoSuchMethodErrorResponse() {
     83   return new Response(id_, kErrorNoSuchMethod, "No such method");
     84 }
     85 
     86 scoped_refptr<DevToolsProtocol::Response>
     87 DevToolsProtocol::Command::AsyncResponsePromise() {
     88   scoped_refptr<DevToolsProtocol::Response> promise =
     89       new DevToolsProtocol::Response(0, NULL);
     90   promise->is_async_promise_ = true;
     91   return promise;
     92 }
     93 
     94 DevToolsProtocol::Command::Command(int id,
     95                                    const std::string& method,
     96                                    base::DictionaryValue* params)
     97     : Message(method, params),
     98       id_(id) {
     99 }
    100 
    101 DevToolsProtocol::Response::~Response() {
    102 }
    103 
    104 std::string DevToolsProtocol::Response::Serialize() {
    105   base::DictionaryValue response;
    106 
    107   if (id_ != kNoId)
    108     response.SetInteger(kIdParam, id_);
    109 
    110   if (error_code_) {
    111     base::DictionaryValue* error_object = new base::DictionaryValue();
    112     response.Set(kErrorParam, error_object);
    113     error_object->SetInteger(kErrorCodeParam, error_code_);
    114     if (!error_message_.empty())
    115       error_object->SetString(kErrorMessageParam, error_message_);
    116   } else if (result_) {
    117     response.Set(kResultParam, result_->DeepCopy());
    118   }
    119 
    120   std::string json_response;
    121   base::JSONWriter::Write(&response, &json_response);
    122   return json_response;
    123 }
    124 
    125 DevToolsProtocol::Response::Response(int id, base::DictionaryValue* result)
    126     : id_(id),
    127       result_(result),
    128       error_code_(0),
    129       is_async_promise_(false) {
    130 }
    131 
    132 DevToolsProtocol::Response::Response(int id,
    133                                      int error_code,
    134                                      const std::string& error_message)
    135     : id_(id),
    136       error_code_(error_code),
    137       error_message_(error_message),
    138       is_async_promise_(false) {
    139 }
    140 
    141 DevToolsProtocol::Notification::Notification(const std::string& method,
    142                                              base::DictionaryValue* params)
    143     : Message(method, params) {
    144 }
    145 
    146 DevToolsProtocol::Notification::~Notification() {
    147 }
    148 
    149 std::string DevToolsProtocol::Notification::Serialize() {
    150   base::DictionaryValue notification;
    151   notification.SetString(kMethodParam, method_);
    152   if (params_)
    153     notification.Set(kParamsParam, params_->DeepCopy());
    154 
    155   std::string json_notification;
    156   base::JSONWriter::Write(&notification, &json_notification);
    157   return json_notification;
    158 }
    159 
    160 DevToolsProtocol::Handler::~Handler() {
    161 }
    162 
    163 scoped_refptr<DevToolsProtocol::Response>
    164 DevToolsProtocol::Handler::HandleCommand(
    165     scoped_refptr<DevToolsProtocol::Command> command) {
    166   CommandHandlers::iterator it = command_handlers_.find(command->method());
    167   if (it == command_handlers_.end())
    168     return NULL;
    169   return (it->second).Run(command);
    170 }
    171 
    172 void DevToolsProtocol::Handler::SetNotifier(const Notifier& notifier) {
    173   notifier_ = notifier;
    174 }
    175 
    176 DevToolsProtocol::Handler::Handler() {
    177 }
    178 
    179 void DevToolsProtocol::Handler::RegisterCommandHandler(
    180     const std::string& command,
    181     const CommandHandler& handler) {
    182   command_handlers_[command] = handler;
    183 }
    184 
    185 void DevToolsProtocol::Handler::SendNotification(
    186     const std::string& method,
    187     base::DictionaryValue* params) {
    188   scoped_refptr<DevToolsProtocol::Notification> notification =
    189       new DevToolsProtocol::Notification(method, params);
    190   SendRawMessage(notification->Serialize());
    191 }
    192 
    193 void DevToolsProtocol::Handler::SendAsyncResponse(
    194     scoped_refptr<DevToolsProtocol::Response> response) {
    195   SendRawMessage(response->Serialize());
    196 }
    197 
    198 void DevToolsProtocol::Handler::SendRawMessage(const std::string& message) {
    199   if (!notifier_.is_null())
    200     notifier_.Run(message);
    201 }
    202 
    203 static bool ParseMethod(base::DictionaryValue* command,
    204                         std::string* method) {
    205   if (!command->GetString(kMethodParam, method))
    206     return false;
    207   size_t pos = method->find(".");
    208   if (pos == std::string::npos || pos == 0)
    209     return false;
    210   return true;
    211 }
    212 
    213 // static
    214 scoped_refptr<DevToolsProtocol::Command> DevToolsProtocol::ParseCommand(
    215     const std::string& json,
    216     std::string* error_response) {
    217   scoped_ptr<base::DictionaryValue> command_dict(
    218       ParseMessage(json, error_response));
    219   if (!command_dict)
    220     return NULL;
    221 
    222   int id;
    223   std::string method;
    224   bool ok = command_dict->GetInteger(kIdParam, &id) && id >= 0;
    225   ok = ok && ParseMethod(command_dict.get(), &method);
    226   if (!ok) {
    227     scoped_refptr<Response> response =
    228         new Response(kNoId, kErrorInvalidRequest, "No such method");
    229     *error_response = response->Serialize();
    230     return NULL;
    231   }
    232 
    233   base::DictionaryValue* params = NULL;
    234   command_dict->GetDictionary(kParamsParam, &params);
    235   return new Command(id, method, params ? params->DeepCopy() : NULL);
    236 }
    237 
    238 // static
    239 scoped_refptr<DevToolsProtocol::Command>
    240 DevToolsProtocol::CreateCommand(
    241     int id,
    242     const std::string& method,
    243     base::DictionaryValue* params) {
    244   return new Command(id, method, params);
    245 }
    246 
    247 // static
    248 scoped_refptr<DevToolsProtocol::Notification>
    249 DevToolsProtocol::ParseNotification(const std::string& json) {
    250   scoped_ptr<base::DictionaryValue> dict(ParseMessage(json, NULL));
    251   if (!dict)
    252     return NULL;
    253 
    254   std::string method;
    255   bool ok = ParseMethod(dict.get(), &method);
    256   if (!ok)
    257     return NULL;
    258 
    259   base::DictionaryValue* params = NULL;
    260   dict->GetDictionary(kParamsParam, &params);
    261   return new Notification(method, params ? params->DeepCopy() : NULL);
    262 }
    263 
    264 //static
    265 scoped_refptr<DevToolsProtocol::Notification>
    266 DevToolsProtocol::CreateNotification(
    267     const std::string& method,
    268     base::DictionaryValue* params) {
    269   return new Notification(method, params);
    270 }
    271 
    272 // static
    273 base::DictionaryValue* DevToolsProtocol::ParseMessage(
    274     const std::string& json,
    275     std::string* error_response) {
    276   int parse_error_code;
    277   std::string error_message;
    278   scoped_ptr<Value> message(
    279       base::JSONReader::ReadAndReturnError(
    280           json, 0, &parse_error_code, &error_message));
    281 
    282   if (!message || !message->IsType(Value::TYPE_DICTIONARY)) {
    283     scoped_refptr<Response> response =
    284         new Response(0, kErrorParseError, error_message);
    285     if (error_response)
    286       *error_response = response->Serialize();
    287     return NULL;
    288   }
    289 
    290   return static_cast<base::DictionaryValue*>(message.release());
    291 }
    292 
    293 }  // namespace content
    294