• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
~Message()37 DevToolsProtocol::Message::~Message() {
38 }
39 
Message(const std::string & method,base::DictionaryValue * params)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 
~Command()49 DevToolsProtocol::Command::~Command() {
50 }
51 
Serialize()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>
SuccessResponse(base::DictionaryValue * result)65 DevToolsProtocol::Command::SuccessResponse(base::DictionaryValue* result) {
66   return new DevToolsProtocol::Response(id_, result);
67 }
68 
69 scoped_refptr<DevToolsProtocol::Response>
InternalErrorResponse(const std::string & message)70 DevToolsProtocol::Command::InternalErrorResponse(const std::string& message) {
71   return new DevToolsProtocol::Response(id_, kErrorInternalError, message);
72 }
73 
74 scoped_refptr<DevToolsProtocol::Response>
InvalidParamResponse(const std::string & param)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>
NoSuchMethodErrorResponse()82 DevToolsProtocol::Command::NoSuchMethodErrorResponse() {
83   return new Response(id_, kErrorNoSuchMethod, "No such method");
84 }
85 
86 scoped_refptr<DevToolsProtocol::Response>
AsyncResponsePromise()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 
Command(int id,const std::string & method,base::DictionaryValue * params)94 DevToolsProtocol::Command::Command(int id,
95                                    const std::string& method,
96                                    base::DictionaryValue* params)
97     : Message(method, params),
98       id_(id) {
99 }
100 
~Response()101 DevToolsProtocol::Response::~Response() {
102 }
103 
Serialize()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 
Response(int id,base::DictionaryValue * result)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 
Response(int id,int error_code,const std::string & error_message)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 
Notification(const std::string & method,base::DictionaryValue * params)141 DevToolsProtocol::Notification::Notification(const std::string& method,
142                                              base::DictionaryValue* params)
143     : Message(method, params) {
144 }
145 
~Notification()146 DevToolsProtocol::Notification::~Notification() {
147 }
148 
Serialize()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(&notification, &json_notification);
157   return json_notification;
158 }
159 
~Handler()160 DevToolsProtocol::Handler::~Handler() {
161 }
162 
163 scoped_refptr<DevToolsProtocol::Response>
HandleCommand(scoped_refptr<DevToolsProtocol::Command> command)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 
SetNotifier(const Notifier & notifier)172 void DevToolsProtocol::Handler::SetNotifier(const Notifier& notifier) {
173   notifier_ = notifier;
174 }
175 
Handler()176 DevToolsProtocol::Handler::Handler() {
177 }
178 
RegisterCommandHandler(const std::string & command,const CommandHandler & handler)179 void DevToolsProtocol::Handler::RegisterCommandHandler(
180     const std::string& command,
181     const CommandHandler& handler) {
182   command_handlers_[command] = handler;
183 }
184 
SendNotification(const std::string & method,base::DictionaryValue * params)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 
SendAsyncResponse(scoped_refptr<DevToolsProtocol::Response> response)193 void DevToolsProtocol::Handler::SendAsyncResponse(
194     scoped_refptr<DevToolsProtocol::Response> response) {
195   SendRawMessage(response->Serialize());
196 }
197 
SendRawMessage(const std::string & message)198 void DevToolsProtocol::Handler::SendRawMessage(const std::string& message) {
199   if (!notifier_.is_null())
200     notifier_.Run(message);
201 }
202 
ParseMethod(base::DictionaryValue * command,std::string * method)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
ParseCommand(const std::string & json,std::string * error_response)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, &params);
235   return new Command(id, method, params ? params->DeepCopy() : NULL);
236 }
237 
238 // static
239 scoped_refptr<DevToolsProtocol::Command>
CreateCommand(int id,const std::string & method,base::DictionaryValue * params)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>
ParseNotification(const std::string & json)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, &params);
261   return new Notification(method, params ? params->DeepCopy() : NULL);
262 }
263 
264 //static
265 scoped_refptr<DevToolsProtocol::Notification>
CreateNotification(const std::string & method,base::DictionaryValue * params)266 DevToolsProtocol::CreateNotification(
267     const std::string& method,
268     base::DictionaryValue* params) {
269   return new Notification(method, params);
270 }
271 
272 // static
ParseMessage(const std::string & json,std::string * error_response)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