Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / browser / devtools / devtools_protocol.cc
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(&notification, &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::HandleNotification(
182     scoped_refptr<DevToolsProtocol::Notification> notification) {
183   NotificationHandlers::iterator it =
184     notification_handlers_.find(notification->method());
185   if (it == notification_handlers_.end())
186     return;
187   (it->second).Run(notification);
188 }
189
190 void DevToolsProtocol::Handler::SetNotifier(const Notifier& notifier) {
191   notifier_ = notifier;
192 }
193
194 DevToolsProtocol::Handler::Handler() {
195 }
196
197 void DevToolsProtocol::Handler::RegisterCommandHandler(
198     const std::string& command,
199     const CommandHandler& handler) {
200   command_handlers_[command] = handler;
201 }
202
203 void DevToolsProtocol::Handler::RegisterNotificationHandler(
204     const std::string& notification,
205     const NotificationHandler& handler) {
206   notification_handlers_[notification] = handler;
207 }
208
209 void DevToolsProtocol::Handler::SendNotification(
210     const std::string& method,
211     base::DictionaryValue* params) {
212   scoped_refptr<DevToolsProtocol::Notification> notification =
213       new DevToolsProtocol::Notification(method, params);
214   SendRawMessage(notification->Serialize());
215 }
216
217 void DevToolsProtocol::Handler::SendAsyncResponse(
218     scoped_refptr<DevToolsProtocol::Response> response) {
219   SendRawMessage(response->Serialize());
220 }
221
222 void DevToolsProtocol::Handler::SendRawMessage(const std::string& message) {
223   if (!notifier_.is_null())
224     notifier_.Run(message);
225 }
226
227 static bool ParseMethod(base::DictionaryValue* command,
228                         std::string* method) {
229   if (!command->GetString(kMethodParam, method))
230     return false;
231   size_t pos = method->find(".");
232   if (pos == std::string::npos || pos == 0)
233     return false;
234   return true;
235 }
236
237 // static
238 scoped_refptr<DevToolsProtocol::Command> DevToolsProtocol::ParseCommand(
239     const std::string& json,
240     std::string* error_response) {
241   scoped_ptr<base::DictionaryValue> command_dict(
242       ParseMessage(json, error_response));
243   return ParseCommand(command_dict.get(), error_response);
244 }
245
246 // static
247 scoped_refptr<DevToolsProtocol::Command> DevToolsProtocol::ParseCommand(
248     base::DictionaryValue* command_dict,
249     std::string* error_response) {
250   if (!command_dict)
251     return NULL;
252
253   int id;
254   std::string method;
255   bool ok = command_dict->GetInteger(kIdParam, &id) && id >= 0;
256   ok = ok && ParseMethod(command_dict, &method);
257   if (!ok) {
258     scoped_refptr<Response> response =
259         new Response(kNoId, kErrorInvalidRequest, "No such method");
260     *error_response = response->Serialize();
261     return NULL;
262   }
263
264   base::DictionaryValue* params = NULL;
265   command_dict->GetDictionary(kParamsParam, &params);
266   return new Command(id, method, params ? params->DeepCopy() : NULL);
267 }
268
269 // static
270 scoped_refptr<DevToolsProtocol::Command>
271 DevToolsProtocol::CreateCommand(
272     int id,
273     const std::string& method,
274     base::DictionaryValue* params) {
275   return new Command(id, method, params);
276 }
277
278 //static
279 scoped_refptr<DevToolsProtocol::Response>
280 DevToolsProtocol::ParseResponse(
281     base::DictionaryValue* response_dict) {
282   int id;
283   if (!response_dict->GetInteger(kIdParam, &id))
284     id = kNoId;
285
286   const base::DictionaryValue* error_dict;
287   if (response_dict->GetDictionary(kErrorParam, &error_dict)) {
288     int error_code = kErrorInternalError;
289     response_dict->GetInteger(kErrorCodeParam, &error_code);
290     std::string error_message;
291     response_dict->GetString(kErrorMessageParam, &error_message);
292     return new Response(id, error_code, error_message);
293   }
294
295   const base::DictionaryValue* result = NULL;
296   response_dict->GetDictionary(kResultParam, &result);
297   return new Response(id, result ? result->DeepCopy() : NULL);
298 }
299
300 // static
301 scoped_refptr<DevToolsProtocol::Notification>
302 DevToolsProtocol::ParseNotification(const std::string& json) {
303   scoped_ptr<base::DictionaryValue> dict(ParseMessage(json, NULL));
304   if (!dict)
305     return NULL;
306
307   std::string method;
308   bool ok = ParseMethod(dict.get(), &method);
309   if (!ok)
310     return NULL;
311
312   base::DictionaryValue* params = NULL;
313   dict->GetDictionary(kParamsParam, &params);
314   return new Notification(method, params ? params->DeepCopy() : NULL);
315 }
316
317 //static
318 scoped_refptr<DevToolsProtocol::Notification>
319 DevToolsProtocol::CreateNotification(
320     const std::string& method,
321     base::DictionaryValue* params) {
322   return new Notification(method, params);
323 }
324
325 // static
326 base::DictionaryValue* DevToolsProtocol::ParseMessage(
327     const std::string& json,
328     std::string* error_response) {
329   int parse_error_code;
330   std::string error_message;
331   scoped_ptr<base::Value> message(
332       base::JSONReader::ReadAndReturnError(
333           json, 0, &parse_error_code, &error_message));
334
335   if (!message || !message->IsType(base::Value::TYPE_DICTIONARY)) {
336     scoped_refptr<Response> response =
337         new Response(0, kErrorParseError, error_message);
338     if (error_response)
339       *error_response = response->Serialize();
340     return NULL;
341   }
342
343   return static_cast<base::DictionaryValue*>(message.release());
344 }
345
346 }  // namespace content