Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / extensions / renderer / guest_view / mime_handler_view / mime_handler_view_container.cc
blobd71d6a29ade270996e1969dcde4f6d6caf43268b
1 // Copyright 2014 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.
5 #include "extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h"
7 #include <map>
8 #include <set>
10 #include "content/public/child/v8_value_converter.h"
11 #include "content/public/renderer/render_frame.h"
12 #include "content/public/renderer/render_view.h"
13 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_constants.h"
14 #include "extensions/common/extension_messages.h"
15 #include "extensions/common/guest_view/extensions_guest_view_messages.h"
16 #include "extensions/common/guest_view/guest_view_constants.h"
17 #include "extensions/common/guest_view/guest_view_messages.h"
18 #include "gin/arguments.h"
19 #include "gin/dictionary.h"
20 #include "gin/handle.h"
21 #include "gin/interceptor.h"
22 #include "gin/object_template_builder.h"
23 #include "gin/wrappable.h"
24 #include "third_party/WebKit/public/web/WebDocument.h"
25 #include "third_party/WebKit/public/web/WebLocalFrame.h"
26 #include "third_party/WebKit/public/web/WebView.h"
28 namespace extensions {
30 namespace {
32 const char kPostMessageName[] = "postMessage";
34 // The gin-backed scriptable object which is exposed by the BrowserPlugin for
35 // MimeHandlerViewContainer. This currently only implements "postMessage".
36 class ScriptableObject : public gin::Wrappable<ScriptableObject>,
37 public gin::NamedPropertyInterceptor {
38 public:
39 static gin::WrapperInfo kWrapperInfo;
41 static v8::Handle<v8::Object> Create(
42 v8::Isolate* isolate,
43 base::WeakPtr<MimeHandlerViewContainer> container) {
44 ScriptableObject* scriptable_object =
45 new ScriptableObject(isolate, container);
46 return gin::CreateHandle(isolate, scriptable_object).ToV8()->ToObject();
49 // gin::NamedPropertyInterceptor
50 v8::Local<v8::Value> GetNamedProperty(
51 v8::Isolate* isolate,
52 const std::string& identifier) override {
53 if (identifier == kPostMessageName) {
54 if (post_message_function_template_.IsEmpty()) {
55 post_message_function_template_.Reset(
56 isolate,
57 gin::CreateFunctionTemplate(
58 isolate, base::Bind(&MimeHandlerViewContainer::PostMessage,
59 container_, isolate)));
61 return v8::Local<v8::FunctionTemplate>::New(
62 isolate, post_message_function_template_)->GetFunction();
64 return v8::Local<v8::Value>();
67 private:
68 ScriptableObject(v8::Isolate* isolate,
69 base::WeakPtr<MimeHandlerViewContainer> container)
70 : gin::NamedPropertyInterceptor(isolate, this),
71 container_(container) {}
73 // gin::Wrappable
74 gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
75 v8::Isolate* isolate) override {
76 return gin::Wrappable<ScriptableObject>::GetObjectTemplateBuilder(isolate)
77 .AddNamedPropertyInterceptor();
80 base::WeakPtr<MimeHandlerViewContainer> container_;
81 v8::Persistent<v8::FunctionTemplate> post_message_function_template_;
84 // static
85 gin::WrapperInfo ScriptableObject::kWrapperInfo = { gin::kEmbedderNativeGin };
87 // Maps from content::RenderFrame to the set of MimeHandlerViewContainers within
88 // it.
89 base::LazyInstance<
90 std::map<content::RenderFrame*, std::set<MimeHandlerViewContainer*>>>
91 g_mime_handler_view_container_map = LAZY_INSTANCE_INITIALIZER;
93 } // namespace
95 MimeHandlerViewContainer::MimeHandlerViewContainer(
96 content::RenderFrame* render_frame,
97 const std::string& mime_type,
98 const GURL& original_url)
99 : GuestViewContainer(render_frame),
100 mime_type_(mime_type),
101 original_url_(original_url),
102 guest_proxy_routing_id_(-1),
103 guest_loaded_(false),
104 weak_factory_(this) {
105 DCHECK(!mime_type_.empty());
106 is_embedded_ = !render_frame->GetWebFrame()->document().isPluginDocument();
107 g_mime_handler_view_container_map.Get()[render_frame].insert(this);
110 MimeHandlerViewContainer::~MimeHandlerViewContainer() {
111 if (loader_)
112 loader_->cancel();
114 if (render_frame()) {
115 g_mime_handler_view_container_map.Get()[render_frame()].erase(this);
116 if (g_mime_handler_view_container_map.Get()[render_frame()].empty())
117 g_mime_handler_view_container_map.Get().erase(render_frame());
121 // static
122 std::vector<MimeHandlerViewContainer*>
123 MimeHandlerViewContainer::FromRenderFrame(content::RenderFrame* render_frame) {
124 auto it = g_mime_handler_view_container_map.Get().find(render_frame);
125 if (it == g_mime_handler_view_container_map.Get().end())
126 return std::vector<MimeHandlerViewContainer*>();
128 return std::vector<MimeHandlerViewContainer*>(it->second.begin(),
129 it->second.end());
132 void MimeHandlerViewContainer::Ready() {
133 if (!render_frame())
134 return;
136 blink::WebFrame* frame = render_frame()->GetWebFrame();
137 blink::WebURLLoaderOptions options;
138 // The embedded plugin is allowed to be cross-origin and we should always
139 // send credentials/cookies with the request.
140 options.crossOriginRequestPolicy =
141 blink::WebURLLoaderOptions::CrossOriginRequestPolicyAllow;
142 options.allowCredentials = true;
143 DCHECK(!loader_);
144 loader_.reset(frame->createAssociatedURLLoader(options));
146 blink::WebURLRequest request(original_url_);
147 request.setRequestContext(blink::WebURLRequest::RequestContextObject);
148 loader_->loadAsynchronously(request, this);
151 void MimeHandlerViewContainer::DidFinishLoading() {
152 DCHECK(!is_embedded_);
153 CreateMimeHandlerViewGuest();
156 void MimeHandlerViewContainer::OnRenderFrameDestroyed() {
157 g_mime_handler_view_container_map.Get().erase(render_frame());
160 void MimeHandlerViewContainer::DidReceiveData(const char* data,
161 int data_length) {
162 view_id_ += std::string(data, data_length);
165 bool MimeHandlerViewContainer::OnMessageReceived(const IPC::Message& message) {
166 bool handled = true;
167 IPC_BEGIN_MESSAGE_MAP(MimeHandlerViewContainer, message)
168 IPC_MESSAGE_HANDLER(ExtensionsGuestViewMsg_CreateMimeHandlerViewGuestACK,
169 OnCreateMimeHandlerViewGuestACK)
170 IPC_MESSAGE_HANDLER(
171 ExtensionsGuestViewMsg_MimeHandlerViewGuestOnLoadCompleted,
172 OnMimeHandlerViewGuestOnLoadCompleted)
173 IPC_MESSAGE_HANDLER(GuestViewMsg_GuestAttached, OnGuestAttached)
174 IPC_MESSAGE_UNHANDLED(handled = false)
175 IPC_END_MESSAGE_MAP()
176 return handled;
179 void MimeHandlerViewContainer::DidResizeElement(const gfx::Size& old_size,
180 const gfx::Size& new_size) {
181 element_size_ = new_size;
182 render_frame()->Send(new ExtensionsGuestViewHostMsg_ResizeGuest(
183 render_frame()->GetRoutingID(), element_instance_id(), new_size));
186 v8::Local<v8::Object> MimeHandlerViewContainer::V8ScriptableObject(
187 v8::Isolate* isolate) {
188 if (scriptable_object_.IsEmpty()) {
189 v8::Local<v8::Object> object =
190 ScriptableObject::Create(isolate, weak_factory_.GetWeakPtr());
191 scriptable_object_.Reset(isolate, object);
193 return v8::Local<v8::Object>::New(isolate, scriptable_object_);
196 void MimeHandlerViewContainer::didReceiveData(blink::WebURLLoader* /* unused */,
197 const char* data,
198 int data_length,
199 int /* unused */) {
200 view_id_ += std::string(data, data_length);
203 void MimeHandlerViewContainer::didFinishLoading(
204 blink::WebURLLoader* /* unused */,
205 double /* unused */,
206 int64_t /* unused */) {
207 DCHECK(is_embedded_);
208 CreateMimeHandlerViewGuest();
211 void MimeHandlerViewContainer::PostMessage(v8::Isolate* isolate,
212 v8::Handle<v8::Value> message) {
213 if (!guest_loaded_) {
214 linked_ptr<v8::Global<v8::Value>> global(
215 new v8::Global<v8::Value>(isolate, message));
216 pending_messages_.push_back(global);
217 return;
220 content::RenderView* guest_proxy_render_view =
221 content::RenderView::FromRoutingID(guest_proxy_routing_id_);
222 if (!guest_proxy_render_view)
223 return;
224 blink::WebFrame* guest_proxy_frame =
225 guest_proxy_render_view->GetWebView()->mainFrame();
226 if (!guest_proxy_frame)
227 return;
229 v8::Context::Scope context_scope(
230 render_frame()->GetWebFrame()->mainWorldScriptContext());
231 v8::Local<v8::Object> guest_proxy_window =
232 guest_proxy_frame->mainWorldScriptContext()->Global();
233 gin::Dictionary window_object(isolate, guest_proxy_window);
234 v8::Handle<v8::Function> post_message;
235 if (!window_object.Get(std::string(kPostMessageName), &post_message))
236 return;
238 v8::Handle<v8::Value> args[] = {
239 message,
240 // Post the message to any domain inside the browser plugin. The embedder
241 // should already know what is embedded.
242 gin::StringToV8(isolate, "*")
244 guest_proxy_frame->callFunctionEvenIfScriptDisabled(
245 post_message.As<v8::Function>(),
246 guest_proxy_window,
247 arraysize(args),
248 args);
251 void MimeHandlerViewContainer::PostMessageFromValue(
252 const base::Value& message) {
253 blink::WebFrame* frame = render_frame()->GetWebFrame();
254 if (!frame)
255 return;
257 v8::Isolate* isolate = v8::Isolate::GetCurrent();
258 v8::HandleScope handle_scope(isolate);
259 v8::Context::Scope context_scope(frame->mainWorldScriptContext());
260 scoped_ptr<content::V8ValueConverter> converter(
261 content::V8ValueConverter::create());
262 PostMessage(isolate,
263 converter->ToV8Value(&message, frame->mainWorldScriptContext()));
266 void MimeHandlerViewContainer::OnCreateMimeHandlerViewGuestACK(
267 int element_instance_id) {
268 DCHECK_NE(this->element_instance_id(), guestview::kInstanceIDNone);
269 DCHECK_EQ(this->element_instance_id(), element_instance_id);
271 if (!render_frame())
272 return;
274 render_frame()->AttachGuest(element_instance_id);
277 void MimeHandlerViewContainer::OnGuestAttached(int /* unused */,
278 int guest_proxy_routing_id) {
279 // Save the RenderView routing ID of the guest here so it can be used to route
280 // PostMessage calls.
281 guest_proxy_routing_id_ = guest_proxy_routing_id;
284 void MimeHandlerViewContainer::OnMimeHandlerViewGuestOnLoadCompleted(
285 int /* unused */) {
286 if (!render_frame())
287 return;
289 guest_loaded_ = true;
290 if (pending_messages_.empty())
291 return;
293 // Now that the guest has loaded, flush any unsent messages.
294 blink::WebFrame* frame = render_frame()->GetWebFrame();
295 if (!frame)
296 return;
298 v8::Isolate* isolate = v8::Isolate::GetCurrent();
299 v8::HandleScope handle_scope(isolate);
300 v8::Context::Scope context_scope(frame->mainWorldScriptContext());
301 for (const auto& pending_message : pending_messages_)
302 PostMessage(isolate, v8::Local<v8::Value>::New(isolate, *pending_message));
304 pending_messages_.clear();
307 void MimeHandlerViewContainer::CreateMimeHandlerViewGuest() {
308 // The loader has completed loading |view_id_| so we can dispose it.
309 loader_.reset();
311 DCHECK_NE(element_instance_id(), guestview::kInstanceIDNone);
313 if (!render_frame())
314 return;
316 render_frame()->Send(
317 new ExtensionsGuestViewHostMsg_CreateMimeHandlerViewGuest(
318 render_frame()->GetRoutingID(), view_id_, element_instance_id(),
319 element_size_));
322 } // namespace extensions