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/frame_messages.h"
10 #include "content/renderer/render_view_impl.h"
11 #include "content/renderer/v8_value_converter_impl.h"
12 #include "gin/handle.h"
13 #include "gin/object_template_builder.h"
14 #include "third_party/blink/public/web/blink.h"
15 #include "third_party/blink/public/web/web_local_frame.h"
16 
17 namespace content {
18 
19 gin::WrapperInfo DomAutomationController::kWrapperInfo = {
20     gin::kEmbedderNativeGin};
21 
22 // static
Install(RenderFrame * render_frame,blink::WebLocalFrame * frame)23 void DomAutomationController::Install(RenderFrame* render_frame,
24                                       blink::WebLocalFrame* frame) {
25   v8::Isolate* isolate = blink::MainThreadIsolate();
26   v8::HandleScope handle_scope(isolate);
27   v8::Local<v8::Context> context = frame->MainWorldScriptContext();
28   if (context.IsEmpty())
29     return;
30 
31   v8::Context::Scope context_scope(context);
32 
33   gin::Handle<DomAutomationController> controller =
34       gin::CreateHandle(isolate, new DomAutomationController(render_frame));
35   if (controller.IsEmpty())
36     return;
37 
38   v8::Local<v8::Object> global = context->Global();
39   global
40       ->Set(context, gin::StringToV8(isolate, "domAutomationController"),
41             controller.ToV8())
42       .Check();
43 }
44 
DomAutomationController(RenderFrame * render_frame)45 DomAutomationController::DomAutomationController(RenderFrame* render_frame)
46     : RenderFrameObserver(render_frame) {}
47 
~DomAutomationController()48 DomAutomationController::~DomAutomationController() {}
49 
GetObjectTemplateBuilder(v8::Isolate * isolate)50 gin::ObjectTemplateBuilder DomAutomationController::GetObjectTemplateBuilder(
51     v8::Isolate* isolate) {
52   return gin::Wrappable<DomAutomationController>::GetObjectTemplateBuilder(
53              isolate)
54       .SetMethod("send", &DomAutomationController::SendMsg);
55 }
56 
OnDestruct()57 void DomAutomationController::OnDestruct() {}
58 
DidCreateScriptContext(v8::Local<v8::Context> context,int32_t world_id)59 void DomAutomationController::DidCreateScriptContext(
60     v8::Local<v8::Context> context,
61     int32_t world_id) {
62   // Add the domAutomationController to isolated worlds as well.
63   v8::Isolate* isolate = blink::MainThreadIsolate();
64   v8::HandleScope handle_scope(isolate);
65   if (context.IsEmpty())
66     return;
67 
68   v8::Context::Scope context_scope(context);
69 
70   // Resuse this object instead of creating others.
71   gin::Handle<DomAutomationController> controller =
72       gin::CreateHandle(isolate, this);
73   if (controller.IsEmpty())
74     return;
75 
76   v8::Local<v8::Object> global = context->Global();
77   global
78       ->Set(context, gin::StringToV8(isolate, "domAutomationController"),
79             controller.ToV8())
80       .Check();
81 }
82 
SendMsg(const gin::Arguments & args)83 bool DomAutomationController::SendMsg(const gin::Arguments& args) {
84   if (!render_frame())
85     return false;
86 
87   std::string json;
88   JSONStringValueSerializer serializer(&json);
89   std::unique_ptr<base::Value> value;
90 
91   // Warning: note that JSON officially requires the root-level object to be
92   // an object (e.g. {foo:3}) or an array, while here we're serializing
93   // strings, bools, etc. to "JSON".  This only works because (a) the JSON
94   // writer is lenient, and (b) on the receiving side we wrap the JSON string
95   // in square brackets, converting it to an array, then parsing it and
96   // grabbing the 0th element to get the value out.
97   if (!args.PeekNext().IsEmpty()) {
98     V8ValueConverterImpl conv;
99     value =
100         conv.FromV8Value(args.PeekNext(), args.isolate()->GetCurrentContext());
101   } else {
102     NOTREACHED() << "No arguments passed to domAutomationController.send";
103     return false;
104   }
105 
106   if (!value || !serializer.Serialize(*value))
107     return false;
108 
109   GetDomAutomationControllerHost()->DomOperationResponse(json);
110   return true;
111 }
112 
113 const mojo::AssociatedRemote<mojom::DomAutomationControllerHost>&
GetDomAutomationControllerHost()114 DomAutomationController::GetDomAutomationControllerHost() {
115   if (!dom_automation_controller_host_) {
116     render_frame()->GetRemoteAssociatedInterfaces()->GetInterface(
117         &dom_automation_controller_host_);
118   }
119   return dom_automation_controller_host_;
120 }
121 
122 }  // namespace content
123