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   kErrorServerError = -32000
     32 };
     33 
     34 }  // namespace
     35 
     36 using base::Value;
     37 
     38 DevToolsProtocol::Message::~Message() {
     39 }
     40 
     41 DevToolsProtocol::Message::Message(const std::string& method,
     42                                    base::DictionaryValue* params)
     43     : method_(method),
     44       params_(params) {
     45   size_t pos = method.find(".");
     46   if (pos != std::string::npos && pos > 0)
     47     domain_ = method.substr(0, pos);
     48 }
     49 
     50 DevToolsProtocol::Command::~Command() {
     51 }
     52 
     53 std::string DevToolsProtocol::Command::Serialize() {
     54   base::DictionaryValue command;
     55   command.SetInteger(kIdParam, id_);
     56   command.SetString(kMethodParam, method_);
     57   if (params_)
     58     command.Set(kParamsParam, params_->DeepCopy());
     59 
     60   std::string json_command;
     61   base::JSONWriter::Write(&command, &json_command);
     62   return json_command;
     63 }
     64 
     65 scoped_refptr<DevToolsProtocol::Response>
     66 DevToolsProtocol::Command::SuccessResponse(base::DictionaryValue* result) {
     67   return new DevToolsProtocol::Response(id_, result);
     68 }
     69 
     70 scoped_refptr<DevToolsProtocol::Response>
     71 DevToolsProtocol::Command::InternalErrorResponse(const std::string& message) {
     72   return new DevToolsProtocol::Response(id_, kErrorInternalError, message);
     73 }
     74 
     75 scoped_refptr<DevToolsProtocol::Response>
     76 DevToolsProtocol::Command::InvalidParamResponse(const std::string& param) {
     77   std::string message =
     78       base::StringPrintf("Missing or invalid '%s' parameter", param.c_str());
     79   return new DevToolsProtocol::Response(id_, kErrorInvalidParams, message);
     80 }
     81 
     82 scoped_refptr<DevToolsProtocol::Response>
     83 DevToolsProtocol::Command::NoSuchMethodErrorResponse() {
     84   return new Response(id_, kErrorNoSuchMethod, "No such method");
     85 }
     86 
     87 scoped_refptr<DevToolsProtocol::Response>
     88 DevToolsProtocol::Command::ServerErrorResponse(const std::string& message) {
     89   return new Response(id_, kErrorServerError, message);
     90 }
     91 
     92 scoped_refptr<DevToolsProtocol::Response>
     93 DevToolsProtocol::Command::AsyncResponsePromise() {
     94   scoped_refptr<DevToolsProtocol::Response> promise =
     95       new DevToolsProtocol::Response(0, NULL);
     96   promise->is_async_promise_ = true;
     97   return promise;
     98 }
     99 
    100 DevToolsProtocol::Command::Command(int id,
    101                                    const std::string& method,
    102                                    base::DictionaryValue* params)
    103     : Message(method, params),
    104       id_(id) {
    105 }
    106 
    107 DevToolsProtocol::Response::~Response() {
    108 }
    109 
    110 std::string DevToolsProtocol::Response::Serialize() {
    111   base::DictionaryValue response;
    112 
    113   if (id_ != kNoId)
    114     response.SetInteger(kIdParam, id_);
    115 
    116   if (error_code_) {
    117     base::DictionaryValue* error_object = new base::DictionaryValue();
    118     response.Set(kErrorParam, error_object);
    119     error_object->SetInteger(kErrorCodeParam, error_code_);
    120     if (!error_message_.empty())
    121       error_object->SetString(kErrorMessageParam, error_message_);
    122   } else if (result_) {
    123     response.Set(kResultParam, result_->DeepCopy());
    124   }
    125 
    126   std::string json_response;
    127   base::JSONWriter::Write(&response, &json_response);
    128   return json_response;
    129 }
    130 
    131 DevToolsProtocol::Response::Response(int id, base::DictionaryValue* result)
    132     : id_(id),
    133       result_(result),
    134       error_code_(0),
    135       is_async_promise_(false) {
    136 }
    137 
    138 DevToolsProtocol::Response::Response(int id,
    139                                      int error_code,
    140                                      const std::string& error_message)
    141     : id_(id),
    142       error_code_(error_code),
    143       error_message_(error_message),
    144       is_async_promise_(false) {
    145 }
    146 
    147 DevToolsProtocol::Notification::Notification(const std::string& method,
    148                                              base::DictionaryValue* params)
    149     : Message(method, params) {
    150 }
    151 
    152 DevToolsProtocol::Notification::~Notification() {
    153 }
    154 
    155 std::string DevToolsProtocol::Notification::Serialize() {
    156   base::DictionaryValue notification;
    157   notification.SetString(kMethodParam, method_);
    158   if (params_)
    159     notification.Set(kParamsParam, params_->DeepCopy());
    160 
    161   std::string json_notification;
    162   base::JSONWriter::Write(&notification, &json_notification);
    163   return json_notification;
    164 }
    165 
    166 DevToolsProtocol::Handler::~Handler() {
    167 }
    168 
    169 scoped_refptr<DevToolsProtocol::Response>
    170 DevToolsProtocol::Handler::HandleCommand(
    171     scoped_refptr<DevToolsProtocol::Command> command) {
    172   CommandHandlers::iterator it = command_handlers_.find(command->method());
    173   if (it == command_handlers_.end())
    174     return NULL;
    175   return (it->second).Run(command);
    176 }
    177 
    178 void DevToolsProtocol::Handler::SetNotifier(const Notifier& notifier) {
    179   notifier_ = notifier;
    180 }
    181 
    182 DevToolsProtocol::Handler::Handler() {
    183 }
    184 
    185 void DevToolsProtocol::Handler::RegisterCommandHandler(
    186     const std::string& command,
    187     const CommandHandler& handler) {
    188   command_handlers_[command] = handler;
    189 }
    190 
    191 void DevToolsProtocol::Handler::SendNotification(
    192     const std::string& method,
    193     base::DictionaryValue* params) {
    194   scoped_refptr<DevToolsProtocol::Notification> notification =
    195       new DevToolsProtocol::Notification(method, params);
    196   SendRawMessage(notification->Serialize());
    197 }
    198 
    199 void DevToolsProtocol::Handler::SendAsyncResponse(
    200     scoped_refptr<DevToolsProtocol::Response> response) {
    201   SendRawMessage(response->Serialize());
    202 }
    203 
    204 void DevToolsProtocol::Handler::SendRawMessage(const std::string& message) {
    205   if (!notifier_.is_null())
    206     notifier_.Run(message);
    207 }
    208 
    209 static bool ParseMethod(base::DictionaryValue* command,
    210                         std::string* method) {
    211   if (!command->GetString(kMethodParam, method))
    212     return false;
    213   size_t pos = method->find(".");
    214   if (pos == std::string::npos || pos == 0)
    215     return false;
    216   return true;
    217 }
    218 
    219 // static
    220 scoped_refptr<DevToolsProtocol::Command> DevToolsProtocol::ParseCommand(
    221     const std::string& json,
    222     std::string* error_response) {
    223   scoped_ptr<base::DictionaryValue> command_dict(
    224       ParseMessage(json, error_response));
    225   return ParseCommand(command_dict.get(), error_response);
    226 }
    227 
    228 // static
    229 scoped_refptr<DevToolsProtocol::Command> DevToolsProtocol::ParseCommand(
    230     base::DictionaryValue* command_dict,
    231     std::string* error_response) {
    232   if (!command_dict)
    233     return NULL;
    234 
    235   int id;
    236   std::string method;
    237   bool ok = command_dict->GetInteger(kIdParam, &id) && id >= 0;
    238   ok = ok && ParseMethod(command_dict, &method);
    239   if (!ok) {
    240     scoped_refptr<Response> response =
    241         new Response(kNoId, kErrorInvalidRequest, "No such method");
    242     *error_response = response->Serialize();
    243     return NULL;
    244   }
    245 
    246   base::DictionaryValue* params = NULL;
    247   command_dict->GetDictionary(kParamsParam, &params);
    248   return new Command(id, method, params ? params->DeepCopy() : NULL);
    249 }
    250 
    251 // static
    252 scoped_refptr<DevToolsProtocol::Command>
    253 DevToolsProtocol::CreateCommand(
    254     int id,
    255     const std::string& method,
    256     base::DictionaryValue* params) {
    257   return new Command(id, method, params);
    258 }
    259 
    260 //static
    261 scoped_refptr<DevToolsProtocol::Response>
    262 DevToolsProtocol::ParseResponse(
    263     base::DictionaryValue* response_dict) {
    264   int id;
    265   if (!response_dict->GetInteger(kIdParam, &id))
    266     id = kNoId;
    267 
    268   const base::DictionaryValue* error_dict;
    269   if (response_dict->GetDictionary(kErrorParam, &error_dict)) {
    270     int error_code = kErrorInternalError;
    271     response_dict->GetInteger(kErrorCodeParam, &error_code);
    272     std::string error_message;
    273     response_dict->GetString(kErrorMessageParam, &error_message);
    274     return new Response(id, error_code, error_message);
    275   }
    276 
    277   const base::DictionaryValue* result = NULL;
    278   response_dict->GetDictionary(kResultParam, &result);
    279   return new Response(id, result ? result->DeepCopy() : NULL);
    280 }
    281 
    282 // static
    283 scoped_refptr<DevToolsProtocol::Notification>
    284 DevToolsProtocol::ParseNotification(const std::string& json) {
    285   scoped_ptr<base::DictionaryValue> dict(ParseMessage(json, NULL));
    286   if (!dict)
    287     return NULL;
    288 
    289   std::string method;
    290   bool ok = ParseMethod(dict.get(), &method);
    291   if (!ok)
    292     return NULL;
    293 
    294   base::DictionaryValue* params = NULL;
    295   dict->GetDictionary(kParamsParam, &params);
    296   return new Notification(method, params ? params->DeepCopy() : NULL);
    297 }
    298 
    299 //static
    300 scoped_refptr<DevToolsProtocol::Notification>
    301 DevToolsProtocol::CreateNotification(
    302     const std::string& method,
    303     base::DictionaryValue* params) {
    304   return new Notification(method, params);
    305 }
    306 
    307 // static
    308 base::DictionaryValue* DevToolsProtocol::ParseMessage(
    309     const std::string& json,
    310     std::string* error_response) {
    311   int parse_error_code;
    312   std::string error_message;
    313   scoped_ptr<base::Value> message(
    314       base::JSONReader::ReadAndReturnError(
    315           json, 0, &parse_error_code, &error_message));
    316 
    317   if (!message || !message->IsType(base::Value::TYPE_DICTIONARY)) {
    318     scoped_refptr<Response> response =
    319         new Response(0, kErrorParseError, error_message);
    320     if (error_response)
    321       *error_response = response->Serialize();
    322     return NULL;
    323   }
    324 
    325   return static_cast<base::DictionaryValue*>(message.release());
    326 }
    327 
    328 }  // namespace content
    329