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 {
    123     if (result_)
    124       response.Set(kResultParam, result_->DeepCopy());
    125     else
    126       response.Set(kResultParam, new base::DictionaryValue());
    127   }
    128 
    129   std::string json_response;
    130   base::JSONWriter::Write(&response, &json_response);
    131   return json_response;
    132 }
    133 
    134 DevToolsProtocol::Response::Response(int id, base::DictionaryValue* result)
    135     : id_(id),
    136       result_(result),
    137       error_code_(0),
    138       is_async_promise_(false) {
    139 }
    140 
    141 DevToolsProtocol::Response::Response(int id,
    142                                      int error_code,
    143                                      const std::string& error_message)
    144     : id_(id),
    145       error_code_(error_code),
    146       error_message_(error_message),
    147       is_async_promise_(false) {
    148 }
    149 
    150 DevToolsProtocol::Notification::Notification(const std::string& method,
    151                                              base::DictionaryValue* params)
    152     : Message(method, params) {
    153 }
    154 
    155 DevToolsProtocol::Notification::~Notification() {
    156 }
    157 
    158 std::string DevToolsProtocol::Notification::Serialize() {
    159   base::DictionaryValue notification;
    160   notification.SetString(kMethodParam, method_);
    161   if (params_)
    162     notification.Set(kParamsParam, params_->DeepCopy());
    163 
    164   std::string json_notification;
    165   base::JSONWriter::Write(&notification, &json_notification);
    166   return json_notification;
    167 }
    168 
    169 DevToolsProtocol::Handler::~Handler() {
    170 }
    171 
    172 scoped_refptr<DevToolsProtocol::Response>
    173 DevToolsProtocol::Handler::HandleCommand(
    174     scoped_refptr<DevToolsProtocol::Command> command) {
    175   CommandHandlers::iterator it = command_handlers_.find(command->method());
    176   if (it == command_handlers_.end())
    177     return NULL;
    178   return (it->second).Run(command);
    179 }
    180 
    181 void DevToolsProtocol::Handler::SetNotifier(const Notifier& notifier) {
    182   notifier_ = notifier;
    183 }
    184 
    185 DevToolsProtocol::Handler::Handler() {
    186 }
    187 
    188 void DevToolsProtocol::Handler::RegisterCommandHandler(
    189     const std::string& command,
    190     const CommandHandler& handler) {
    191   command_handlers_[command] = handler;
    192 }
    193 
    194 void DevToolsProtocol::Handler::SendNotification(
    195     const std::string& method,
    196     base::DictionaryValue* params) {
    197   scoped_refptr<DevToolsProtocol::Notification> notification =
    198       new DevToolsProtocol::Notification(method, params);
    199   SendRawMessage(notification->Serialize());
    200 }
    201 
    202 void DevToolsProtocol::Handler::SendAsyncResponse(
    203     scoped_refptr<DevToolsProtocol::Response> response) {
    204   SendRawMessage(response->Serialize());
    205 }
    206 
    207 void DevToolsProtocol::Handler::SendRawMessage(const std::string& message) {
    208   if (!notifier_.is_null())
    209     notifier_.Run(message);
    210 }
    211 
    212 static bool ParseMethod(base::DictionaryValue* command,
    213                         std::string* method) {
    214   if (!command->GetString(kMethodParam, method))
    215     return false;
    216   size_t pos = method->find(".");
    217   if (pos == std::string::npos || pos == 0)
    218     return false;
    219   return true;
    220 }
    221 
    222 // static
    223 scoped_refptr<DevToolsProtocol::Command> DevToolsProtocol::ParseCommand(
    224     const std::string& json,
    225     std::string* error_response) {
    226   scoped_ptr<base::DictionaryValue> command_dict(
    227       ParseMessage(json, error_response));
    228   return ParseCommand(command_dict.get(), error_response);
    229 }
    230 
    231 // static
    232 scoped_refptr<DevToolsProtocol::Command> DevToolsProtocol::ParseCommand(
    233     base::DictionaryValue* command_dict,
    234     std::string* error_response) {
    235   if (!command_dict)
    236     return NULL;
    237 
    238   int id;
    239   std::string method;
    240   bool ok = command_dict->GetInteger(kIdParam, &id) && id >= 0;
    241   ok = ok && ParseMethod(command_dict, &method);
    242   if (!ok) {
    243     scoped_refptr<Response> response =
    244         new Response(kNoId, kErrorInvalidRequest, "No such method");
    245     *error_response = response->Serialize();
    246     return NULL;
    247   }
    248 
    249   base::DictionaryValue* params = NULL;
    250   command_dict->GetDictionary(kParamsParam, &params);
    251   return new Command(id, method, params ? params->DeepCopy() : NULL);
    252 }
    253 
    254 // static
    255 scoped_refptr<DevToolsProtocol::Command>
    256 DevToolsProtocol::CreateCommand(
    257     int id,
    258     const std::string& method,
    259     base::DictionaryValue* params) {
    260   return new Command(id, method, params);
    261 }
    262 
    263 //static
    264 scoped_refptr<DevToolsProtocol::Response>
    265 DevToolsProtocol::ParseResponse(
    266     base::DictionaryValue* response_dict) {
    267   int id;
    268   if (!response_dict->GetInteger(kIdParam, &id))
    269     id = kNoId;
    270 
    271   const base::DictionaryValue* error_dict;
    272   if (response_dict->GetDictionary(kErrorParam, &error_dict)) {
    273     int error_code = kErrorInternalError;
    274     response_dict->GetInteger(kErrorCodeParam, &error_code);
    275     std::string error_message;
    276     response_dict->GetString(kErrorMessageParam, &error_message);
    277     return new Response(id, error_code, error_message);
    278   }
    279 
    280   const base::DictionaryValue* result = NULL;
    281   response_dict->GetDictionary(kResultParam, &result);
    282   return new Response(id, result ? result->DeepCopy() : NULL);
    283 }
    284 
    285 // static
    286 scoped_refptr<DevToolsProtocol::Notification>
    287 DevToolsProtocol::ParseNotification(const std::string& json) {
    288   scoped_ptr<base::DictionaryValue> dict(ParseMessage(json, NULL));
    289   if (!dict)
    290     return NULL;
    291 
    292   std::string method;
    293   bool ok = ParseMethod(dict.get(), &method);
    294   if (!ok)
    295     return NULL;
    296 
    297   base::DictionaryValue* params = NULL;
    298   dict->GetDictionary(kParamsParam, &params);
    299   return new Notification(method, params ? params->DeepCopy() : NULL);
    300 }
    301 
    302 //static
    303 scoped_refptr<DevToolsProtocol::Notification>
    304 DevToolsProtocol::CreateNotification(
    305     const std::string& method,
    306     base::DictionaryValue* params) {
    307   return new Notification(method, params);
    308 }
    309 
    310 // static
    311 base::DictionaryValue* DevToolsProtocol::ParseMessage(
    312     const std::string& json,
    313     std::string* error_response) {
    314   int parse_error_code;
    315   std::string error_message;
    316   scoped_ptr<base::Value> message(
    317       base::JSONReader::ReadAndReturnError(
    318           json, 0, &parse_error_code, &error_message));
    319 
    320   if (!message || !message->IsType(base::Value::TYPE_DICTIONARY)) {
    321     scoped_refptr<Response> response =
    322         new Response(0, kErrorParseError, error_message);
    323     if (error_response)
    324       *error_response = response->Serialize();
    325     return NULL;
    326   }
    327 
    328   return static_cast<base::DictionaryValue*>(message.release());
    329 }
    330 
    331 }  // namespace content
    332