diff options
11 files changed, 174 insertions, 142 deletions
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc index 4eb7744..44cc3ae 100644 --- a/chrome/browser/apps/guest_view/web_view_browsertest.cc +++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc @@ -89,6 +89,7 @@ namespace { const char kEmptyResponsePath[] = "/close-socket"; const char kRedirectResponsePath[] = "/server-redirect"; const char kUserAgentRedirectResponsePath[] = "/detect-user-agent"; +const char kCacheResponsePath[] = "/cache-control-response"; const char kRedirectResponseFullPath[] = "/extensions/platform_apps/web_view/shim/guest_redirect.html"; @@ -256,40 +257,6 @@ class MockWebContentsDelegate : public content::WebContentsDelegate { DISALLOW_COPY_AND_ASSIGN(MockWebContentsDelegate); }; -class MockWebViewGuestDelegate : public extensions::WebViewGuestDelegate { - public: - explicit MockWebViewGuestDelegate(extensions::WebViewGuest* web_view_guest) - : web_view_guest_(web_view_guest), clear_cache_called_(false) {} - ~MockWebViewGuestDelegate() override {} - - // WebViewGuestDelegate implementation. - void ClearCache(base::Time remove_since, - const base::Closure& callback) override { - clear_cache_called_ = true; - base::MessageLoop::current()->PostTask(FROM_HERE, callback); - } - bool HandleContextMenu(const content::ContextMenuParams& params) override { - return false; - } - void OnAttachWebViewHelpers(content::WebContents* contents) override {} - void OnDidCommitProvisionalLoadForFrame(bool is_main_frame) override {} - void OnDidInitialize() override {} - void OnDocumentLoadedInFrame( - content::RenderFrameHost* render_frame_host) override {} - void OnGuestDestroyed() override {} - void OnShowContextMenu( - int request_id, - const WebViewGuestDelegate::MenuItemVector* items) override {} - - bool clear_cache_called() { return clear_cache_called_; } - - private: - extensions::WebViewGuest* web_view_guest_; - bool clear_cache_called_; - - DISALLOW_COPY_AND_ASSIGN(MockWebViewGuestDelegate); -}; - // This class intercepts download request from the guest. class MockDownloadWebContentsDelegate : public content::WebContentsDelegate { public: @@ -608,14 +575,27 @@ class WebViewTest : public extensions::PlatformAppBrowserTest { static scoped_ptr<net::test_server::HttpResponse> EmptyResponseHandler( const std::string& path, const net::test_server::HttpRequest& request) { - if (StartsWithASCII(path, request.relative_url, true)) { - return scoped_ptr<net::test_server::HttpResponse>( - new EmptyHttpResponse); - } + if (StartsWithASCII(path, request.relative_url, true)) + return scoped_ptr<net::test_server::HttpResponse>(new EmptyHttpResponse); return scoped_ptr<net::test_server::HttpResponse>(); } + // Handles |request| by serving cache-able response. + static scoped_ptr<net::test_server::HttpResponse> CacheControlResponseHandler( + const std::string& path, + const net::test_server::HttpRequest& request) { + if (!StartsWithASCII(path, request.relative_url, true)) + return scoped_ptr<net::test_server::HttpResponse>(); + + scoped_ptr<net::test_server::BasicHttpResponse> http_response( + new net::test_server::BasicHttpResponse); + http_response->AddCustomHeader("Cache-control", "max-age=3600"); + http_response->set_content_type("text/plain"); + http_response->set_content("dummy text"); + return http_response.Pass(); + } + // Shortcut to return the current MenuManager. extensions::MenuManager* menu_manager() { return extensions::MenuManager::Get(browser()->profile()); @@ -662,6 +642,9 @@ class WebViewTest : public extensions::PlatformAppBrowserTest { &WebViewTest::UserAgentResponseHandler, kUserAgentRedirectResponsePath, embedded_test_server()->GetURL(kRedirectResponseFullPath))); + + embedded_test_server()->RegisterRequestHandler(base::Bind( + &WebViewTest::CacheControlResponseHandler, kCacheResponsePath)); } LoadAndLaunchPlatformApp(app_location.c_str(), "Launched"); @@ -2434,25 +2417,7 @@ IN_PROC_BROWSER_TEST_F(WebViewTest, ClearData) { } IN_PROC_BROWSER_TEST_F(WebViewTest, ClearDataCache) { - LoadAppWithGuest("web_view/clear_data_cache"); - content::WebContents* guest_web_contents = GetGuestWebContents(); - auto guest = extensions::WebViewGuest::FromWebContents(guest_web_contents); - ASSERT_TRUE(guest); - scoped_ptr<extensions::WebViewGuestDelegate> mock_web_view_guest_delegate( - new MockWebViewGuestDelegate(guest)); - scoped_ptr<extensions::WebViewGuestDelegate> orig_web_view_guest_delegate = - guest->SetDelegateForTesting(mock_web_view_guest_delegate.Pass()); - - ASSERT_TRUE(GetEmbedderWebContents()); - ExtensionTestMessageListener clear_data_done_listener( - "WebViewTest.CLEAR_DATA_DONE", false); - EXPECT_TRUE(content::ExecuteScript( - GetEmbedderWebContents(), base::StringPrintf("testClearDataCache()"))); - EXPECT_TRUE(clear_data_done_listener.WaitUntilSatisfied()); - - // Reset delegate back to original once we're done mocking. - mock_web_view_guest_delegate = - guest->SetDelegateForTesting(orig_web_view_guest_delegate.Pass()); + TestHelper("testClearCache", "web_view/clear_data_cache", NEEDS_TEST_SERVER); } // This test is disabled on Win due to being flaky. http://crbug.com/294592 diff --git a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc index 03abc79..ffdb52d 100644 --- a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc +++ b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc @@ -11,10 +11,8 @@ #include "chrome/browser/renderer_context_menu/render_view_context_menu.h" #include "chrome/browser/ui/pdf/chrome_pdf_web_contents_helper_client.h" #include "chrome/common/chrome_version_info.h" -#include "components/browsing_data/storage_partition_http_cache_data_remover.h" #include "components/pdf/browser/pdf_web_contents_helper.h" #include "components/renderer_context_menu/context_menu_delegate.h" -#include "components/web_cache/browser/web_cache_manager.h" #include "content/public/browser/render_process_host.h" #include "extensions/browser/api/web_request/web_request_api.h" #include "extensions/browser/guest_view/guest_view_event.h" @@ -42,28 +40,6 @@ ChromeWebViewGuestDelegate::ChromeWebViewGuestDelegate( ChromeWebViewGuestDelegate::~ChromeWebViewGuestDelegate() { } -void ChromeWebViewGuestDelegate::ClearCache( - base::Time remove_since, - const base::Closure& done_callback) { - int render_process_id = guest_web_contents()->GetRenderProcessHost()->GetID(); - // We need to clear renderer cache separately for our process because - // StoragePartitionHttpCacheDataRemover::ClearData() does not clear that. - web_cache::WebCacheManager::GetInstance()->Remove(render_process_id); - web_cache::WebCacheManager::GetInstance()->ClearCacheForProcess( - render_process_id); - - content::StoragePartition* partition = - content::BrowserContext::GetStoragePartition( - guest_web_contents()->GetBrowserContext(), - guest_web_contents()->GetSiteInstance()); - - // StoragePartitionHttpCacheDataRemover removes itself when it is done. - // TODO(lazyboy): Once StoragePartitionHttpCacheDataRemover moves to - // components/, move |ClearCache| to WebViewGuest: http//crbug.com/471287. - browsing_data::StoragePartitionHttpCacheDataRemover::CreateForRange( - partition, remove_since, base::Time::Now())->Remove(done_callback); -} - bool ChromeWebViewGuestDelegate::HandleContextMenu( const content::ContextMenuParams& params) { ContextMenuDelegate* menu_delegate = diff --git a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.h b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.h index 9cd1722..aae364a 100644 --- a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.h +++ b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.h @@ -27,8 +27,6 @@ class ChromeWebViewGuestDelegate : public WebViewGuestDelegate { ~ChromeWebViewGuestDelegate() override; // WebViewGuestDelegate implementation. - void ClearCache(base::Time remove_since, - const base::Closure& done_callback) override; bool HandleContextMenu(const content::ContextMenuParams& params) override; void OnAttachWebViewHelpers(content::WebContents* contents) override; void OnDidCommitProvisionalLoadForFrame(bool is_main_frame) override; diff --git a/chrome/test/data/extensions/platform_apps/web_view/clear_data_cache/embedder.js b/chrome/test/data/extensions/platform_apps/web_view/clear_data_cache/embedder.js index 435c5cb..5d41fa5 100644 --- a/chrome/test/data/extensions/platform_apps/web_view/clear_data_cache/embedder.js +++ b/chrome/test/data/extensions/platform_apps/web_view/clear_data_cache/embedder.js @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var LOG = function(msg) { window.console.log(msg); }; +var LOG = function(var_args) { + window.console.log(Array.prototype.slice.call(arguments)); +}; function ClearDataTester() { this.webview_ = null; @@ -19,62 +21,123 @@ function ClearDataTester() { ClearDataTester.prototype.setWebview = function(webview) { this.webview_ = webview; + this.webview_.onconsolemessage = this.onGuestConsoleMessage_.bind(this); +}; + +ClearDataTester.prototype.onGuestConsoleMessage_ = function(e) { + LOG('G:', e.message); + if (e.message == 'ERROR') { + this.fail(); + } }; +ClearDataTester.prototype.requestXhrFromWebView_ = function() { + var msg = ['sendXhr']; + this.webview_.contentWindow.postMessage(JSON.stringify(msg), '*'); +}; + +ClearDataTester.prototype.fail = function() { + chrome.test.sendMessage('TEST_FAILED'); +}; + +ClearDataTester.prototype.pass = function() { + chrome.test.sendMessage('TEST_PASSED'); +}; + +// This test instructs a <webview> to load same resource request via xhr +// multiple times. That makes some of those requests to be served from +// http cache. +// Calling clearData{cache: true} resets the cache and next request +// from the same resource should not be served from cache. ClearDataTester.prototype.testClearDataCache = function() { - this.webview_.clearData( - {since: 10}, {"cache": true}, function doneCallback() { - LOG('clearData done'); - chrome.test.sendMessage('WebViewTest.CLEAR_DATA_DONE'); - }); + // Request same resource multiple times from <webview>, latter + // ones would be served from cache. + var responseCount = 0; + var servedFromCacheCount = 0; + + var responseStartedHandler = function(details) { + LOG('onResponseStarted, url:', details.url, + 'fromCache:', details.fromCache); + if (details.url.indexOf('/cache-control-response') == -1) { + return; + } + + ++responseCount; + if (details.fromCache) { + ++servedFromCacheCount; + } + + if (responseCount == 5) { + // We should see some request getting served from cache. + if (servedFromCacheCount <= 0) { + this.fail(); + return; + } + + // Clear cache from <webview>. + this.webview_.clearData( + {since: 10}, {'cache': true}, function doneCallback() { + LOG('clearData done'); + this.requestXhrFromWebView_(); + // Now request the same resource again, this time it should + // not be served from cache. + this.requestXhrFromWebView_(); + }.bind(this)); + } else if (responseCount == 6) { + if (details.fromCache) { + // Response received after clearData should not be served from cache. + this.fail(); + } else { + this.pass(); + } + } + }.bind(this); + + this.webview_.request.onResponseStarted.addListener( + responseStartedHandler, {urls: ['<all_urls>']}); + + for (var i = 0; i < 5; ++i) { + this.requestXhrFromWebView_(); + } }; var tester = new ClearDataTester(); // window.* exported functions begin. -window.testClearDataCache = function() { - LOG('window.testClearDataCache'); - tester.testClearDataCache(); +window.runTest = function(testName) { + switch (testName) { + case 'testClearCache': + tester.testClearDataCache(); + break; + default: + LOG('curious test to run:', testName); + tester.fail(); + break; + } }; // window.* exported functions end. -function setUpTest(messageCallback) { - var guestUrl = 'data:text/html,<html><body>guest</body></html>'; +function setUpTest(guestURL, doneCallback) { var webview = document.createElement('webview'); webview.onloadstop = function(e) { LOG('webview has loaded.'); - webview.executeScript( - {file: 'guest.js'}, - function(results) { - if (!results || !results.length) { - chrome.test.sendMessage('WebViewTest.FAILURE'); - return; - } - LOG('Script has been injected into webview.'); - // Establish a communication channel with the guest. - var msg = ['connect']; - webview.contentWindow.postMessage(JSON.stringify(msg), '*'); - }); + doneCallback(webview); }; - window.addEventListener('message', function(e) { - var data = JSON.parse(e.data); - if (data[0] == 'connected') { - console.log('A communication channel has been established with webview.'); - } - messageCallback(webview); - }); - - webview.setAttribute('src', guestUrl); + webview.setAttribute('src', guestURL); document.body.appendChild(webview); } onload = function() { chrome.test.getConfig(function(config) { - setUpTest(function(webview) { + LOG('config: ' + config.testServer.port); + var guestURL = 'http://localhost:' + config.testServer.port + + '/extensions/platform_apps/web_view/clear_data_cache/guest.html'; + setUpTest(guestURL, function(webview) { LOG('Guest load completed.'); - chrome.test.sendMessage('WebViewTest.LAUNCHED'); + //chrome.test.sendMessage('WebViewTest.LAUNCHED'); + chrome.test.sendMessage('Launched'); tester.setWebview(webview); }); }); diff --git a/chrome/test/data/extensions/platform_apps/web_view/clear_data_cache/guest.html b/chrome/test/data/extensions/platform_apps/web_view/clear_data_cache/guest.html new file mode 100644 index 0000000..74e3cff --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/web_view/clear_data_cache/guest.html @@ -0,0 +1,10 @@ +<!-- + * Copyright 2015 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. +--> +<html> +<body> + <script src="guest.js"></script> +</body> +</html> diff --git a/chrome/test/data/extensions/platform_apps/web_view/clear_data_cache/guest.js b/chrome/test/data/extensions/platform_apps/web_view/clear_data_cache/guest.js index 6b90df3..72b5aea 100644 --- a/chrome/test/data/extensions/platform_apps/web_view/clear_data_cache/guest.js +++ b/chrome/test/data/extensions/platform_apps/web_view/clear_data_cache/guest.js @@ -5,24 +5,33 @@ var LOG = function(msg) { window.console.log(msg); }; LOG('Guest script loading.'); -// The window reference of the embedder to send post message reply. -var embedderWindowChannel = null; +var fail = function() { + // Embedder catches this message and fails the test. + LOG('ERROR'); +}; -// A value that uniquely identifies the guest sending the messages to the -// embedder. -var channelId = 0; -var notifyEmbedder = function(msg_array) { - var msg = msg_array.concat([channelId]); - embedderWindowChannel.postMessage(JSON.stringify(msg), '*'); +var sendXhr = function() { + var xhr = new XMLHttpRequest(); + xhr.onload = function() { + LOG('xhr.onload'); + if (xhr.responseText != 'dummy text') { + fail(); + } + }; + xhr.onerror = function() { + fail(); + }; + xhr.open('GET', '/cache-control-response', true); + xhr.send(); }; var onPostMessageReceived = function(e) { - embedderWindowChannel = e.source; var data = JSON.parse(e.data); - if (data[0] == 'connect') { - channelId = data[1]; - notifyEmbedder(['connected']); + if (data[0] != 'sendXhr') { + fail(); return; } + + sendXhr(); }; window.addEventListener('message', onPostMessageReceived, false); diff --git a/extensions/DEPS b/extensions/DEPS index a5faa35..285b7d3 100644 --- a/extensions/DEPS +++ b/extensions/DEPS @@ -1,5 +1,6 @@ include_rules = [ # Do not add Chrome dependencies. Much work went into removing them. + "+components/browsing_data", "+components/crx_file", "+components/url_matcher", "-content", diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn index 9ecb71e..6a643160 100644 --- a/extensions/browser/BUILD.gn +++ b/extensions/browser/BUILD.gn @@ -44,6 +44,7 @@ source_set("browser") { "//extensions") deps += [ + "//components/browsing_data", "//components/onc", "//components/storage_monitor", "//components/update_client", diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc index f29e12f..721cb11 100644 --- a/extensions/browser/guest_view/web_view/web_view_guest.cc +++ b/extensions/browser/guest_view/web_view/web_view_guest.cc @@ -7,6 +7,8 @@ #include "base/message_loop/message_loop.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "components/browsing_data/storage_partition_http_cache_data_remover.h" +#include "components/web_cache/browser/web_cache_manager.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_security_policy.h" @@ -705,15 +707,25 @@ bool WebViewGuest::ClearData(base::Time remove_since, return false; if (removal_mask & webview::WEB_VIEW_REMOVE_DATA_MASK_CACHE) { - if (web_view_guest_delegate_) { - // First clear http cache data and then clear the rest in - // |ClearDataInternal|. - web_view_guest_delegate_->ClearCache( - remove_since, base::Bind(&WebViewGuest::ClearDataInternal, - weak_ptr_factory_.GetWeakPtr(), remove_since, - removal_mask, callback)); - return true; - } + // First clear http cache data and then clear the rest in + // |ClearDataInternal|. + int render_process_id = web_contents()->GetRenderProcessHost()->GetID(); + // We need to clear renderer cache separately for our process because + // StoragePartitionHttpCacheDataRemover::ClearData() does not clear that. + web_cache::WebCacheManager::GetInstance()->Remove(render_process_id); + web_cache::WebCacheManager::GetInstance()->ClearCacheForProcess( + render_process_id); + + base::Closure cache_removal_done_callback = base::Bind( + &WebViewGuest::ClearDataInternal, weak_ptr_factory_.GetWeakPtr(), + remove_since, removal_mask, callback); + // StoragePartitionHttpCacheDataRemover removes itself when it is done. + // components/, move |ClearCache| to WebViewGuest: http//crbug.com/471287. + browsing_data::StoragePartitionHttpCacheDataRemover::CreateForRange( + partition, remove_since, base::Time::Now()) + ->Remove(cache_removal_done_callback); + + return true; } ClearDataInternal(remove_since, removal_mask, callback); diff --git a/extensions/browser/guest_view/web_view/web_view_guest_delegate.h b/extensions/browser/guest_view/web_view/web_view_guest_delegate.h index 7b1dd56..473ffd3d 100644 --- a/extensions/browser/guest_view/web_view/web_view_guest_delegate.h +++ b/extensions/browser/guest_view/web_view/web_view_guest_delegate.h @@ -32,10 +32,6 @@ class WebViewGuestDelegate { typedef std::vector<linked_ptr<api::web_view_internal::ContextMenuItem> > MenuItemVector; - // Clears http cache for this guest's StoragePartition. - virtual void ClearCache(base::Time remove_since, - const base::Closure& callback) = 0; - // Called when context menu operation was handled. virtual bool HandleContextMenu(const content::ContextMenuParams& params) = 0; diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp index 4c12f71..a057839 100644 --- a/extensions/extensions.gyp +++ b/extensions/extensions.gyp @@ -124,6 +124,7 @@ 'dependencies': [ '../base/base.gyp:base', '../base/base.gyp:base_prefs', + '../components/components.gyp:browsing_data', '../components/components.gyp:device_event_log_component', '../components/components.gyp:keyed_service_content', '../components/components.gyp:keyed_service_core', |