1 // Copyright 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 #ifndef EXTENSIONS_RENDERER_EXTENSION_FRAME_HELPER_H_
6 #define EXTENSIONS_RENDERER_EXTENSION_FRAME_HELPER_H_
7 
8 #include <string>
9 #include <vector>
10 
11 #include "base/callback_forward.h"
12 #include "base/macros.h"
13 #include "base/memory/weak_ptr.h"
14 #include "content/public/renderer/render_frame_observer.h"
15 #include "content/public/renderer/render_frame_observer_tracker.h"
16 #include "extensions/common/view_type.h"
17 #include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
18 #include "v8/include/v8.h"
19 
20 struct ExtensionMsg_ExternalConnectionInfo;
21 struct ExtensionMsg_TabConnectionInfo;
22 
23 namespace base {
24 class ListValue;
25 }
26 
27 namespace extensions {
28 
29 class Dispatcher;
30 struct Message;
31 struct PortId;
32 class ScriptContext;
33 
34 // RenderFrame-level plumbing for extension features.
35 class ExtensionFrameHelper
36     : public content::RenderFrameObserver,
37       public content::RenderFrameObserverTracker<ExtensionFrameHelper> {
38  public:
39   ExtensionFrameHelper(content::RenderFrame* render_frame,
40                        Dispatcher* extension_dispatcher);
41   ~ExtensionFrameHelper() override;
42 
43   // Returns a list of extension RenderFrames that match the given filter
44   // criteria. A |browser_window_id| of extension_misc::kUnknownWindowId
45   // specifies "all", as does a |view_type| of VIEW_TYPE_INVALID.
46   static std::vector<content::RenderFrame*> GetExtensionFrames(
47       const std::string& extension_id,
48       int browser_window_id,
49       int tab_id,
50       ViewType view_type);
51   // Same as above, but returns a v8::Array of the v8 global objects for those
52   // frames, and only includes main frames. Note: This only returns contexts
53   // that are accessible by |context|, and |context| must be the current
54   // context.
55   // Returns an empty v8::Array if no frames are found.
56   static v8::Local<v8::Array> GetV8MainFrames(v8::Local<v8::Context> context,
57                                               const std::string& extension_id,
58                                               int browser_window_id,
59                                               int tab_id,
60                                               ViewType view_type);
61 
62   // Returns the main frame of the extension's background page, or null if there
63   // isn't one in this process.
64   static content::RenderFrame* GetBackgroundPageFrame(
65       const std::string& extension_id);
66   // Same as above, but returns the background page's main frame, or
67   // v8::Undefined if there is none. Note: This will assert that the
68   // isolate's current context can access the returned object; callers should
69   // ensure that the current context is correct.
70   static v8::Local<v8::Value> GetV8BackgroundPageMainFrame(
71       v8::Isolate* isolate,
72       const std::string& extension_id);
73 
74   // Finds a neighboring extension frame with the same extension as the one
75   // owning |relative_to_frame| (if |relative_to_frame| is not an extension
76   // frame, returns nullptr). Pierces the browsing instance boundary because
77   // certain extensions rely on this behavior.
78   // TODO(devlin, lukasza): https://crbug.com/786411: Remove this behavior, and
79   // make extensions follow the web standard for finding frames or use an
80   // explicit API.
81   static content::RenderFrame* FindFrame(
82       content::RenderFrame* relative_to_frame,
83       const std::string& name);
84 
85   // Returns true if the given |context| is for any frame in the extension's
86   // event page.
87   // TODO(devlin): This isn't really used properly, and should probably be
88   // deleted.
89   static bool IsContextForEventPage(const ScriptContext* context);
90 
view_type()91   ViewType view_type() const { return view_type_; }
tab_id()92   int tab_id() const { return tab_id_; }
browser_window_id()93   int browser_window_id() const { return browser_window_id_; }
did_create_current_document_element()94   bool did_create_current_document_element() const {
95     return did_create_current_document_element_;
96   }
97 
98   // Called when the document element has been inserted in this frame. This
99   // method may invoke untrusted JavaScript code that invalidate the frame and
100   // this ExtensionFrameHelper.
101   void RunScriptsAtDocumentStart();
102 
103   // Called after the DOMContentLoaded event has fired.
104   void RunScriptsAtDocumentEnd();
105 
106   // Called before the window.onload event is fired.
107   void RunScriptsAtDocumentIdle();
108 
109   // Schedule a callback, to be run at the next RunScriptsAtDocumentStart
110   // notification. Only call this when you are certain that there will be such a
111   // notification, e.g. from RenderFrameObserver::DidCreateDocumentElement.
112   // Otherwise the callback is never invoked, or invoked for a document that you
113   // were not expecting.
114   void ScheduleAtDocumentStart(const base::Closure& callback);
115 
116   // Schedule a callback, to be run at the next RunScriptsAtDocumentEnd call.
117   void ScheduleAtDocumentEnd(const base::Closure& callback);
118 
119   // Schedule a callback, to be run at the next RunScriptsAtDocumentIdle call.
120   void ScheduleAtDocumentIdle(const base::Closure& callback);
121 
122  private:
123   // RenderFrameObserver implementation.
124   void DidCreateDocumentElement() override;
125   void DidCreateNewDocument() override;
126   void ReadyToCommitNavigation(
127       blink::WebDocumentLoader* document_loader) override;
128   void DidCommitProvisionalLoad(ui::PageTransition transition) override;
129   void DidCreateScriptContext(v8::Local<v8::Context>,
130                               int32_t world_id) override;
131   void WillReleaseScriptContext(v8::Local<v8::Context>,
132                                 int32_t world_id) override;
133   bool OnMessageReceived(const IPC::Message& message) override;
134   void OnDestruct() override;
135   void DraggableRegionsChanged() override;
136 
137   // IPC handlers.
138   void OnExtensionValidateMessagePort(int worker_thread_id, const PortId& id);
139   void OnExtensionDispatchOnConnect(
140       int worker_thread_id,
141       const PortId& target_port_id,
142       const std::string& channel_name,
143       const ExtensionMsg_TabConnectionInfo& source,
144       const ExtensionMsg_ExternalConnectionInfo& info);
145   void OnExtensionDeliverMessage(int worker_thread_id,
146                                  const PortId& target_port_id,
147                                  const Message& message);
148   void OnExtensionDispatchOnDisconnect(int worker_thread_id,
149                                        const PortId& id,
150                                        const std::string& error_message);
151   void OnExtensionSetTabId(int tab_id);
152   void OnUpdateBrowserWindowId(int browser_window_id);
153   void OnNotifyRendererViewType(ViewType view_type);
154   void OnExtensionResponse(int request_id,
155                            bool success,
156                            const base::ListValue& response,
157                            const std::string& error);
158   void OnExtensionMessageInvoke(const std::string& extension_id,
159                                 const std::string& module_name,
160                                 const std::string& function_name,
161                                 const base::ListValue& args);
162   void OnSetFrameName(const std::string& name);
163   void OnAppWindowClosed(bool send_onclosed);
164   void OnSetSpatialNavigationEnabled(bool enabled);
165 
166   // Type of view associated with the RenderFrame.
167   ViewType view_type_;
168 
169   // The id of the tab the render frame is attached to.
170   int tab_id_;
171 
172   // The id of the browser window the render frame is attached to.
173   int browser_window_id_;
174 
175   Dispatcher* extension_dispatcher_;
176 
177   // Whether or not the current document element has been created.
178   bool did_create_current_document_element_;
179 
180   // Callbacks to be run at the next RunScriptsAtDocumentStart notification.
181   std::vector<base::Closure> document_element_created_callbacks_;
182 
183   // Callbacks to be run at the next RunScriptsAtDocumentEnd notification.
184   std::vector<base::Closure> document_load_finished_callbacks_;
185 
186   // Callbacks to be run at the next RunScriptsAtDocumentIdle notification.
187   std::vector<base::Closure> document_idle_callbacks_;
188 
189   bool delayed_main_world_script_initialization_ = false;
190 
191   // Whether or not a DocumentLoader has been created at least once for this
192   // RenderFrame.
193   // Note: Chrome Apps intentionally do not support new navigations. When a
194   // navigation happens, it is either the initial one or a reload.
195   bool has_started_first_navigation_ = false;
196 
197   base::WeakPtrFactory<ExtensionFrameHelper> weak_ptr_factory_{this};
198 
199   DISALLOW_COPY_AND_ASSIGN(ExtensionFrameHelper);
200 };
201 
202 }  // namespace extensions
203 
204 #endif  // EXTENSIONS_RENDERER_EXTENSION_FRAME_HELPER_H_
205