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