diff options
26 files changed, 213 insertions, 113 deletions
diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc index dbb47cd..8ff88e8 100644 --- a/chrome/browser/extensions/extension_apitest.cc +++ b/chrome/browser/extensions/extension_apitest.cc @@ -152,7 +152,6 @@ bool ExtensionApiTest::RunExtensionTestImpl(const char* extension_name, url = extension->GetResourceURL(page_url); } - LOG(ERROR) << "Loading page url: " << url.spec(); ui_test_utils::NavigateToURL(browser(), url); } diff --git a/chrome/browser/extensions/extension_browsertests_misc.cc b/chrome/browser/extensions/extension_browsertests_misc.cc index 8ceda4d..63d0402 100644 --- a/chrome/browser/extensions/extension_browsertests_misc.cc +++ b/chrome/browser/extensions/extension_browsertests_misc.cc @@ -79,72 +79,6 @@ static ExtensionHost* FindHostWithPath(ExtensionProcessManager* manager, return host; } -// Tests that extension resources can be loaded from origins which the -// extension specifies in permissions but not from others. -IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, OriginPrivileges) { - host_resolver()->AddRule("*", "127.0.0.1"); - ASSERT_TRUE(test_server()->Start()); - ASSERT_TRUE(LoadExtension(test_data_dir_ - .AppendASCII("origin_privileges").AppendASCII("extension"))); - - GURL origin_privileges_index( - test_server()->GetURL("files/extensions/origin_privileges/index.html")); - - std::string host_a("a.com"); - GURL::Replacements make_host_a_com; - make_host_a_com.SetHostStr(host_a); - - std::string host_b("b.com"); - GURL::Replacements make_host_b_com; - make_host_b_com.SetHostStr(host_b); - - // A web host that has permission. - ui_test_utils::NavigateToURL( - browser(), origin_privileges_index.ReplaceComponents(make_host_a_com)); - std::string result; - ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( - browser()->GetSelectedTabContents()->render_view_host(), L"", - L"window.domAutomationController.send(document.title)", - &result)); - EXPECT_EQ(result, "Loaded"); - - // A web host that does not have permission. - ui_test_utils::NavigateToURL( - browser(), origin_privileges_index.ReplaceComponents(make_host_b_com)); - ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( - browser()->GetSelectedTabContents()->render_view_host(), L"", - L"window.domAutomationController.send(document.title)", - &result)); - EXPECT_EQ(result, "Image failed to load"); - - // A data URL. Data URLs should always be able to load chrome-extension:// - // resources. - std::string file_source; - ASSERT_TRUE(file_util::ReadFileToString( - test_data_dir_.AppendASCII("origin_privileges") - .AppendASCII("index.html"), &file_source)); - ui_test_utils::NavigateToURL(browser(), - GURL(std::string("data:text/html;charset=utf-8,") + file_source)); - ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( - browser()->GetSelectedTabContents()->render_view_host(), L"", - L"window.domAutomationController.send(document.title)", - &result)); - EXPECT_EQ(result, "Loaded"); - - // A different extension. Extensions should always be able to load each - // other's resources. - ASSERT_TRUE(LoadExtension(test_data_dir_ - .AppendASCII("origin_privileges").AppendASCII("extension2"))); - ui_test_utils::NavigateToURL( - browser(), - GURL("chrome-extension://pbkkcbgdkliohhfaeefcijaghglkahja/index.html")); - ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( - browser()->GetSelectedTabContents()->render_view_host(), L"", - L"window.domAutomationController.send(document.title)", - &result)); - EXPECT_EQ(result, "Loaded"); -} - // Tests that we can load extension pages into the tab area and they can call // extension APIs. IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TabContents) { diff --git a/chrome/browser/extensions/extension_protocols.cc b/chrome/browser/extensions/extension_protocols.cc index 1ee6952..91222c7 100644 --- a/chrome/browser/extensions/extension_protocols.cc +++ b/chrome/browser/extensions/extension_protocols.cc @@ -67,6 +67,8 @@ class URLRequestResourceBundleJob : public net::URLRequestSimpleJob { }; // Returns true if an chrome-extension:// resource should be allowed to load. +// TODO(aa): This should be moved into ExtensionResourceRequestPolicy, but we +// first need to find a way to get CanLoadInIncognito state into the renderers. bool AllowExtensionResourceLoad(net::URLRequest* request, ChromeURLRequestContext* context, const std::string& scheme) { @@ -81,27 +83,6 @@ bool AllowExtensionResourceLoad(net::URLRequest* request, return true; } - GURL origin_url(info->frame_origin()); - - // chrome:// URLs are always allowed to load chrome-extension:// resources. - // The app launcher in the NTP uses this feature, as does dev tools. - if (origin_url.SchemeIs(chrome::kChromeDevToolsScheme) || - origin_url.SchemeIs(chrome::kChromeUIScheme)) - return true; - - // Disallow loading of packaged resources for hosted apps. We don't allow - // hybrid hosted/packaged apps. The one exception is access to icons, since - // some extensions want to be able to do things like create their own - // launchers. - if (context->extension_info_map()-> - ExtensionHasWebExtent(request->url().host())) { - if (!context->extension_info_map()->URLIsForExtensionIcon(request->url())) { - LOG(ERROR) << "Denying load of " << request->url().spec() << " from " - << "hosted app."; - return false; - } - } - // Don't allow toplevel navigations to extension resources in incognito mode. // This is because an extension must run in a single process, and an // incognito tab prevents that. @@ -114,30 +95,7 @@ bool AllowExtensionResourceLoad(net::URLRequest* request, return false; } - // Otherwise, pages are allowed to load resources from extensions if the - // extension has host permissions to (and therefore could be running script - // in, which might need access to the extension resources). - // - // Exceptions are: - // - empty origin (needed for some edge cases when we have empty origins) - // - chrome-extension:// (for legacy reasons -- some extensions interop) - // - data: (basic HTML notifications use data URLs internally) - if (origin_url.is_empty() || - origin_url.SchemeIs(chrome::kExtensionScheme) | - origin_url.SchemeIs(chrome::kDataScheme)) { - return true; - } else { - ExtensionExtent host_permissions = context->extension_info_map()-> - GetEffectiveHostPermissionsForExtension(request->url().host()); - if (host_permissions.ContainsURL(origin_url)) { - return true; - } else { - LOG(ERROR) << "Denying load of " << request->url().spec() << " from " - << origin_url.spec() << " because the extension does not have " - << "access to the requesting page."; - return false; - } - } + return true; } } // namespace @@ -151,8 +109,10 @@ static net::URLRequestJob* CreateExtensionURLRequestJob( static_cast<ChromeURLRequestContext*>(request->context()); // TODO(mpcomplete): better error code. - if (!AllowExtensionResourceLoad(request, context, scheme)) + if (!AllowExtensionResourceLoad(request, context, scheme)) { + LOG(ERROR) << "disallowed in extension protocols"; return new net::URLRequestErrorJob(request, net::ERR_ADDRESS_UNREACHABLE); + } // chrome-extension://extension-id/resource/path.js const std::string& extension_id = request->url().host(); diff --git a/chrome/browser/extensions/extension_resource_request_policy_apitest.cc b/chrome/browser/extensions/extension_resource_request_policy_apitest.cc new file mode 100644 index 0000000..b5d45c1 --- /dev/null +++ b/chrome/browser/extensions/extension_resource_request_policy_apitest.cc @@ -0,0 +1,95 @@ +// Copyright (c) 2011 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 "base/logging.h" +#include "chrome/browser/extensions/extension_apitest.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/test/ui_test_utils.h" +#include "googleurl/src/gurl.h" +#include "net/base/mock_host_resolver.h" + +class ExtensionResourceRequestPolicyTest : public ExtensionApiTest { +}; + +// Note, this mostly tests the logic of chrome/renderer/extensions/ +// extension_resource_request_policy.*, but we have it as a browser test so that +// can make sure it works end-to-end. +IN_PROC_BROWSER_TEST_F(ExtensionResourceRequestPolicyTest, OriginPrivileges) { + host_resolver()->AddRule("*", "127.0.0.1"); + ASSERT_TRUE(test_server()->Start()); + ASSERT_TRUE(LoadExtension(test_data_dir_ + .AppendASCII("extension_resource_request_policy") + .AppendASCII("extension"))); + + GURL web_resource( + test_server()->GetURL( + "files/extensions/api_test/extension_resource_request_policy/" + "index.html")); + + std::string host_a("a.com"); + GURL::Replacements make_host_a_com; + make_host_a_com.SetHostStr(host_a); + + std::string host_b("b.com"); + GURL::Replacements make_host_b_com; + make_host_b_com.SetHostStr(host_b); + + // A web host that has permission. + ui_test_utils::NavigateToURL( + browser(), web_resource.ReplaceComponents(make_host_a_com)); + std::string result; + ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( + browser()->GetSelectedTabContents()->render_view_host(), L"", + L"window.domAutomationController.send(document.title)", + &result)); + EXPECT_EQ(result, "Loaded"); + + // A web host that does not have permission. + ui_test_utils::NavigateToURL( + browser(), web_resource.ReplaceComponents(make_host_b_com)); + ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( + browser()->GetSelectedTabContents()->render_view_host(), L"", + L"window.domAutomationController.send(document.title)", + &result)); + EXPECT_EQ(result, "Image failed to load"); + + // A data URL. Data URLs should always be able to load chrome-extension:// + // resources. + std::string file_source; + ASSERT_TRUE(file_util::ReadFileToString( + test_data_dir_.AppendASCII("extension_resource_request_policy") + .AppendASCII("index.html"), &file_source)); + ui_test_utils::NavigateToURL(browser(), + GURL(std::string("data:text/html;charset=utf-8,") + file_source)); + ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( + browser()->GetSelectedTabContents()->render_view_host(), L"", + L"window.domAutomationController.send(document.title)", + &result)); + EXPECT_EQ(result, "Loaded"); + + // A different extension. Extensions should always be able to load each + // other's resources. + ASSERT_TRUE(LoadExtension(test_data_dir_ + .AppendASCII("extension_resource_request_policy") + .AppendASCII("extension2"))); + ui_test_utils::NavigateToURL( + browser(), + GURL("chrome-extension://pbkkcbgdkliohhfaeefcijaghglkahja/index.html")); + ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( + browser()->GetSelectedTabContents()->render_view_host(), L"", + L"window.domAutomationController.send(document.title)", + &result)); + EXPECT_EQ(result, "Loaded"); +} + +IN_PROC_BROWSER_TEST_F(ExtensionResourceRequestPolicyTest, Audio) { + EXPECT_TRUE(RunExtensionSubtest("extension_resource_request_policy/media", + "audio.html")); +} + +IN_PROC_BROWSER_TEST_F(ExtensionResourceRequestPolicyTest, Video) { + EXPECT_TRUE(RunExtensionSubtest("extension_resource_request_policy/media", + "video.html")); +} diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi index 055645b..54f315a 100644 --- a/chrome/chrome_renderer.gypi +++ b/chrome/chrome_renderer.gypi @@ -60,6 +60,8 @@ 'renderer/extensions/event_bindings.h', 'renderer/extensions/extension_process_bindings.cc', 'renderer/extensions/extension_process_bindings.h', + 'renderer/extensions/extension_resource_request_policy.cc', + 'renderer/extensions/extension_resource_request_policy.h', 'renderer/extensions/js_only_v8_extensions.cc', 'renderer/extensions/js_only_v8_extensions.h', 'renderer/extensions/renderer_extension_bindings.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index c46805b..f52e3ed 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -2136,6 +2136,7 @@ 'browser/extensions/extension_popup_apitest.cc', 'browser/extensions/extension_proxy_apitest.cc', 'browser/extensions/extension_processes_apitest.cc', + 'browser/extensions/extension_resource_request_policy_apitest.cc', 'browser/extensions/extension_rlz_apitest.cc', 'browser/extensions/extension_sidebar_apitest.cc', 'browser/extensions/extension_startup_browsertest.cc', diff --git a/chrome/renderer/extensions/extension_resource_request_policy.cc b/chrome/renderer/extensions/extension_resource_request_policy.cc new file mode 100644 index 0000000..f4fcb30 --- /dev/null +++ b/chrome/renderer/extensions/extension_resource_request_policy.cc @@ -0,0 +1,63 @@ +// Copyright (c) 2011 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 "chrome/renderer/extensions/extension_resource_request_policy.h" + +#include "base/logging.h" +#include "chrome/common/url_constants.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/extensions/extension_set.h" +#include "googleurl/src/gurl.h" + +// static +bool ExtensionResourceRequestPolicy::CanRequestResource( + const GURL& resource_url, + const GURL& frame_url, + const ExtensionSet* loaded_extensions) { + CHECK(resource_url.SchemeIs(chrome::kExtensionScheme)); + + // chrome:// URLs are always allowed to load chrome-extension:// resources. + // The app launcher in the NTP uses this feature, as does dev tools. + if (frame_url.SchemeIs(chrome::kChromeDevToolsScheme) || + frame_url.SchemeIs(chrome::kChromeUIScheme)) + return true; + + // Disallow loading of packaged resources for hosted apps. We don't allow + // hybrid hosted/packaged apps. The one exception is access to icons, since + // some extensions want to be able to do things like create their own + // launchers. + const Extension* extension = loaded_extensions->GetByURL(resource_url); + if (extension && extension->is_hosted_app() && + !extension->icons().ContainsPath(resource_url.path())) { + LOG(ERROR) << "Denying load of " << resource_url.spec() << " from " + << "hosted app."; + return false; + } + + // Otherwise, pages are allowed to load resources from extensions if the + // extension has host permissions to (and therefore could be running script + // in, which might need access to the extension resources). + // + // Exceptions are: + // - empty origin (needed for some edge cases when we have empty origins) + // - chrome-extension:// (for legacy reasons -- some extensions interop) + // - data: (basic HTML notifications use data URLs internally) + if (frame_url.is_empty() || + frame_url.SchemeIs(chrome::kExtensionScheme) | + frame_url.SchemeIs(chrome::kDataScheme)) { + return true; + } else { + if (extension->GetEffectiveHostPermissions().ContainsURL(frame_url)) { + return true; + } else { + LOG(ERROR) << "Denying load of " << resource_url.spec() << " from " + << frame_url.spec() << " because the extension does not have " + << "access to the requesting page."; + return false; + } + } +} + +ExtensionResourceRequestPolicy::ExtensionResourceRequestPolicy() { +} diff --git a/chrome/renderer/extensions/extension_resource_request_policy.h b/chrome/renderer/extensions/extension_resource_request_policy.h new file mode 100644 index 0000000..adfc816 --- /dev/null +++ b/chrome/renderer/extensions/extension_resource_request_policy.h @@ -0,0 +1,24 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_RENDERER_EXTENSIONS_EXTENSION_RESOURCE_REQUEST_POLICY_H_ +#define CHROME_RENDERER_EXTENSIONS_EXTENSION_RESOURCE_REQUEST_POLICY_H_ +#pragma once + +class ExtensionSet; +class GURL; + +// Encapsulates the policy for when chrome-extension:// URLs can be requested. +class ExtensionResourceRequestPolicy { + public: + // Returns true if the |resource_url| can be requested from |frame_url|. + static bool CanRequestResource(const GURL& resource_url, + const GURL& frame_url, + const ExtensionSet* loaded_extensions); + + private: + ExtensionResourceRequestPolicy(); +}; + +#endif // CHROME_RENDERER_EXTENSIONS_EXTENSION_RESOURCE_REQUEST_POLICY_H_ diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 9ea2b85..8372ad3 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -61,6 +61,7 @@ #include "chrome/renderer/extensions/bindings_utils.h" #include "chrome/renderer/extensions/event_bindings.h" #include "chrome/renderer/extensions/extension_process_bindings.h" +#include "chrome/renderer/extensions/extension_resource_request_policy.h" #include "chrome/renderer/extensions/renderer_extension_bindings.h" #include "chrome/renderer/external_host_bindings.h" #include "chrome/renderer/external_popup_menu.h" @@ -3616,6 +3617,19 @@ void RenderView::willSendRequest( WebDataSource* top_data_source = top_frame->dataSource(); WebDataSource* data_source = provisional_data_source ? provisional_data_source : top_data_source; + + // If the request is for an extension resource, check whether it should be + // allowed. If not allowed, we reset the URL to something invalid to prevent + // the request and cause an error. + GURL request_url(request.url()); + if (request_url.SchemeIs(chrome::kExtensionScheme) && + !ExtensionResourceRequestPolicy::CanRequestResource( + request_url, + GURL(frame->url()), + render_thread_->GetExtensions())) { + request.setURL(WebURL(GURL("chrome-extension://invalid/"))); + } + if (data_source) { NavigationState* state = NavigationState::FromDataSource(data_source); if (state && state->is_cache_policy_override_set()) diff --git a/chrome/test/data/extensions/origin_privileges/extension/manifest.json b/chrome/test/data/extensions/api_test/extension_resource_request_policy/extension/manifest.json index 3a0c184..3a0c184 100644 --- a/chrome/test/data/extensions/origin_privileges/extension/manifest.json +++ b/chrome/test/data/extensions/api_test/extension_resource_request_policy/extension/manifest.json diff --git a/chrome/test/data/extensions/origin_privileges/extension/test.png b/chrome/test/data/extensions/api_test/extension_resource_request_policy/extension/test.png Binary files differindex 4421311..4421311 100644 --- a/chrome/test/data/extensions/origin_privileges/extension/test.png +++ b/chrome/test/data/extensions/api_test/extension_resource_request_policy/extension/test.png diff --git a/chrome/test/data/extensions/origin_privileges/extension2/can_load_icons_from_hosted_apps.html b/chrome/test/data/extensions/api_test/extension_resource_request_policy/extension2/can_load_icons_from_hosted_apps.html index 46c6a70..46c6a70 100644 --- a/chrome/test/data/extensions/origin_privileges/extension2/can_load_icons_from_hosted_apps.html +++ b/chrome/test/data/extensions/api_test/extension_resource_request_policy/extension2/can_load_icons_from_hosted_apps.html diff --git a/chrome/test/data/extensions/origin_privileges/extension2/cant_load_packaged_resources_from_hosted_apps.html b/chrome/test/data/extensions/api_test/extension_resource_request_policy/extension2/cant_load_packaged_resources_from_hosted_apps.html index 9ba959d..9ba959d 100644 --- a/chrome/test/data/extensions/origin_privileges/extension2/cant_load_packaged_resources_from_hosted_apps.html +++ b/chrome/test/data/extensions/api_test/extension_resource_request_policy/extension2/cant_load_packaged_resources_from_hosted_apps.html diff --git a/chrome/test/data/extensions/origin_privileges/extension2/extensions_can_load_other_extension_resources.html b/chrome/test/data/extensions/api_test/extension_resource_request_policy/extension2/extensions_can_load_other_extension_resources.html index 4183769..4183769 100644 --- a/chrome/test/data/extensions/origin_privileges/extension2/extensions_can_load_other_extension_resources.html +++ b/chrome/test/data/extensions/api_test/extension_resource_request_policy/extension2/extensions_can_load_other_extension_resources.html diff --git a/chrome/test/data/extensions/origin_privileges/extension2/index.html b/chrome/test/data/extensions/api_test/extension_resource_request_policy/extension2/index.html index 4183769..4183769 100644 --- a/chrome/test/data/extensions/origin_privileges/extension2/index.html +++ b/chrome/test/data/extensions/api_test/extension_resource_request_policy/extension2/index.html diff --git a/chrome/test/data/extensions/origin_privileges/extension2/manifest.json b/chrome/test/data/extensions/api_test/extension_resource_request_policy/extension2/manifest.json index 970fcf0..970fcf0 100644 --- a/chrome/test/data/extensions/origin_privileges/extension2/manifest.json +++ b/chrome/test/data/extensions/api_test/extension_resource_request_policy/extension2/manifest.json diff --git a/chrome/test/data/extensions/origin_privileges/extension2/test.png b/chrome/test/data/extensions/api_test/extension_resource_request_policy/extension2/test.png Binary files differindex 4421311..4421311 100644 --- a/chrome/test/data/extensions/origin_privileges/extension2/test.png +++ b/chrome/test/data/extensions/api_test/extension_resource_request_policy/extension2/test.png diff --git a/chrome/test/data/extensions/origin_privileges/hosted_app/manifest.json b/chrome/test/data/extensions/api_test/extension_resource_request_policy/hosted_app/manifest.json index 4de0837..4de0837 100644 --- a/chrome/test/data/extensions/origin_privileges/hosted_app/manifest.json +++ b/chrome/test/data/extensions/api_test/extension_resource_request_policy/hosted_app/manifest.json diff --git a/chrome/test/data/extensions/origin_privileges/hosted_app/test.png b/chrome/test/data/extensions/api_test/extension_resource_request_policy/hosted_app/test.png Binary files differindex 4421311..4421311 100644 --- a/chrome/test/data/extensions/origin_privileges/hosted_app/test.png +++ b/chrome/test/data/extensions/api_test/extension_resource_request_policy/hosted_app/test.png diff --git a/chrome/test/data/extensions/origin_privileges/hosted_app/test2.png b/chrome/test/data/extensions/api_test/extension_resource_request_policy/hosted_app/test2.png Binary files differindex 4421311..4421311 100644 --- a/chrome/test/data/extensions/origin_privileges/hosted_app/test2.png +++ b/chrome/test/data/extensions/api_test/extension_resource_request_policy/hosted_app/test2.png diff --git a/chrome/test/data/extensions/origin_privileges/index.html b/chrome/test/data/extensions/api_test/extension_resource_request_policy/index.html index 4183769..4183769 100644 --- a/chrome/test/data/extensions/origin_privileges/index.html +++ b/chrome/test/data/extensions/api_test/extension_resource_request_policy/index.html diff --git a/chrome/test/data/extensions/api_test/extension_resource_request_policy/media/audio.html b/chrome/test/data/extensions/api_test/extension_resource_request_policy/media/audio.html new file mode 100644 index 0000000..8ef69f4 --- /dev/null +++ b/chrome/test/data/extensions/api_test/extension_resource_request_policy/media/audio.html @@ -0,0 +1 @@ +<audio src="bear.wav" oncanplay="chrome.test.notifyPass()"> diff --git a/chrome/test/data/extensions/api_test/extension_resource_request_policy/media/bear.wav b/chrome/test/data/extensions/api_test/extension_resource_request_policy/media/bear.wav Binary files differnew file mode 100644 index 0000000..1870eed --- /dev/null +++ b/chrome/test/data/extensions/api_test/extension_resource_request_policy/media/bear.wav diff --git a/chrome/test/data/extensions/api_test/extension_resource_request_policy/media/bear.webm b/chrome/test/data/extensions/api_test/extension_resource_request_policy/media/bear.webm Binary files differnew file mode 100644 index 0000000..422df3f --- /dev/null +++ b/chrome/test/data/extensions/api_test/extension_resource_request_policy/media/bear.webm diff --git a/chrome/test/data/extensions/api_test/extension_resource_request_policy/media/manifest.json b/chrome/test/data/extensions/api_test/extension_resource_request_policy/media/manifest.json new file mode 100644 index 0000000..0d9792a --- /dev/null +++ b/chrome/test/data/extensions/api_test/extension_resource_request_policy/media/manifest.json @@ -0,0 +1,4 @@ +{ + "name": "test", + "version": "1" +} diff --git a/chrome/test/data/extensions/api_test/extension_resource_request_policy/media/video.html b/chrome/test/data/extensions/api_test/extension_resource_request_policy/media/video.html new file mode 100644 index 0000000..dfa951c --- /dev/null +++ b/chrome/test/data/extensions/api_test/extension_resource_request_policy/media/video.html @@ -0,0 +1,3 @@ +<!-- The display:none is a workaround for crbug.com/71905 --> +<video src="bear.webm" oncanplay="chrome.test.notifyPass()" + style="display:none"> |