Index: extensions/browser/extension_navigation_throttle.cc |
diff --git a/extensions/browser/extension_navigation_throttle.cc b/extensions/browser/extension_navigation_throttle.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3c63dd76bf152bc75bef182b82b3a6b1fd2b09ca |
--- /dev/null |
+++ b/extensions/browser/extension_navigation_throttle.cc |
@@ -0,0 +1,93 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "extensions/browser/extension_navigation_throttle.h" |
+ |
+#include "content/public/browser/browser_thread.h" |
+#include "content/public/browser/navigation_handle.h" |
+#include "content/public/browser/render_frame_host.h" |
+#include "content/public/browser/web_contents.h" |
+#include "content/public/common/url_constants.h" |
+#include "extensions/browser/extension_registry.h" |
+#include "extensions/common/constants.h" |
+#include "extensions/common/extension.h" |
+#include "extensions/common/extension_set.h" |
+#include "extensions/common/manifest_handlers/web_accessible_resources_info.h" |
+ |
+namespace extensions { |
+ |
+ExtensionNavigationThrottle::ExtensionNavigationThrottle( |
+ content::NavigationHandle* navigation_handle) |
+ : content::NavigationThrottle(navigation_handle) {} |
+ |
+ExtensionNavigationThrottle::~ExtensionNavigationThrottle() {} |
+ |
+content::NavigationThrottle::ThrottleCheckResult |
+ExtensionNavigationThrottle::WillStartRequest() { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ |
+ // This method for now enforces only web_accessible_resources for navigations. |
+ // Top-level navigations should always be allowed. |
+ DCHECK(!navigation_handle()->IsInMainFrame()); |
+ |
+ // If the navigation is not to a chrome-extension:// URL, no need to perform |
+ // any more checks. |
+ if (!navigation_handle()->GetURL().SchemeIs(extensions::kExtensionScheme)) |
+ return content::NavigationThrottle::PROCEED; |
+ |
+ // The subframe which is navigated needs to have all of its ancestors be |
+ // at the same origin, otherwise the resource needs to be explicitly listed |
+ // in web_accessible_resources. |
+ // Since the RenderFrameHost is not known until navigation has committed, |
+ // we can't get it from NavigationHandle. However, this code only cares about |
+ // the ancestor chain, so find the current RenderFrameHost and use it to |
+ // traverse up to the main frame. |
+ content::RenderFrameHost* navigating_frame = nullptr; |
+ for (auto frame : navigation_handle()->GetWebContents()->GetAllFrames()) { |
+ if (frame->GetFrameTreeNodeId() == |
+ navigation_handle()->GetFrameTreeNodeId()) { |
+ navigating_frame = frame; |
+ break; |
+ } |
+ } |
+ DCHECK(navigating_frame); |
+ |
+ // Traverse the chain of parent frames, checking if they are the same origin |
+ // as the URL of this navigation. |
+ content::RenderFrameHost* ancestor = navigating_frame->GetParent(); |
+ bool external_ancestor = false; |
+ while (ancestor) { |
+ if (ancestor->GetLastCommittedURL().GetOrigin() != |
+ navigation_handle()->GetURL().GetOrigin()) { |
+ // Ignore DevTools, as it is allowed to embed extension pages. |
+ if (!ancestor->GetLastCommittedURL().SchemeIs( |
+ content::kChromeDevToolsScheme)) { |
+ external_ancestor = true; |
+ break; |
+ } |
+ } |
+ ancestor = ancestor->GetParent(); |
+ } |
+ |
+ if (!external_ancestor) |
+ return content::NavigationThrottle::PROCEED; |
+ |
+ // Since there was at least one origin different than the navigation URL, |
+ // explicitly check for the resource in web_accessible_resources. |
+ std::string resource_path = navigation_handle()->GetURL().path(); |
+ ExtensionRegistry* registry = ExtensionRegistry::Get( |
+ navigation_handle()->GetWebContents()->GetBrowserContext()); |
+ const extensions::Extension* extension = |
+ registry->enabled_extensions().GetByID( |
+ navigation_handle()->GetURL().host()); |
+ |
+ if (WebAccessibleResourcesInfo::IsResourceWebAccessible(extension, |
+ resource_path)) { |
+ return content::NavigationThrottle::PROCEED; |
+ } |
+ |
+ return content::NavigationThrottle::BLOCK_REQUEST; |
+} |
+ |
+} // namespace extensions |