1bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// found in the LICENSE file.
4bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
5bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "chrome/browser/devtools/devtools_protocol.h"
6bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
7bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "base/json/json_reader.h"
8bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "base/json/json_writer.h"
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/strings/stringprintf.h"
10bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
11bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochnamespace {
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kErrorCodeParam[] = "code";
14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kErrorParam[] = "error";
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kErrorMessageParam[] = "message";
16bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochconst char kIdParam[] = "id";
17bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochconst char kMethodParam[] = "method";
18bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochconst char kParamsParam[] = "params";
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kResultParam[] = "result";
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// JSON RPC 2.0 spec: http://www.jsonrpc.org/specification#error_object
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)enum Error {
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  kErrorInvalidParams = -32602
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
26bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}  // namespace
27bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
28bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochDevToolsProtocol::Message::~Message() {
29bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
30bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
31bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochDevToolsProtocol::Message::Message(const std::string& method,
32bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                                   base::DictionaryValue* params)
33bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    : method_(method),
34bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      params_(params ? params->DeepCopy() : NULL) {
35bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
36bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
37bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochDevToolsProtocol::Command::Command(int id,
38bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                                   const std::string& method,
39bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                                   base::DictionaryValue* params)
40bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    : Message(method, params),
41bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      id_(id) {
42bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
43bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
44bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochDevToolsProtocol::Command::~Command() {
45bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
46bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
47bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochstd::string DevToolsProtocol::Command::Serialize() {
48bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  base::DictionaryValue command;
49bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  command.SetInteger(kIdParam, id_);
50bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  command.SetString(kMethodParam, method_);
51bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  if (params_)
52bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    command.Set(kParamsParam, params_->DeepCopy());
53bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
54bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  std::string json_command;
55bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  base::JSONWriter::Write(&command, &json_command);
56bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  return json_command;
57bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
58bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)scoped_ptr<DevToolsProtocol::Response>
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)DevToolsProtocol::Command::SuccessResponse(base::DictionaryValue* result) {
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return scoped_ptr<DevToolsProtocol::Response>(
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      new DevToolsProtocol::Response(id_, result));
63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)scoped_ptr<DevToolsProtocol::Response>
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)DevToolsProtocol::Command::InvalidParamResponse(const std::string& param) {
67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string message =
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::StringPrintf("Missing or invalid '%s' parameter", param.c_str());
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return scoped_ptr<DevToolsProtocol::Response>(
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      new DevToolsProtocol::Response(id_, kErrorInvalidParams, message));
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
73bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochDevToolsProtocol::Notification::~Notification() {
74bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
75bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
76bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochDevToolsProtocol::Notification::Notification(const std::string& method,
77bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                                             base::DictionaryValue* params)
78bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    : Message(method, params) {
79bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
80bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
81c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben MurdochDevToolsProtocol::Response::~Response() {
82c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
83c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)DevToolsProtocol::Response::Response(int id,
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                     int error_code,
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                     const std::string error_message)
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    : id_(id),
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      error_code_(error_code),
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      error_message_(error_message) {
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)DevToolsProtocol::Response::Response(int id, base::DictionaryValue* result)
93c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    : id_(id),
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      error_code_(0),
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      result_(result) {
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)base::DictionaryValue* DevToolsProtocol::Response::Serialize() {
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::DictionaryValue* response = new base::DictionaryValue();
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  response->SetInteger(kIdParam, id_);
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (error_code_) {
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    base::DictionaryValue* error_object = new base::DictionaryValue();
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    response->Set(kErrorParam, error_object);
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    error_object->SetInteger(kErrorCodeParam, error_code_);
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!error_message_.empty())
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      error_object->SetString(kErrorMessageParam, error_message_);
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else {
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (result_)
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      response->Set(kResultParam, result_->DeepCopy());
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    else
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      response->Set(kResultParam, new base::DictionaryValue());
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return response;
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)DevToolsProtocol::Command* DevToolsProtocol::ParseCommand(
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    base::DictionaryValue* command_dict) {
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!command_dict)
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return NULL;
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int id;
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!command_dict->GetInteger(kIdParam, &id) || id < 0)
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return NULL;
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string method;
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!command_dict->GetString(kMethodParam, &method))
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return NULL;
132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::DictionaryValue* params = NULL;
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  command_dict->GetDictionary(kParamsParam, &params);
135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return new Command(id, method, params);
136c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
137c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
138bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// static
139bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochDevToolsProtocol::Notification* DevToolsProtocol::ParseNotification(
140bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    const std::string& json) {
141bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  scoped_ptr<base::Value> value(base::JSONReader::Read(json));
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!value || !value->IsType(base::Value::TYPE_DICTIONARY))
143bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    return NULL;
144bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
145bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  scoped_ptr<base::DictionaryValue> dict(
146bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      static_cast<base::DictionaryValue*>(value.release()));
147bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
148bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  std::string method;
149bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  if (!dict->GetString(kMethodParam, &method))
150bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    return NULL;
151bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
152bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  base::DictionaryValue* params = NULL;
153bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  dict->GetDictionary(kParamsParam, &params);
154bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  return new Notification(method, params);
155bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
156c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
157c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben MurdochDevToolsProtocol::Response* DevToolsProtocol::ParseResponse(
158c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    const std::string& json) {
159c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  scoped_ptr<base::Value> value(base::JSONReader::Read(json));
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!value || !value->IsType(base::Value::TYPE_DICTIONARY))
161c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    return NULL;
162c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
163c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  scoped_ptr<base::DictionaryValue> dict(
164c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      static_cast<base::DictionaryValue*>(value.release()));
165c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
166c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  int id;
167c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  if (!dict->GetInteger(kIdParam, &id))
168c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    return NULL;
169c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
170c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  int error_code = 0;
171c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  base::DictionaryValue* error_dict = NULL;
172c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  if (dict->GetDictionary(kErrorParam, &error_dict))
173c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    error_dict->GetInteger(kErrorCodeParam, &error_code);
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return new Response(id, error_code, std::string());
175c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
176