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(¬ification, &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, ¶ms); 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, ¶ms); 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