1// Copyright (c) 2012 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/renderer/dom_automation_controller.h"
6
7#include "base/json/json_string_value_serializer.h"
8#include "base/strings/string_util.h"
9#include "content/common/child_process_messages.h"
10#include "content/common/frame_messages.h"
11#include "content/renderer/render_view_impl.h"
12#include "content/renderer/v8_value_converter_impl.h"
13#include "gin/handle.h"
14#include "gin/object_template_builder.h"
15#include "third_party/WebKit/public/web/WebFrame.h"
16#include "third_party/WebKit/public/web/WebKit.h"
17
18namespace content {
19
20gin::WrapperInfo DomAutomationController::kWrapperInfo = {
21    gin::kEmbedderNativeGin};
22
23// static
24void DomAutomationController::Install(RenderFrame* render_frame,
25                                      blink::WebFrame* frame) {
26  v8::Isolate* isolate = blink::mainThreadIsolate();
27  v8::HandleScope handle_scope(isolate);
28  v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
29  if (context.IsEmpty())
30    return;
31
32  v8::Context::Scope context_scope(context);
33
34  gin::Handle<DomAutomationController> controller =
35      gin::CreateHandle(isolate, new DomAutomationController(render_frame));
36  if (controller.IsEmpty())
37    return;
38
39  v8::Handle<v8::Object> global = context->Global();
40  global->Set(gin::StringToV8(isolate, "domAutomationController"),
41              controller.ToV8());
42}
43
44DomAutomationController::DomAutomationController(RenderFrame* render_frame)
45    : RenderFrameObserver(render_frame), automation_id_(MSG_ROUTING_NONE) {}
46
47DomAutomationController::~DomAutomationController() {}
48
49gin::ObjectTemplateBuilder DomAutomationController::GetObjectTemplateBuilder(
50    v8::Isolate* isolate) {
51  return gin::Wrappable<DomAutomationController>::GetObjectTemplateBuilder(
52             isolate)
53      .SetMethod("send", &DomAutomationController::SendMsg)
54      .SetMethod("setAutomationId", &DomAutomationController::SetAutomationId)
55      .SetMethod("sendJSON", &DomAutomationController::SendJSON)
56      .SetMethod("sendWithId", &DomAutomationController::SendWithId);
57}
58
59void DomAutomationController::OnDestruct() {}
60
61bool DomAutomationController::SendMsg(const gin::Arguments& args) {
62  if (!render_frame())
63    return false;
64
65  if (automation_id_ == MSG_ROUTING_NONE)
66    return false;
67
68  std::string json;
69  JSONStringValueSerializer serializer(&json);
70  scoped_ptr<base::Value> value;
71
72  // Warning: note that JSON officially requires the root-level object to be
73  // an object (e.g. {foo:3}) or an array, while here we're serializing
74  // strings, bools, etc. to "JSON".  This only works because (a) the JSON
75  // writer is lenient, and (b) on the receiving side we wrap the JSON string
76  // in square brackets, converting it to an array, then parsing it and
77  // grabbing the 0th element to get the value out.
78  if (args.PeekNext()->IsString() || args.PeekNext()->IsBoolean() ||
79      args.PeekNext()->IsNumber()) {
80    V8ValueConverterImpl conv;
81    value.reset(
82        conv.FromV8Value(args.PeekNext(), args.isolate()->GetCurrentContext()));
83  } else {
84    return false;
85  }
86
87  if (!serializer.Serialize(*value))
88    return false;
89
90  bool succeeded = Send(new FrameHostMsg_DomOperationResponse(
91      routing_id(), json, automation_id_));
92
93  automation_id_ = MSG_ROUTING_NONE;
94  return succeeded;
95}
96
97bool DomAutomationController::SendJSON(const std::string& json) {
98  if (!render_frame())
99    return false;
100
101  if (automation_id_ == MSG_ROUTING_NONE)
102    return false;
103  bool result = Send(new FrameHostMsg_DomOperationResponse(
104      routing_id(), json, automation_id_));
105
106  automation_id_ = MSG_ROUTING_NONE;
107  return result;
108}
109
110bool DomAutomationController::SendWithId(int automation_id,
111                                         const std::string& str) {
112  if (!render_frame())
113    return false;
114  return Send(
115      new FrameHostMsg_DomOperationResponse(routing_id(), str, automation_id));
116}
117
118bool DomAutomationController::SetAutomationId(int automation_id) {
119  automation_id_ = automation_id;
120  return true;
121}
122
123}  // namespace content
124