devtools_protocol.cc revision bb1529ce867d8845a77ec7cdf3e3003ef1771a40
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 11namespace content { 12 13namespace { 14 15const char kIdParam[] = "id"; 16const char kMethodParam[] = "method"; 17const char kParamsParam[] = "params"; 18const char kResultParam[] = "result"; 19const char kErrorParam[] = "error"; 20const char kErrorCodeParam[] = "code"; 21const char kErrorMessageParam[] = "message"; 22const int kNoId = -1; 23 24// JSON RPC 2.0 spec: http://www.jsonrpc.org/specification#error_object 25enum Error { 26 kErrorParseError = -32700, 27 kErrorInvalidRequest = -32600, 28 kErrorNoSuchMethod = -32601, 29 kErrorInvalidParams = -32602, 30 kErrorInternalError = -32603 31}; 32 33} // namespace 34 35using base::Value; 36 37DevToolsProtocol::Message::~Message() { 38} 39 40DevToolsProtocol::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 49DevToolsProtocol::Command::~Command() { 50} 51 52std::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 64scoped_refptr<DevToolsProtocol::Response> 65DevToolsProtocol::Command::SuccessResponse(base::DictionaryValue* result) { 66 return new DevToolsProtocol::Response(id_, result); 67} 68 69scoped_refptr<DevToolsProtocol::Response> 70DevToolsProtocol::Command::InternalErrorResponse(const std::string& message) { 71 return new DevToolsProtocol::Response(id_, kErrorInternalError, message); 72} 73 74scoped_refptr<DevToolsProtocol::Response> 75DevToolsProtocol::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 81scoped_refptr<DevToolsProtocol::Response> 82DevToolsProtocol::Command::NoSuchMethodErrorResponse() { 83 return new Response(id_, kErrorNoSuchMethod, "No such method"); 84} 85 86scoped_refptr<DevToolsProtocol::Response> 87DevToolsProtocol::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 94DevToolsProtocol::Command::Command(int id, 95 const std::string& method, 96 base::DictionaryValue* params) 97 : Message(method, params), 98 id_(id) { 99} 100 101DevToolsProtocol::Response::~Response() { 102} 103 104std::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 125DevToolsProtocol::Response::Response(int id, base::DictionaryValue* result) 126 : id_(id), 127 result_(result), 128 error_code_(0), 129 is_async_promise_(false) { 130} 131 132DevToolsProtocol::Response::Response(int id, 133 int error_code, 134 const std::string& error_message) 135 : id_(id), error_code_(error_code), error_message_(error_message) {} 136 137DevToolsProtocol::Notification::Notification(const std::string& method, 138 base::DictionaryValue* params) 139 : Message(method, params) { 140} 141 142DevToolsProtocol::Notification::~Notification() { 143} 144 145std::string DevToolsProtocol::Notification::Serialize() { 146 base::DictionaryValue notification; 147 notification.SetString(kMethodParam, method_); 148 if (params_) 149 notification.Set(kParamsParam, params_->DeepCopy()); 150 151 std::string json_notification; 152 base::JSONWriter::Write(¬ification, &json_notification); 153 return json_notification; 154} 155 156DevToolsProtocol::Handler::~Handler() { 157} 158 159scoped_refptr<DevToolsProtocol::Response> 160DevToolsProtocol::Handler::HandleCommand( 161 scoped_refptr<DevToolsProtocol::Command> command) { 162 CommandHandlers::iterator it = command_handlers_.find(command->method()); 163 if (it == command_handlers_.end()) 164 return NULL; 165 return (it->second).Run(command); 166} 167 168void DevToolsProtocol::Handler::SetNotifier(const Notifier& notifier) { 169 notifier_ = notifier; 170} 171 172DevToolsProtocol::Handler::Handler() { 173} 174 175void DevToolsProtocol::Handler::RegisterCommandHandler( 176 const std::string& command, 177 const CommandHandler& handler) { 178 command_handlers_[command] = handler; 179} 180 181void DevToolsProtocol::Handler::SendNotification( 182 const std::string& method, 183 base::DictionaryValue* params) { 184 scoped_refptr<DevToolsProtocol::Notification> notification = 185 new DevToolsProtocol::Notification(method, params); 186 SendRawMessage(notification->Serialize()); 187} 188 189void DevToolsProtocol::Handler::SendRawMessage(const std::string& message) { 190 if (!notifier_.is_null()) 191 notifier_.Run(message); 192} 193 194static bool ParseMethod(base::DictionaryValue* command, 195 std::string* method) { 196 if (!command->GetString(kMethodParam, method)) 197 return false; 198 size_t pos = method->find("."); 199 if (pos == std::string::npos || pos == 0) 200 return false; 201 return true; 202} 203 204// static 205scoped_refptr<DevToolsProtocol::Command> DevToolsProtocol::ParseCommand( 206 const std::string& json, 207 std::string* error_response) { 208 scoped_ptr<base::DictionaryValue> command_dict( 209 ParseMessage(json, error_response)); 210 if (!command_dict) 211 return NULL; 212 213 int id; 214 std::string method; 215 bool ok = command_dict->GetInteger(kIdParam, &id) && id >= 0; 216 ok = ok && ParseMethod(command_dict.get(), &method); 217 if (!ok) { 218 scoped_refptr<Response> response = 219 new Response(kNoId, kErrorInvalidRequest, "No such method"); 220 *error_response = response->Serialize(); 221 return NULL; 222 } 223 224 base::DictionaryValue* params = NULL; 225 command_dict->GetDictionary(kParamsParam, ¶ms); 226 return new Command(id, method, params ? params->DeepCopy() : NULL); 227} 228 229// static 230scoped_refptr<DevToolsProtocol::Notification> 231DevToolsProtocol::ParseNotification(const std::string& json) { 232 scoped_ptr<base::DictionaryValue> dict(ParseMessage(json, NULL)); 233 if (!dict) 234 return NULL; 235 236 std::string method; 237 bool ok = ParseMethod(dict.get(), &method); 238 if (!ok) 239 return NULL; 240 241 base::DictionaryValue* params = NULL; 242 dict->GetDictionary(kParamsParam, ¶ms); 243 return new Notification(method, params ? params->DeepCopy() : NULL); 244} 245 246//static 247scoped_refptr<DevToolsProtocol::Notification> 248DevToolsProtocol::CreateNotification( 249 const std::string& method, 250 base::DictionaryValue* params) { 251 return new Notification(method, params); 252} 253 254// static 255base::DictionaryValue* DevToolsProtocol::ParseMessage( 256 const std::string& json, 257 std::string* error_response) { 258 int parse_error_code; 259 std::string error_message; 260 scoped_ptr<Value> message( 261 base::JSONReader::ReadAndReturnError( 262 json, 0, &parse_error_code, &error_message)); 263 264 if (!message || !message->IsType(Value::TYPE_DICTIONARY)) { 265 scoped_refptr<Response> response = 266 new Response(0, kErrorParseError, error_message); 267 if (error_response) 268 *error_response = response->Serialize(); 269 return NULL; 270 } 271 272 return static_cast<base::DictionaryValue*>(message.release()); 273} 274 275} // namespace content 276