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