Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(146)

Side by Side Diff: chrome/renderer/extensions/chrome_extensions_renderer_client.cc

Issue 1394283003: Move more extensions code into ChromeExtensionsRendererClient. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: IWYU Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/renderer/extensions/chrome_extensions_renderer_client.h" 5 #include "chrome/renderer/extensions/chrome_extensions_renderer_client.h"
6 6
7 #include "base/command_line.h"
7 #include "base/lazy_instance.h" 8 #include "base/lazy_instance.h"
8 #include "chrome/common/chrome_isolated_world_ids.h" 9 #include "chrome/common/chrome_isolated_world_ids.h"
10 #include "chrome/common/chrome_switches.h"
11 #include "chrome/common/extensions/extension_constants.h"
12 #include "chrome/common/extensions/extension_metrics.h"
13 #include "chrome/common/extensions/extension_process_policy.h"
14 #include "chrome/common/url_constants.h"
9 #include "chrome/renderer/chrome_render_process_observer.h" 15 #include "chrome/renderer/chrome_render_process_observer.h"
16 #include "chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.h"
17 #include "chrome/renderer/extensions/renderer_permissions_policy_delegate.h"
18 #include "chrome/renderer/extensions/resource_request_policy.h"
19 #include "chrome/renderer/media/cast_ipc_dispatcher.h"
20 #include "content/public/common/content_constants.h"
21 #include "content/public/common/content_switches.h"
22 #include "content/public/renderer/render_thread.h"
23 #include "extensions/common/constants.h"
24 #include "extensions/common/extension.h"
25 #include "extensions/common/extension_set.h"
26 #include "extensions/common/switches.h"
27 #include "extensions/renderer/dispatcher.h"
28 #include "extensions/renderer/extension_frame_helper.h"
29 #include "extensions/renderer/extension_helper.h"
30 #include "extensions/renderer/extensions_render_frame_observer.h"
31 #include "extensions/renderer/guest_view/extensions_guest_view_container.h"
32 #include "extensions/renderer/guest_view/extensions_guest_view_container_dispatc her.h"
33 #include "extensions/renderer/guest_view/mime_handler_view/mime_handler_view_con tainer.h"
34 #include "extensions/renderer/script_context.h"
35 #include "third_party/WebKit/public/platform/WebURL.h"
36 #include "third_party/WebKit/public/web/WebDocument.h"
37 #include "third_party/WebKit/public/web/WebLocalFrame.h"
38 #include "third_party/WebKit/public/web/WebPluginParams.h"
39
40 using extensions::Extension;
41
42 namespace {
43
44 bool IsStandaloneExtensionProcess() {
45 return base::CommandLine::ForCurrentProcess()->HasSwitch(
46 extensions::switches::kExtensionProcess);
47 }
48
49 void IsGuestViewApiAvailableToScriptContext(
50 bool* api_is_available,
51 extensions::ScriptContext* context) {
52 if (context->GetAvailability("guestViewInternal").is_available()) {
53 *api_is_available = true;
54 }
55 }
56
57 // Returns true if the frame is navigating to an URL either into or out of an
58 // extension app's extent.
59 bool CrossesExtensionExtents(blink::WebLocalFrame* frame,
60 const GURL& new_url,
61 bool is_extension_url,
62 bool is_initial_navigation) {
63 DCHECK(!frame->parent());
64 GURL old_url(frame->document().url());
65
66 extensions::RendererExtensionRegistry* extension_registry =
67 extensions::RendererExtensionRegistry::Get();
68
69 // If old_url is still empty and this is an initial navigation, then this is
70 // a window.open operation. We should look at the opener URL. Note that the
71 // opener is a local frame in this case.
72 if (is_initial_navigation && old_url.is_empty() && frame->opener()) {
73 blink::WebLocalFrame* opener_frame = frame->opener()->toWebLocalFrame();
74
75 // If we're about to open a normal web page from a same-origin opener stuck
76 // in an extension process, we want to keep it in process to allow the
77 // opener to script it.
78 blink::WebDocument opener_document = opener_frame->document();
79 blink::WebSecurityOrigin opener_origin = opener_document.securityOrigin();
80 bool opener_is_extension_url = !opener_origin.isUnique() &&
81 extension_registry->GetExtensionOrAppByURL(
82 opener_document.url()) != nullptr;
83 if (!is_extension_url && !opener_is_extension_url &&
84 IsStandaloneExtensionProcess() &&
85 opener_origin.canRequest(blink::WebURL(new_url)))
86 return false;
87
88 // In all other cases, we want to compare against the URL that determines
89 // the type of process. In default Chrome, that's the URL of the opener's
90 // top frame and not the opener frame itself. In --site-per-process, we
91 // can use the opener frame itself.
92 // TODO(nick): Either wire this up to SiteIsolationPolicy, or to state on
93 // |opener_frame|/its ancestors.
94 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
95 switches::kSitePerProcess) ||
96 base::CommandLine::ForCurrentProcess()->HasSwitch(
97 switches::kIsolateExtensions))
98 old_url = opener_frame->document().url();
99 else
100 old_url = opener_frame->top()->document().url();
101 }
102
103 // Only consider keeping non-app URLs in an app process if this window
104 // has an opener (in which case it might be an OAuth popup that tries to
105 // script an iframe within the app).
106 bool should_consider_workaround = !!frame->opener();
107
108 return extensions::CrossesExtensionProcessBoundary(
109 *extension_registry->GetMainThreadExtensionSet(), old_url, new_url,
110 should_consider_workaround);
111 }
112
113 } // namespace
10 114
11 ChromeExtensionsRendererClient::ChromeExtensionsRendererClient() {} 115 ChromeExtensionsRendererClient::ChromeExtensionsRendererClient() {}
12 116
13 ChromeExtensionsRendererClient::~ChromeExtensionsRendererClient() {} 117 ChromeExtensionsRendererClient::~ChromeExtensionsRendererClient() {}
14 118
15 // static 119 // static
16 ChromeExtensionsRendererClient* ChromeExtensionsRendererClient::GetInstance() { 120 ChromeExtensionsRendererClient* ChromeExtensionsRendererClient::GetInstance() {
17 static base::LazyInstance<ChromeExtensionsRendererClient> client = 121 static base::LazyInstance<ChromeExtensionsRendererClient> client =
18 LAZY_INSTANCE_INITIALIZER; 122 LAZY_INSTANCE_INITIALIZER;
19 return client.Pointer(); 123 return client.Pointer();
20 } 124 }
21 125
22 bool ChromeExtensionsRendererClient::IsIncognitoProcess() const { 126 bool ChromeExtensionsRendererClient::IsIncognitoProcess() const {
23 return ChromeRenderProcessObserver::is_incognito_process(); 127 return ChromeRenderProcessObserver::is_incognito_process();
24 } 128 }
25 129
26 int ChromeExtensionsRendererClient::GetLowestIsolatedWorldId() const { 130 int ChromeExtensionsRendererClient::GetLowestIsolatedWorldId() const {
27 return chrome::ISOLATED_WORLD_ID_EXTENSIONS; 131 return chrome::ISOLATED_WORLD_ID_EXTENSIONS;
28 } 132 }
133
134 void ChromeExtensionsRendererClient::RenderThreadStarted() {
135 content::RenderThread* thread = content::RenderThread::Get();
136 extension_dispatcher_delegate_.reset(
137 new ChromeExtensionsDispatcherDelegate());
138 // ChromeRenderViewTest::SetUp() creates its own ExtensionDispatcher and
139 // injects it using SetExtensionDispatcher(). Don't overwrite it.
140 if (!extension_dispatcher_) {
141 extension_dispatcher_.reset(
142 new extensions::Dispatcher(extension_dispatcher_delegate_.get()));
143 }
144 permissions_policy_delegate_.reset(
145 new extensions::RendererPermissionsPolicyDelegate(
146 extension_dispatcher_.get()));
147 resource_request_policy_.reset(
148 new extensions::ResourceRequestPolicy(extension_dispatcher_.get()));
149 guest_view_container_dispatcher_.reset(
150 new extensions::ExtensionsGuestViewContainerDispatcher());
151
152 thread->AddObserver(extension_dispatcher_.get());
153 thread->AddObserver(guest_view_container_dispatcher_.get());
154 thread->AddFilter(new CastIPCDispatcher(thread->GetIOMessageLoopProxy()));
155 }
156
157 void ChromeExtensionsRendererClient::RenderFrameCreated(
158 content::RenderFrame* render_frame) {
159 new extensions::ExtensionsRenderFrameObserver(render_frame);
160 new extensions::ExtensionFrameHelper(render_frame,
161 extension_dispatcher_.get());
162 extension_dispatcher_->OnRenderFrameCreated(render_frame);
163 }
164
165 void ChromeExtensionsRendererClient::RenderViewCreated(
166 content::RenderView* render_view) {
167 new extensions::ExtensionHelper(render_view, extension_dispatcher_.get());
168 }
169
170 bool ChromeExtensionsRendererClient::OverrideCreatePlugin(
171 content::RenderFrame* render_frame,
172 const blink::WebPluginParams& params) {
173 if (params.mimeType.utf8() != content::kBrowserPluginMimeType)
174 return true;
175
176 bool guest_view_api_available = false;
177 extension_dispatcher_->script_context_set().ForEach(
178 render_frame, base::Bind(&IsGuestViewApiAvailableToScriptContext,
179 &guest_view_api_available));
180 return !guest_view_api_available;
181 }
182
183 bool ChromeExtensionsRendererClient::AllowPopup() {
184 extensions::ScriptContext* current_context =
185 extension_dispatcher_->script_context_set().GetCurrent();
186 if (!current_context || !current_context->extension())
187 return false;
188
189 // See http://crbug.com/117446 for the subtlety of this check.
190 switch (current_context->context_type()) {
191 case extensions::Feature::UNSPECIFIED_CONTEXT:
192 case extensions::Feature::WEB_PAGE_CONTEXT:
193 case extensions::Feature::UNBLESSED_EXTENSION_CONTEXT:
194 case extensions::Feature::WEBUI_CONTEXT:
195 case extensions::Feature::SERVICE_WORKER_CONTEXT:
196 return false;
197 case extensions::Feature::BLESSED_EXTENSION_CONTEXT:
198 case extensions::Feature::CONTENT_SCRIPT_CONTEXT:
199 return true;
200 case extensions::Feature::BLESSED_WEB_PAGE_CONTEXT:
201 return !current_context->web_frame()->parent();
202 default:
203 NOTREACHED();
204 return false;
205 }
206 }
207
208 bool ChromeExtensionsRendererClient::WillSendRequest(
209 blink::WebFrame* frame,
210 ui::PageTransition transition_type,
211 const GURL& url,
212 GURL* new_url) {
213 if (url.SchemeIs(extensions::kExtensionScheme) &&
214 !resource_request_policy_->CanRequestResource(url, frame,
215 transition_type)) {
216 *new_url = GURL(chrome::kExtensionInvalidRequestURL);
217 return true;
218 }
219
220 if (url.SchemeIs(extensions::kExtensionResourceScheme) &&
221 !resource_request_policy_->CanRequestExtensionResourceScheme(url,
222 frame)) {
223 *new_url = GURL(chrome::kExtensionResourceInvalidRequestURL);
224 return true;
225 }
226
227 return false;
228 }
229
230 void ChromeExtensionsRendererClient::SetExtensionDispatcherForTest(
231 scoped_ptr<extensions::Dispatcher> extension_dispatcher) {
232 extension_dispatcher_ = extension_dispatcher.Pass();
233 permissions_policy_delegate_.reset(
234 new extensions::RendererPermissionsPolicyDelegate(
235 extension_dispatcher_.get()));
236 content::RenderThread::Get()->RegisterExtension(
237 extensions::SafeBuiltins::CreateV8Extension());
238 }
239
240 extensions::Dispatcher*
241 ChromeExtensionsRendererClient::GetExtensionDispatcherForTest() {
242 return extension_dispatcher();
243 }
244
245 // static
246 bool ChromeExtensionsRendererClient::ShouldFork(blink::WebLocalFrame* frame,
247 const GURL& url,
248 bool is_initial_navigation,
249 bool is_server_redirect,
250 bool* send_referrer) {
251 const extensions::RendererExtensionRegistry* extension_registry =
252 extensions::RendererExtensionRegistry::Get();
253
254 // Determine if the new URL is an extension (excluding bookmark apps).
255 const Extension* new_url_extension = extensions::GetNonBookmarkAppExtension(
256 *extension_registry->GetMainThreadExtensionSet(), url);
257 bool is_extension_url = !!new_url_extension;
258
259 // If the navigation would cross an app extent boundary, we also need
260 // to defer to the browser to ensure process isolation. This is not necessary
261 // for server redirects, which will be transferred to a new process by the
262 // browser process when they are ready to commit. It is necessary for client
263 // redirects, which won't be transferred in the same way.
264 if (!is_server_redirect &&
265 CrossesExtensionExtents(frame, url, is_extension_url,
266 is_initial_navigation)) {
267 // Include the referrer in this case since we're going from a hosted web
268 // page. (the packaged case is handled previously by the extension
269 // navigation test)
270 *send_referrer = true;
271
272 const Extension* extension =
273 extension_registry->GetExtensionOrAppByURL(url);
274 if (extension && extension->is_app()) {
275 extensions::RecordAppLaunchType(
276 extension_misc::APP_LAUNCH_CONTENT_NAVIGATION, extension->GetType());
277 }
278 return true;
279 }
280
281 // If this is a reload, check whether it has the wrong process type. We
282 // should send it to the browser if it's an extension URL (e.g., hosted app)
283 // in a normal process, or if it's a process for an extension that has been
284 // uninstalled. Without --site-per-process mode, we never fork processes for
285 // subframes, so this check only makes sense for top-level frames.
286 // TODO(alexmos,nasko): Figure out how this check should work when reloading
287 // subframes in --site-per-process mode.
288 if (!frame->parent() && frame->document().url() == url) {
289 if (is_extension_url != IsStandaloneExtensionProcess())
290 return true;
291 }
292 return false;
293 }
294
295 // static
296 content::BrowserPluginDelegate*
297 ChromeExtensionsRendererClient::CreateBrowserPluginDelegate(
298 content::RenderFrame* render_frame,
299 const std::string& mime_type,
300 const GURL& original_url) {
301 if (mime_type == content::kBrowserPluginMimeType)
302 return new extensions::ExtensionsGuestViewContainer(render_frame);
303 return new extensions::MimeHandlerViewContainer(render_frame, mime_type,
304 original_url);
305 }
OLDNEW
« no previous file with comments | « chrome/renderer/extensions/chrome_extensions_renderer_client.h ('k') | chrome/renderer/page_load_histograms.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698