diff --git a/DEPS b/DEPS index abdf99f..41dd62a 100644 --- a/DEPS +++ b/DEPS
@@ -44,7 +44,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '64735758443e0a81a2f8a67338a5203fd725c2f3', + 'v8_revision': 'f9b1cd343df071f543f07539513692367af25b06', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -88,7 +88,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling NaCl # and whatever else without interference from each other. - 'nacl_revision': 'f88070127d32714df2714d94c9494fce951993d8', + 'nacl_revision': '015356a98e4430dff9ce7e80ce9d2a62b04c2c4e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling freetype # and whatever else without interference from each other. @@ -96,7 +96,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '28f796f29c9e269f992fbb1550b0e384a227f602', + 'catapult_revision': 'd4f2d777c7aa4d9454a74afe92ff17e13da62380', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other.
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc index d36e22d..28410322 100644 --- a/chrome/browser/pdf/pdf_extension_test.cc +++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -143,6 +143,7 @@ WebContents* guest_contents = LoadPdfGetGuestContents(url); ASSERT_TRUE(guest_contents); std::string test_util_js; + std::string mock_interactions_js; { base::ThreadRestrictions::ScopedAllowIO allow_io; @@ -152,6 +153,15 @@ base::FilePath test_util_path = test_data_dir.AppendASCII("test_util.js"); ASSERT_TRUE(base::ReadFileToString(test_util_path, &test_util_js)); + base::FilePath source_root_dir; + PathService::Get(base::DIR_SOURCE_ROOT, &source_root_dir); + base::FilePath mock_interactions_path = source_root_dir.Append( + FILE_PATH_LITERAL("third_party/polymer/v1_0/components-chromium/" + "iron-test-helpers/mock-interactions.js")); + ASSERT_TRUE(base::ReadFileToString(mock_interactions_path, + &mock_interactions_js)); + test_util_js.append(mock_interactions_js); + base::FilePath test_file_path = test_data_dir.AppendASCII(filename); std::string test_js; ASSERT_TRUE(base::ReadFileToString(test_file_path, &test_js));
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 4523ef28..29840ec 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1697,6 +1697,7 @@ "//third_party/accessibility-audit/axs_testing.js", "//third_party/chaijs/chai.js", "//third_party/mocha/mocha.js", + "//third_party/polymer/v1_0/components-chromium/iron-test-helpers/mock-interactions.js", "//third_party/pyftpdlib/", "//third_party/pywebsocket/", "//third_party/simplejson/",
diff --git a/chrome/test/data/pdf/basic_test.js b/chrome/test/data/pdf/basic_test.js index fc541f6..bde0be10 100644 --- a/chrome/test/data/pdf/basic_test.js +++ b/chrome/test/data/pdf/basic_test.js
@@ -123,6 +123,4 @@ } ]; -importTestHelpers().then(function() { - chrome.test.runTests(tests); -}); +chrome.test.runTests(tests);
diff --git a/chrome/test/data/pdf/material_elements_test.js b/chrome/test/data/pdf/material_elements_test.js index 082e960..bad24228 100644 --- a/chrome/test/data/pdf/material_elements_test.js +++ b/chrome/test/data/pdf/material_elements_test.js
@@ -195,6 +195,4 @@ } ]; -importTestHelpers().then(function() { - chrome.test.runTests(tests); -}); +chrome.test.runTests(tests);
diff --git a/chrome/test/data/pdf/page_change_test.js b/chrome/test/data/pdf/page_change_test.js index 85395d6..8c27397 100644 --- a/chrome/test/data/pdf/page_change_test.js +++ b/chrome/test/data/pdf/page_change_test.js
@@ -69,6 +69,4 @@ } ]; -importTestHelpers().then(function() { - chrome.test.runTests(tests); -}); +chrome.test.runTests(tests);
diff --git a/chrome/test/data/pdf/test_util.js b/chrome/test/data/pdf/test_util.js index 7fff3fa3..9efead4 100644 --- a/chrome/test/data/pdf/test_util.js +++ b/chrome/test/data/pdf/test_util.js
@@ -104,27 +104,3 @@ this.pageDimensions = []; }; } - -function importHTML(src) { - var link = document.createElement('link'); - var promise = new Promise(function(resolve, reject) { - link.onload = resolve; - link.onerror = reject; - }); - link.rel = 'import'; - link.href = src; - document.head.appendChild(link); - return promise; -} - -/** - * Import iron-test-helpers into the test document. - * @example - * importTestHelpers().then(function() { - * chrome.test.runTests(...); - * }) - */ -function importTestHelpers() { - return importHTML('chrome://resources/polymer/v1_0/iron-test-helpers/' + - 'iron-test-helpers.html'); -}
diff --git a/chrome/test/data/pdf/toolbar_manager_test.js b/chrome/test/data/pdf/toolbar_manager_test.js index 041101c..ecd74ab 100644 --- a/chrome/test/data/pdf/toolbar_manager_test.js +++ b/chrome/test/data/pdf/toolbar_manager_test.js
@@ -194,6 +194,4 @@ } ]; -importTestHelpers().then(function() { - chrome.test.runTests(tests); -}); +chrome.test.runTests(tests);
diff --git a/components/feature_engagement_tracker/internal/init_aware_model.cc b/components/feature_engagement_tracker/internal/init_aware_model.cc index a5ab190..c514a70 100644 --- a/components/feature_engagement_tracker/internal/init_aware_model.cc +++ b/components/feature_engagement_tracker/internal/init_aware_model.cc
@@ -9,7 +9,9 @@ namespace feature_engagement_tracker { InitAwareModel::InitAwareModel(std::unique_ptr<Model> model) - : model_(std::move(model)), weak_ptr_factory_(this) { + : model_(std::move(model)), + initialization_complete_(false), + weak_ptr_factory_(this) { DCHECK(model_); } @@ -37,19 +39,27 @@ return; } + if (initialization_complete_) + return; + queued_events_.push_back(std::tie(event_name, current_day)); } void InitAwareModel::OnInitializeComplete( const OnModelInitializationFinished& callback, bool success) { + initialization_complete_ = true; if (success) { for (auto& event : queued_events_) model_->IncrementEvent(std::get<0>(event), std::get<1>(event)); - queued_events_.clear(); } + queued_events_.clear(); callback.Run(success); } +size_t InitAwareModel::GetQueuedEventCountForTesting() { + return queued_events_.size(); +} + } // namespace feature_engagement_tracker
diff --git a/components/feature_engagement_tracker/internal/init_aware_model.h b/components/feature_engagement_tracker/internal/init_aware_model.h index 72a76d1..89b0e45 100644 --- a/components/feature_engagement_tracker/internal/init_aware_model.h +++ b/components/feature_engagement_tracker/internal/init_aware_model.h
@@ -30,6 +30,8 @@ void IncrementEvent(const std::string& event_name, uint32_t current_day) override; + size_t GetQueuedEventCountForTesting(); + private: void OnInitializeComplete(const OnModelInitializationFinished& callback, bool success); @@ -37,6 +39,11 @@ std::unique_ptr<Model> model_; std::vector<std::tuple<std::string, uint32_t>> queued_events_; + // Whether the initialization has completed. This will be set to true once + // the underlying model has been initialized, regardless of whether the + // result was a success or not. + bool initialization_complete_; + base::WeakPtrFactory<InitAwareModel> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(InitAwareModel);
diff --git a/components/feature_engagement_tracker/internal/init_aware_model_unittest.cc b/components/feature_engagement_tracker/internal/init_aware_model_unittest.cc index 6345257..00f3894 100644 --- a/components/feature_engagement_tracker/internal/init_aware_model_unittest.cc +++ b/components/feature_engagement_tracker/internal/init_aware_model_unittest.cc
@@ -98,6 +98,7 @@ model_->IncrementEvent("foo", 0U); model_->IncrementEvent("bar", 1U); + EXPECT_EQ(0U, model_->GetQueuedEventCountForTesting()); } TEST_F(InitAwareModelTest, QueuedIncrementEvent) { @@ -130,6 +131,40 @@ EXPECT_CALL(*mocked_model_, IsReady()).WillRepeatedly(Return(true)); EXPECT_CALL(*mocked_model_, IncrementEvent("qux", 3U)).Times(1); model_->IncrementEvent("qux", 3U); + EXPECT_EQ(0U, model_->GetQueuedEventCountForTesting()); +} + +TEST_F(InitAwareModelTest, QueuedIncrementEventWithUnsuccessfulInit) { + { + EXPECT_CALL(*mocked_model_, IsReady()).WillRepeatedly(Return(false)); + EXPECT_CALL(*mocked_model_, IncrementEvent(_, _)).Times(0); + + model_->IncrementEvent("foo", 0U); + model_->IncrementEvent("bar", 1U); + } + + Model::OnModelInitializationFinished callback; + EXPECT_CALL(*mocked_model_, Initialize(_, 2U)) + .WillOnce(SaveArg<0>(&callback)); + model_->Initialize(load_callback_, 2U); + + { + Sequence sequence; + EXPECT_CALL(*mocked_model_, IncrementEvent("foo", 0U)) + .Times(0) + .InSequence(sequence); + EXPECT_CALL(*mocked_model_, IncrementEvent("bar", 1U)) + .Times(0) + .InSequence(sequence); + + callback.Run(false); + EXPECT_FALSE(load_success_.value()); + EXPECT_EQ(0U, model_->GetQueuedEventCountForTesting()); + } + + EXPECT_CALL(*mocked_model_, IncrementEvent("qux", 3U)).Times(0); + model_->IncrementEvent("qux", 3U); + EXPECT_EQ(0U, model_->GetQueuedEventCountForTesting()); } } // namespace feature_engagement_tracker
diff --git a/components/security_interstitials_strings.grdp b/components/security_interstitials_strings.grdp index 6e54c197..8d44d5d 100644 --- a/components/security_interstitials_strings.grdp +++ b/components/security_interstitials_strings.grdp
@@ -62,10 +62,20 @@ <!-- SSL error page: Superfish-specific --> <message name="IDS_SSL_SUPERFISH_HEADING" desc="The large heading at the top of the Superfish-specific SSL interstitial."> - Software on your computer is stopping Chrome from connecting to the web + Software on your computer is stopping Chrome from safely connecting to the web </message> <message name="IDS_SSL_SUPERFISH_PRIMARY_PARAGRAPH" desc="The primary explanatory paragraph for the Superfish-specific SSL interstitial."> - Follow these steps to remove the software and its associated certificate. You'll need administrator privileges. <ph name="BEGIN_LEARN_MORE_LINK"><a href="#" id="learn-more-link"></ph>Learn more<ph name="END_LEARN_MORE_LINK"></a></ph> + <ph name="BEGIN_PARAGRAPH"><p></ph>Follow these steps to temporarily disable the software so you can get on the web. You'll need administrator privileges.<ph name="END_PARAGRAPH"></p></ph> + + <ph name="BEGIN_LIST"><ol></ph> + <ph name="LIST_ITEM"><li></ph>Click <ph name="BEGIN_BOLD"><strong></ph>Start<ph name="END_BOLD"></strong></ph>, then search for and select <ph name="BEGIN_BOLD"><strong></ph>"View local services"<ph name="END_BOLD"></strong></ph> + <ph name="LIST_ITEM"><li></ph>Select <ph name="BEGIN_BOLD"><strong></ph>VisualDiscovery<ph name="END_BOLD"></strong></ph> + <ph name="LIST_ITEM"><li></ph>Under <ph name="BEGIN_BOLD"><strong></ph>Startup type<ph name="END_BOLD"></strong></ph>, select <ph name="BEGIN_BOLD"><strong></ph>Disabled<ph name="END_BOLD"></strong></ph> + <ph name="LIST_ITEM"><li></ph>Under <ph name="BEGIN_BOLD"><strong></ph>Service status<ph name="END_BOLD"></strong></ph>, click <ph name="BEGIN_BOLD"><strong></ph>Stop<ph name="END_BOLD"></strong></ph> + <ph name="LIST_ITEM"><li></ph>Click <ph name="BEGIN_BOLD"><strong></ph>Apply<ph name="END_BOLD"></strong></ph>, then click <ph name="BEGIN_BOLD"><strong></ph>OK<ph name="END_BOLD"></strong></ph> + <ph name="LIST_ITEM"><li></ph>Visit the <ph name="BEGIN_LEARN_MORE_LINK"><a href="#" id="learn-more-link"></ph>Chrome help center<ph name="END_LEARN_MORE_LINK"></a></ph> to learn how to permanently remove the software from your computer + <ph name="END_LIST"></ol></ph> + </message> <!-- SSL error page: overridable -->
diff --git a/content/browser/power_monitor_browsertest.cc b/content/browser/power_monitor_browsertest.cc index 83791f3..e7e09fae 100644 --- a/content/browser/power_monitor_browsertest.cc +++ b/content/browser/power_monitor_browsertest.cc
@@ -5,8 +5,12 @@ #include "base/bind.h" #include "base/macros.h" #include "base/run_loop.h" +#include "base/strings/utf_string_conversions.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" +#include "content/public/browser/utility_process_host.h" +#include "content/public/browser/utility_process_host_client.h" #include "content/public/browser/web_contents.h" #include "content/public/common/service_names.mojom.h" #include "content/public/test/browser_test_utils.h" @@ -37,6 +41,14 @@ run_loop.Run(); } +void StartUtilityProcessOnIOThread(mojom::PowerMonitorTestRequest request) { + UtilityProcessHost* host = UtilityProcessHost::Create(nullptr, nullptr); + host->SetName(base::ASCIIToUTF16("TestProcess")); + EXPECT_TRUE(host->Start()); + + BindInterface(host, std::move(request)); +} + class MockPowerMonitorMessageBroadcaster : public device::mojom::PowerMonitor { public: MockPowerMonitorMessageBroadcaster() = default; @@ -86,15 +98,38 @@ void BindPowerMonitor(const service_manager::BindSourceInfo& source_info, const std::string& interface_name, mojo::ScopedMessagePipeHandle handle) { - if (source_info.identity.name() == mojom::kRendererServiceName) + if (source_info.identity.name() == mojom::kRendererServiceName) { ++request_count_from_renderer_; + DCHECK(renderer_bound_closure_); + std::move(renderer_bound_closure_).Run(); + } else if (source_info.identity.name() == mojom::kUtilityServiceName) { + ++request_count_from_utility_; + + DCHECK(utility_bound_closure_); + std::move(utility_bound_closure_).Run(); + } + power_monitor_message_broadcaster_.Bind( device::mojom::PowerMonitorRequest(std::move(handle))); } protected: + void StartUtilityProcess(mojom::PowerMonitorTestPtr* power_monitor_test, + base::Closure utility_bound_closure) { + utility_bound_closure_ = utility_bound_closure; + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::BindOnce(&StartUtilityProcessOnIOThread, + mojo::MakeRequest(power_monitor_test))); + } + + void set_renderer_bound_closure(base::Closure closure) { + renderer_bound_closure_ = closure; + } + int request_count_from_renderer() { return request_count_from_renderer_; } + int request_count_from_utility() { return request_count_from_utility_; } void SimulatePowerStateChange(bool on_battery_power) { power_monitor_message_broadcaster_.OnPowerStateChange(on_battery_power); @@ -102,15 +137,21 @@ private: int request_count_from_renderer_ = 0; + int request_count_from_utility_ = 0; + base::OnceClosure renderer_bound_closure_; + base::OnceClosure utility_bound_closure_; MockPowerMonitorMessageBroadcaster power_monitor_message_broadcaster_; DISALLOW_COPY_AND_ASSIGN(PowerMonitorTest); }; -IN_PROC_BROWSER_TEST_F(PowerMonitorTest, RequestOnceFromOneRendererProcess) { +IN_PROC_BROWSER_TEST_F(PowerMonitorTest, TestRendererProcess) { ASSERT_EQ(0, request_count_from_renderer()); + base::RunLoop run_loop; + set_renderer_bound_closure(run_loop.QuitClosure()); ASSERT_TRUE(NavigateToURL(shell(), GetTestUrl(".", "simple_page.html"))); + run_loop.Run(); EXPECT_EQ(1, request_count_from_renderer()); mojom::PowerMonitorTestPtr power_monitor_renderer; @@ -127,6 +168,24 @@ VerifyPowerStateInChildProcess(power_monitor_renderer.get(), false); } +IN_PROC_BROWSER_TEST_F(PowerMonitorTest, TestUtilityProcess) { + mojom::PowerMonitorTestPtr power_monitor_utility; + + ASSERT_EQ(0, request_count_from_utility()); + base::RunLoop run_loop; + StartUtilityProcess(&power_monitor_utility, run_loop.QuitClosure()); + run_loop.Run(); + EXPECT_EQ(1, request_count_from_utility()); + + SimulatePowerStateChange(true); + // Verify utility process on_battery_power changed to true. + VerifyPowerStateInChildProcess(power_monitor_utility.get(), true); + + SimulatePowerStateChange(false); + // Verify utility process on_battery_power changed to false. + VerifyPowerStateInChildProcess(power_monitor_utility.get(), false); +} + } // namespace } // namespace content
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn index 25bed8c1..21fb08f3 100644 --- a/content/shell/BUILD.gn +++ b/content/shell/BUILD.gn
@@ -160,6 +160,8 @@ "common/layout_test/layout_test_switches.cc", "common/layout_test/layout_test_switches.h", "common/leak_detection_result.h", + "common/power_monitor_test_impl.cc", + "common/power_monitor_test_impl.h", "common/shell_content_client.cc", "common/shell_content_client.h", "common/shell_messages.cc",
diff --git a/content/shell/browser/content_shell_utility_manifest_overlay.json b/content/shell/browser/content_shell_utility_manifest_overlay.json index abb81bdc..5ca52ab 100644 --- a/content/shell/browser/content_shell_utility_manifest_overlay.json +++ b/content/shell/browser/content_shell_utility_manifest_overlay.json
@@ -4,6 +4,7 @@ "service_manager:connector": { "provides": { "browser": [ + "content::mojom::PowerMonitorTest", "content::mojom::TestService" ] }
diff --git a/content/shell/common/power_monitor_test_impl.cc b/content/shell/common/power_monitor_test_impl.cc new file mode 100644 index 0000000..37cc850 --- /dev/null +++ b/content/shell/common/power_monitor_test_impl.cc
@@ -0,0 +1,53 @@ +// Copyright (c) 2017 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 "content/shell/common/power_monitor_test_impl.h" + +#include "mojo/public/cpp/bindings/strong_binding.h" + +namespace content { + +// static +void PowerMonitorTestImpl::MakeStrongBinding( + std::unique_ptr<PowerMonitorTestImpl> instance, + const service_manager::BindSourceInfo& source_info, + mojom::PowerMonitorTestRequest request) { + mojo::MakeStrongBinding(std::move(instance), std::move(request)); +} + +PowerMonitorTestImpl::PowerMonitorTestImpl() { + base::PowerMonitor* power_monitor = base::PowerMonitor::Get(); + if (power_monitor) + power_monitor->AddObserver(this); +} + +PowerMonitorTestImpl::~PowerMonitorTestImpl() { + base::PowerMonitor* power_monitor = base::PowerMonitor::Get(); + if (power_monitor) + power_monitor->RemoveObserver(this); +} + +void PowerMonitorTestImpl::QueryNextState(QueryNextStateCallback callback) { + // Do not allow overlapping call. + DCHECK(callback_.is_null()); + callback_ = std::move(callback); + + if (need_to_report_) + ReportState(); +} + +void PowerMonitorTestImpl::OnPowerStateChange(bool on_battery_power) { + on_battery_power_ = on_battery_power; + need_to_report_ = true; + + if (!callback_.is_null()) + ReportState(); +} + +void PowerMonitorTestImpl::ReportState() { + std::move(callback_).Run(on_battery_power_); + need_to_report_ = false; +} + +} // namespace content
diff --git a/content/shell/common/power_monitor_test_impl.h b/content/shell/common/power_monitor_test_impl.h new file mode 100644 index 0000000..0f1bf233 --- /dev/null +++ b/content/shell/common/power_monitor_test_impl.h
@@ -0,0 +1,51 @@ +// Copyright (c) 2017 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 CONTENT_SHELL_COMMON_POWER_MONITOR_TEST_IMPL_H_ +#define CONTENT_SHELL_COMMON_POWER_MONITOR_TEST_IMPL_H_ + +#include <memory> + +#include "base/macros.h" +#include "base/power_monitor/power_monitor.h" +#include "content/shell/common/power_monitor_test.mojom.h" + +namespace service_manager { +struct BindSourceInfo; +} + +namespace content { + +class PowerMonitorTestImpl : public base::PowerObserver, + public mojom::PowerMonitorTest { + public: + static void MakeStrongBinding( + std::unique_ptr<PowerMonitorTestImpl> instance, + const service_manager::BindSourceInfo& source_info, + mojom::PowerMonitorTestRequest request); + + PowerMonitorTestImpl(); + ~PowerMonitorTestImpl() override; + + private: + // mojom::PowerMonitorTest: + void QueryNextState(QueryNextStateCallback callback) override; + + // base::PowerObserver: + void OnPowerStateChange(bool on_battery_power) override; + void OnSuspend() override {} + void OnResume() override {} + + void ReportState(); + + QueryNextStateCallback callback_; + bool on_battery_power_ = false; + bool need_to_report_ = false; + + DISALLOW_COPY_AND_ASSIGN(PowerMonitorTestImpl); +}; + +} // namespace content + +#endif // CONTENT_SHELL_COMMON_POWER_MONITOR_TEST_IMPL_H_
diff --git a/content/shell/renderer/shell_content_renderer_client.cc b/content/shell/renderer/shell_content_renderer_client.cc index e78755d..e30a413 100644 --- a/content/shell/renderer/shell_content_renderer_client.cc +++ b/content/shell/renderer/shell_content_renderer_client.cc
@@ -10,18 +10,16 @@ #include "base/command_line.h" #include "base/logging.h" #include "base/macros.h" -#include "base/power_monitor/power_monitor.h" #include "components/cdm/renderer/external_clear_key_key_system_properties.h" #include "components/web_cache/renderer/web_cache_impl.h" #include "content/public/child/child_thread.h" #include "content/public/common/service_manager_connection.h" #include "content/public/common/simple_connection_filter.h" #include "content/public/test/test_service.mojom.h" -#include "content/shell/common/power_monitor_test.mojom.h" +#include "content/shell/common/power_monitor_test_impl.h" #include "content/shell/common/shell_switches.h" #include "content/shell/renderer/shell_render_view_observer.h" #include "mojo/public/cpp/bindings/binding.h" -#include "mojo/public/cpp/bindings/strong_binding.h" #include "mojo/public/cpp/system/message_pipe.h" #include "ppapi/features/features.h" #include "services/service_manager/public/cpp/binder_registry.h" @@ -98,61 +96,6 @@ new TestServiceImpl(std::move(request)); } -class PowerMonitorTestImpl : public base::PowerObserver, - public mojom::PowerMonitorTest { - public: - static void MakeStrongBinding( - std::unique_ptr<PowerMonitorTestImpl> instance, - const service_manager::BindSourceInfo& source_info, - mojom::PowerMonitorTestRequest request) { - mojo::MakeStrongBinding(std::move(instance), std::move(request)); - } - - PowerMonitorTestImpl() { - base::PowerMonitor* power_monitor = base::PowerMonitor::Get(); - if (power_monitor) - power_monitor->AddObserver(this); - } - ~PowerMonitorTestImpl() override { - base::PowerMonitor* power_monitor = base::PowerMonitor::Get(); - if (power_monitor) - power_monitor->RemoveObserver(this); - } - - private: - // mojom::PowerMonitorTest: - void QueryNextState(QueryNextStateCallback callback) override { - // Do not allow overlapping call. - DCHECK(callback_.is_null()); - callback_ = std::move(callback); - - if (need_to_report_) - ReportState(); - } - - // base::PowerObserver: - void OnPowerStateChange(bool on_battery_power) override { - on_battery_power_ = on_battery_power; - need_to_report_ = true; - - if (!callback_.is_null()) - ReportState(); - } - void OnSuspend() override {} - void OnResume() override {} - - void ReportState() { - std::move(callback_).Run(on_battery_power_); - need_to_report_ = false; - } - - QueryNextStateCallback callback_; - bool on_battery_power_ = false; - bool need_to_report_ = false; - - DISALLOW_COPY_AND_ASSIGN(PowerMonitorTestImpl); -}; - } // namespace ShellContentRendererClient::ShellContentRendererClient() {}
diff --git a/content/shell/utility/shell_content_utility_client.cc b/content/shell/utility/shell_content_utility_client.cc index 47a78608..cb94f8e 100644 --- a/content/shell/utility/shell_content_utility_client.cc +++ b/content/shell/utility/shell_content_utility_client.cc
@@ -17,6 +17,7 @@ #include "content/public/test/test_host_resolver.h" #include "content/public/test/test_service.h" #include "content/public/test/test_service.mojom.h" +#include "content/shell/common/power_monitor_test_impl.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "mojo/public/cpp/system/buffer.h" #include "net/base/net_errors.h" @@ -118,6 +119,10 @@ auto registry = base::MakeUnique<service_manager::BinderRegistry>(); registry->AddInterface(base::Bind(&TestServiceImpl::Create), base::ThreadTaskRunnerHandle::Get()); + registry->AddInterface<mojom::PowerMonitorTest>( + base::Bind(&PowerMonitorTestImpl::MakeStrongBinding, + base::Passed(base::MakeUnique<PowerMonitorTestImpl>())), + base::ThreadTaskRunnerHandle::Get()); content::ChildThread::Get() ->GetServiceManagerConnection() ->AddConnectionFilter(
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn index 5ba9e5b..5d63802f 100644 --- a/ios/web/BUILD.gn +++ b/ios/web/BUILD.gn
@@ -629,6 +629,7 @@ "//testing/gtest", "//third_party/ocmock", "//ui/base:test_support", + "//ui/gfx:test_support", ] sources = [
diff --git a/ios/web/public/test/fakes/test_web_state.h b/ios/web/public/test/fakes/test_web_state.h index d98f99e5..90931b7 100644 --- a/ios/web/public/test/fakes/test_web_state.h +++ b/ios/web/public/test/fakes/test_web_state.h
@@ -76,6 +76,8 @@ void RemovePolicyDecider(WebStatePolicyDecider* decider) override {} WebStateInterfaceProvider* GetWebStateInterfaceProvider() override; bool HasOpener() const override; + void TakeSnapshot(const SnapshotCallback& callback, + CGSize target_size) const override; base::WeakPtr<WebState> AsWeakPtr() override; // Setters for test data.
diff --git a/ios/web/public/test/fakes/test_web_state.mm b/ios/web/public/test/fakes/test_web_state.mm index 9c268874..97b631d 100644 --- a/ios/web/public/test/fakes/test_web_state.mm +++ b/ios/web/public/test/fakes/test_web_state.mm
@@ -6,9 +6,12 @@ #include <stdint.h> +#include "base/bind.h" #include "base/callback.h" +#include "base/threading/sequenced_task_runner_handle.h" #import "ios/web/public/web_state/ui/crw_content_view.h" #include "ios/web/public/web_state/web_state_observer.h" +#include "ui/gfx/image/image.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -230,6 +233,12 @@ return false; } +void TestWebState::TakeSnapshot(const SnapshotCallback& callback, + CGSize target_size) const { + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(callback, gfx::Image())); +} + base::WeakPtr<WebState> TestWebState::AsWeakPtr() { NOTREACHED(); return base::WeakPtr<WebState>();
diff --git a/ios/web/public/web_state/web_state.h b/ios/web/public/web_state/web_state.h index 6974f523..8335bb8 100644 --- a/ios/web/public/web_state/web_state.h +++ b/ios/web/public/web_state/web_state.h
@@ -35,6 +35,10 @@ class Value; } +namespace gfx { +class Image; +} + namespace web { class BrowserState; @@ -248,6 +252,14 @@ // CreateParams::created_with_opener for more details. virtual bool HasOpener() const = 0; + // Callback used to handle snapshots. The parameter is the snapshot image. + typedef base::Callback<void(const gfx::Image&)> SnapshotCallback; + + // Takes a snapshot of this WebState with |target_size|. |callback| is + // asynchronously invoked after performing the snapshot. + virtual void TakeSnapshot(const SnapshotCallback& callback, + CGSize target_size) const = 0; + protected: friend class WebStateObserver; friend class WebStatePolicyDecider;
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h index 916f62f..fbdb248b 100644 --- a/ios/web/web_state/web_state_impl.h +++ b/ios/web/web_state/web_state_impl.h
@@ -208,6 +208,8 @@ id<CRWWebViewProxy> GetWebViewProxy() const override; WebStateInterfaceProvider* GetWebStateInterfaceProvider() override; bool HasOpener() const override; + void TakeSnapshot(const SnapshotCallback& callback, + CGSize target_size) const override; base::WeakPtr<WebState> AsWeakPtr() override; // Adds |interstitial|'s view to the web controller's content view.
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm index d973508..d918d55 100644 --- a/ios/web/web_state/web_state_impl.mm +++ b/ios/web/web_state/web_state_impl.mm
@@ -7,10 +7,12 @@ #include <stddef.h> #include <stdint.h> +#include "base/bind.h" #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/strings/sys_string_conversions.h" +#include "base/threading/sequenced_task_runner_handle.h" #import "ios/web/interstitials/web_interstitial_impl.h" #import "ios/web/navigation/crw_session_controller.h" #import "ios/web/navigation/legacy_navigation_manager_impl.h" @@ -38,6 +40,7 @@ #include "ios/web/webui/web_ui_ios_controller_factory_registry.h" #include "ios/web/webui/web_ui_ios_impl.h" #include "net/http/http_response_headers.h" +#include "ui/gfx/image/image.h" namespace web { @@ -672,6 +675,23 @@ return created_with_opener_; } +void WebStateImpl::TakeSnapshot(const SnapshotCallback& callback, + CGSize target_size) const { + UIView* view = [web_controller_ view]; + UIImage* snapshot = nil; + if (view && !CGRectIsEmpty(view.bounds)) { + CGFloat scaled_height = + view.bounds.size.height * target_size.width / view.bounds.size.width; + CGRect scaled_rect = CGRectMake(0, 0, target_size.width, scaled_height); + UIGraphicsBeginImageContextWithOptions(target_size, YES, 0); + [view drawViewHierarchyInRect:scaled_rect afterScreenUpdates:NO]; + snapshot = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + } + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(callback, gfx::Image(snapshot))); +} + void WebStateImpl::OnNavigationStarted(web::NavigationContext* context) { for (auto& observer : observers_) observer.DidStartNavigation(context);
diff --git a/ios/web/web_state/web_state_unittest.mm b/ios/web/web_state/web_state_unittest.mm index 35c165c2..76b37f8 100644 --- a/ios/web/web_state/web_state_unittest.mm +++ b/ios/web/web_state/web_state_unittest.mm
@@ -4,11 +4,16 @@ #import "ios/web/public/web_state/web_state.h" +#import <UIKit/UIKit.h> + #include "base/mac/bind_objc_block.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/ios/wait_util.h" #include "base/values.h" #import "ios/web/public/navigation_manager.h" #import "ios/web/public/test/web_test_with_web_state.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/image/image_unittest_util.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -112,4 +117,37 @@ ASSERT_FALSE(navigation_manager->GetLastCommittedItem()); } +// Tests that the snapshot method returns an image of a rendered html page. +TEST_F(WebStateTest, Snapshot) { + LoadHtml( + "<html><div style='background-color:#FF0000; width:50%; " + "height:100%;'></div></html>"); + __block bool snapshot_complete = false; + [[[UIApplication sharedApplication] keyWindow] + addSubview:web_state()->GetView()]; + // The subview is added but not immediately painted, so a small delay is + // necessary. + base::test::ios::SpinRunLoopWithMinDelay(base::TimeDelta::FromSecondsD(0.1)); + CGSize target_size = CGSizeMake(100.0f, 100.0f); + web_state()->TakeSnapshot( + base::BindBlockArc(^(const gfx::Image& snapshot) { + ASSERT_FALSE(snapshot.IsEmpty()); + EXPECT_EQ(snapshot.Width(), target_size.width); + EXPECT_EQ(snapshot.Height(), target_size.height); + // Test a pixel on the left (red) side. + gfx::test::CheckColors(gfx::test::GetPlatformImageColor( + gfx::test::ToPlatformType(snapshot), 45, 50), + SK_ColorRED); + // Test a pixel on the right (white) side. + gfx::test::CheckColors(gfx::test::GetPlatformImageColor( + gfx::test::ToPlatformType(snapshot), 55, 50), + SK_ColorWHITE); + snapshot_complete = true; + }), + target_size); + WaitForCondition(^{ + return snapshot_complete; + }); +} + } // namespace web
diff --git a/net/data/ssl/certificate_transparency/log_list.json b/net/data/ssl/certificate_transparency/log_list.json index 6ea5b39..6a29f47 100644 --- a/net/data/ssl/certificate_transparency/log_list.json +++ b/net/data/ssl/certificate_transparency/log_list.json
@@ -178,6 +178,26 @@ 8 ], "dns_api_endpoint": "startcom1.ct.googleapis.com" + }, + { + "description": "Comodo 'Sabre' CT log", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8m/SiQ8/xfiHHqtls9m7FyOMBg4JVZY9CgiixXGz0akvKD6DEL8S0ERmFe9U4ZiA0M4kbT5nmuk3I85Sk4bagA==", + "url": "sabre.ct.comodo.com/", + "maximum_merge_delay": 86400, + "operated_by": [ + 9 + ], + "dns_api_endpoint": "comodo-sabre.ct.googleapis.com" + }, + { + "description": "Comodo 'Mammoth' CT log", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7+R9dC4VFbbpuyOL+yy14ceAmEf7QGlo/EmtYU6DRzwat43f/3swtLr/L8ugFOOt1YU/RFmMjGCL17ixv66MZw==", + "url": "mammoth.ct.comodo.com/", + "maximum_merge_delay": 86400, + "operated_by": [ + 9 + ], + "dns_api_endpoint": "comodo-mammoth.ct.googleapis.com" } ], "operators": [ @@ -216,6 +236,10 @@ { "name": "StartSSL", "id": 8 + }, + { + "name": "Comodo", + "id": 9 } ] }
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index c94914c4..88a4e52 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc
@@ -312,6 +312,7 @@ backend_factory_(std::move(backend_factory)), building_backend_(false), bypass_lock_for_test_(false), + bypass_lock_after_headers_for_test_(false), fail_conditionalization_for_test_(false), mode_(NORMAL), network_layer_(std::move(network_layer)), @@ -465,6 +466,8 @@ new HttpCache::Transaction(priority, this); if (bypass_lock_for_test_) transaction->BypassLockForTest(); + if (bypass_lock_after_headers_for_test_) + transaction->BypassLockAfterHeadersForTest(); if (fail_conditionalization_for_test_) transaction->FailConditionalizationForTest();
diff --git a/net/http/http_cache.h b/net/http/http_cache.h index 91214c1..e420c72 100644 --- a/net/http/http_cache.h +++ b/net/http/http_cache.h
@@ -193,7 +193,14 @@ // Causes all transactions created after this point to simulate lock timeout // and effectively bypass the cache lock whenever there is lock contention. - void SimulateCacheLockTimeout() { bypass_lock_for_test_ = true; } + void SimulateCacheLockTimeoutForTesting() { bypass_lock_for_test_ = true; } + + // Causes all transactions created after this point to simulate lock timeout + // and effectively bypass the cache lock whenever there is lock contention + // after the transaction has completed its headers phase. + void SimulateCacheLockTimeoutAfterHeadersForTesting() { + bypass_lock_after_headers_for_test_ = true; + } // Causes all transactions created after this point to generate a failure // when attempting to conditionalize a network request. @@ -513,6 +520,7 @@ std::unique_ptr<BackendFactory> backend_factory_; bool building_backend_; bool bypass_lock_for_test_; + bool bypass_lock_after_headers_for_test_; bool fail_conditionalization_for_test_; Mode mode_;
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc index 29d040c8..6be3d87 100644 --- a/net/http/http_cache_transaction.cc +++ b/net/http/http_cache_transaction.cc
@@ -168,6 +168,7 @@ vary_mismatch_(false), couldnt_conditionalize_request_(false), bypass_lock_for_test_(false), + bypass_lock_after_headers_for_test_(false), fail_conditionalization_for_test_(false), io_buf_len_(0), read_offset_(0), @@ -853,7 +854,7 @@ rv = DoCacheReadMetadataComplete(rv); break; case STATE_HEADERS_PHASE_CANNOT_PROCEED: - rv = DoHeadersPhaseCannotProceed(); + rv = DoHeadersPhaseCannotProceed(rv); break; case STATE_FINISH_HEADERS: rv = DoFinishHeaders(rv); @@ -923,6 +924,10 @@ result); cache_pending_ = false; + // Reset mode_ that might get set in this function. This is done because this + // function can be invoked multiple times for a transaction. + mode_ = NONE; + if (!ShouldPassThrough()) { cache_key_ = cache_->GenerateCacheKey(request_); @@ -1131,42 +1136,48 @@ DCHECK(entry_lock_waiting_since_.is_null()); entry_lock_waiting_since_ = TimeTicks::Now(); int rv = cache_->AddTransactionToEntry(new_entry_, this); - if (rv == ERR_IO_PENDING) { - if (bypass_lock_for_test_) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&HttpCache::Transaction::OnAddToEntryTimeout, - weak_factory_.GetWeakPtr(), entry_lock_waiting_since_)); - } else { - int timeout_milliseconds = 20 * 1000; - if (partial_ && new_entry_->writer && - new_entry_->writer->range_requested_) { - // Quickly timeout and bypass the cache if we're a range request and - // we're blocked by the reader/writer lock. Doing so eliminates a long - // running issue, http://crbug.com/31014, where two of the same media - // resources could not be played back simultaneously due to one locking - // the cache entry until the entire video was downloaded. - // - // Bypassing the cache is not ideal, as we are now ignoring the cache - // entirely for all range requests to a resource beyond the first. This - // is however a much more succinct solution than the alternatives, which - // would require somewhat significant changes to the http caching logic. - // - // Allow some timeout slack for the entry addition to complete in case - // the writer lock is imminently released; we want to avoid skipping - // the cache if at all possible. See http://crbug.com/408765 - timeout_milliseconds = 25; - } - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::Bind(&HttpCache::Transaction::OnAddToEntryTimeout, - weak_factory_.GetWeakPtr(), entry_lock_waiting_since_), - TimeDelta::FromMilliseconds(timeout_milliseconds)); - } - } + if (rv == ERR_IO_PENDING) + AddCacheLockTimeoutHandler(new_entry_); return rv; } +void HttpCache::Transaction::AddCacheLockTimeoutHandler(ActiveEntry* entry) { + DCHECK(next_state_ == STATE_ADD_TO_ENTRY_COMPLETE || + next_state_ == STATE_FINISH_HEADERS_COMPLETE); + if ((bypass_lock_for_test_ && next_state_ == STATE_ADD_TO_ENTRY_COMPLETE) || + (bypass_lock_after_headers_for_test_ && + next_state_ == STATE_FINISH_HEADERS_COMPLETE)) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&HttpCache::Transaction::OnCacheLockTimeout, + weak_factory_.GetWeakPtr(), entry_lock_waiting_since_)); + } else { + int timeout_milliseconds = 20 * 1000; + if (partial_ && entry->writer && entry->writer->range_requested_) { + // Quickly timeout and bypass the cache if we're a range request and + // we're blocked by the reader/writer lock. Doing so eliminates a long + // running issue, http://crbug.com/31014, where two of the same media + // resources could not be played back simultaneously due to one locking + // the cache entry until the entire video was downloaded. + // + // Bypassing the cache is not ideal, as we are now ignoring the cache + // entirely for all range requests to a resource beyond the first. This + // is however a much more succinct solution than the alternatives, which + // would require somewhat significant changes to the http caching logic. + // + // Allow some timeout slack for the entry addition to complete in case + // the writer lock is imminently released; we want to avoid skipping + // the cache if at all possible. See http://crbug.com/408765 + timeout_milliseconds = 25; + } + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::Bind(&HttpCache::Transaction::OnCacheLockTimeout, + weak_factory_.GetWeakPtr(), entry_lock_waiting_since_), + TimeDelta::FromMilliseconds(timeout_milliseconds)); + } +} + int HttpCache::Transaction::DoAddToEntryComplete(int result) { TRACE_EVENT0("io", "HttpCacheTransaction::DoAddToEntryComplete"); net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY, @@ -1817,7 +1828,7 @@ return OK; } -int HttpCache::Transaction::DoHeadersPhaseCannotProceed() { +int HttpCache::Transaction::DoHeadersPhaseCannotProceed(int result) { // If its the Start state machine and it cannot proceed due to a cache // failure, restart this transaction. DCHECK(!reading_); @@ -1831,6 +1842,10 @@ entry_ = nullptr; + // Bypass the cache for timeout scenario. + if (result == ERR_CACHE_LOCK_TIMEOUT) + effective_load_flags_ |= LOAD_DISABLE_CACHE; + TransitionToState(STATE_GET_BACKEND); return OK; } @@ -1854,13 +1869,20 @@ // If the transaction needs to wait because another transaction is still // writing the response body, it will return ERR_IO_PENDING now and the // io_callback_ will be invoked when the wait is done. - return cache_->DoneWithResponseHeaders(entry_, this, partial_ != nullptr); + int rv = cache_->DoneWithResponseHeaders(entry_, this, partial_ != nullptr); + if (rv == ERR_IO_PENDING) { + DCHECK(entry_lock_waiting_since_.is_null()); + entry_lock_waiting_since_ = TimeTicks::Now(); + AddCacheLockTimeoutHandler(entry_); + } + return rv; } int HttpCache::Transaction::DoFinishHeadersComplete(int rv) { - if (rv == ERR_CACHE_RACE) { + entry_lock_waiting_since_ = TimeTicks(); + if (rv == ERR_CACHE_RACE || rv == ERR_CACHE_LOCK_TIMEOUT) { TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED); - return OK; + return rv; } TransitionToState(STATE_NONE); @@ -2805,16 +2827,20 @@ return ERR_CACHE_READ_FAILURE; } -void HttpCache::Transaction::OnAddToEntryTimeout(base::TimeTicks start_time) { +void HttpCache::Transaction::OnCacheLockTimeout(base::TimeTicks start_time) { if (entry_lock_waiting_since_ != start_time) return; - DCHECK_EQ(next_state_, STATE_ADD_TO_ENTRY_COMPLETE); + DCHECK(next_state_ == STATE_ADD_TO_ENTRY_COMPLETE || + next_state_ == STATE_FINISH_HEADERS_COMPLETE); if (!cache_) return; - cache_->RemovePendingTransaction(this); + if (next_state_ == STATE_ADD_TO_ENTRY_COMPLETE) + cache_->RemovePendingTransaction(this); + else + cache_->DoneWithEntry(entry_, this, false, partial_ != nullptr); OnIOComplete(ERR_CACHE_LOCK_TIMEOUT); }
diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h index eac49c2..dec02f1 100644 --- a/net/http/http_cache_transaction.h +++ b/net/http/http_cache_transaction.h
@@ -128,6 +128,10 @@ bypass_lock_for_test_ = true; } + void BypassLockAfterHeadersForTest() { + bypass_lock_after_headers_for_test_ = true; + } + // Generates a failure when attempting to conditionalize a network request. void FailConditionalizationForTest() { fail_conditionalization_for_test_ = true; @@ -191,14 +195,6 @@ bool initialized; }; - // A snapshot of pieces of the transaction before entering the state machine - // so that the state can be restored when restarting the state machine. - struct RestartInfo { - Mode mode = NONE; - HttpResponseInfo::CacheEntryStatus cache_entry_status = - HttpResponseInfo::CacheEntryStatus::ENTRY_UNDEFINED; - }; - enum State { STATE_UNSET, @@ -312,7 +308,7 @@ int DoPartialHeadersReceived(); int DoCacheReadMetadata(); int DoCacheReadMetadataComplete(int result); - int DoHeadersPhaseCannotProceed(); + int DoHeadersPhaseCannotProceed(int result); int DoFinishHeaders(int result); int DoFinishHeadersComplete(int result); int DoNetworkRead(); @@ -324,6 +320,10 @@ int DoCacheWriteTruncatedResponse(); int DoCacheWriteTruncatedResponseComplete(int result); + // Adds time out handling while waiting to be added to entry or after headers + // phase is complete. + void AddCacheLockTimeoutHandler(ActiveEntry* entry); + // Sets request_ and fields derived from it. void SetRequest(const NetLogWithSource& net_log); @@ -413,7 +413,7 @@ int OnCacheReadError(int result, bool restart); // Called when the cache lock timeout fires. - void OnAddToEntryTimeout(base::TimeTicks start_time); + void OnCacheLockTimeout(base::TimeTicks start_time); // Deletes the current partial cache entry (sparse), and optionally removes // the control object (partial_). @@ -505,6 +505,8 @@ bool vary_mismatch_; // The request doesn't match the stored vary data. bool couldnt_conditionalize_request_; bool bypass_lock_for_test_; // A test is exercising the cache lock. + bool bypass_lock_after_headers_for_test_; // A test is exercising the cache + // lock. bool fail_conditionalization_for_test_; // Fail ConditionalizeRequest. scoped_refptr<IOBuffer> read_buf_; int io_buf_len_;
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc index 869708f..b01427a7 100644 --- a/net/http/http_cache_unittest.cc +++ b/net/http/http_cache_unittest.cc
@@ -1576,6 +1576,92 @@ EXPECT_EQ(1, cache.disk_cache()->create_count()); } +// Tests parallel validation on range requests can be successfully restarted +// when there is a cache lock timeout. +TEST(HttpCache, RangeGET_ParallelValidationCacheLockTimeout) { + MockHttpCache cache; + + ScopedMockTransaction transaction(kRangeGET_TransactionOK); + + std::vector<std::unique_ptr<Context>> context_list; + const int kNumTransactions = 2; + + for (int i = 0; i < kNumTransactions; ++i) { + context_list.push_back(base::MakeUnique<Context>()); + } + + // Let 1st transaction complete headers phase for ranges 40-49. + std::string first_read; + MockHttpRequest request1(transaction); + { + auto& c = context_list[0]; + c->result = cache.CreateTransaction(&c->trans); + ASSERT_THAT(c->result, IsOk()); + EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState()); + + c->result = + c->trans->Start(&request1, c->callback.callback(), NetLogWithSource()); + base::RunLoop().RunUntilIdle(); + + // Start writing to the cache so that MockDiskEntry::CouldBeSparse() returns + // true. + const int kBufferSize = 5; + scoped_refptr<IOBuffer> buffer(new IOBuffer(kBufferSize)); + ReleaseBufferCompletionCallback cb(buffer.get()); + c->result = c->trans->Read(buffer.get(), kBufferSize, cb.callback()); + EXPECT_EQ(kBufferSize, cb.GetResult(c->result)); + + std::string data_read(buffer->data(), kBufferSize); + first_read = data_read; + + EXPECT_EQ(LOAD_STATE_READING_RESPONSE, c->trans->GetLoadState()); + } + + cache.SimulateCacheLockTimeoutAfterHeaders(); + + // 2nd transaction requests ranges 30-39. + transaction.request_headers = "Range: bytes = 30-39\r\n" EXTRA_HEADER; + MockHttpRequest request2(transaction); + { + auto& c = context_list[1]; + c->result = cache.CreateTransaction(&c->trans); + ASSERT_THAT(c->result, IsOk()); + EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState()); + + c->result = + c->trans->Start(&request2, c->callback.callback(), NetLogWithSource()); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState()); + } + + EXPECT_TRUE(cache.IsWriterPresent(kRangeGET_TransactionOK.url)); + EXPECT_EQ(0, cache.GetCountDoneHeadersQueue(kRangeGET_TransactionOK.url)); + + EXPECT_EQ(3, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + for (int i = 0; i < kNumTransactions; ++i) { + auto& c = context_list[i]; + if (c->result == ERR_IO_PENDING) + c->result = c->callback.WaitForResult(); + + if (i == 0) { + ReadRemainingAndVerifyTransaction(c->trans.get(), first_read, + transaction); + continue; + } + + transaction.data = "rg: 30-39 "; + ReadAndVerifyTransaction(c->trans.get(), transaction); + } + + EXPECT_EQ(3, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); +} + // Tests parallel validation on range requests with overlapping ranges. TEST(HttpCache, RangeGET_ParallelValidationOverlappingRanges) { MockHttpCache cache; @@ -1939,6 +2025,53 @@ EXPECT_EQ(1, cache.disk_cache()->create_count()); } +// Tests that a transaction which is in validated queue can timeout and start +// reading from the network without writing to the cache. +TEST(HttpCache, SimpleGET_ParallelValidationValidatedTimeout) { + MockHttpCache cache; + + MockHttpRequest request(kSimpleGET_Transaction); + + std::vector<std::unique_ptr<Context>> context_list; + const int kNumTransactions = 2; + + for (int i = 0; i < kNumTransactions; ++i) { + context_list.push_back(base::MakeUnique<Context>()); + auto& c = context_list[i]; + + if (i == 1) + cache.SimulateCacheLockTimeoutAfterHeaders(); + + c->result = cache.CreateTransaction(&c->trans); + ASSERT_THAT(c->result, IsOk()); + + c->result = + c->trans->Start(&request, c->callback.callback(), NetLogWithSource()); + } + + // Allow all requests to move from the Create queue to the active entry. + base::RunLoop().RunUntilIdle(); + + // The first request should be a writer at this point, and the subsequent + // requests should have completed validation, timed out and restarted. + + EXPECT_EQ(2, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + EXPECT_TRUE(cache.IsWriterPresent(kSimpleGET_Transaction.url)); + EXPECT_EQ(0, cache.GetCountDoneHeadersQueue(kSimpleGET_Transaction.url)); + + // Complete the rest of the transactions. + for (auto& context : context_list) { + ReadAndVerifyTransaction(context->trans.get(), kSimpleGET_Transaction); + } + + EXPECT_EQ(2, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); +} + // Tests that a transaction which is in readers can be destroyed without // any impact to other transactions. TEST(HttpCache, SimpleGET_ParallelValidationCancelReader) {
diff --git a/net/http/mock_http_cache.cc b/net/http/mock_http_cache.cc index e676122..5363d3af 100644 --- a/net/http/mock_http_cache.cc +++ b/net/http/mock_http_cache.cc
@@ -586,7 +586,11 @@ } void MockHttpCache::SimulateCacheLockTimeout() { - http_cache_.SimulateCacheLockTimeout(); + http_cache_.SimulateCacheLockTimeoutForTesting(); +} + +void MockHttpCache::SimulateCacheLockTimeoutAfterHeaders() { + http_cache_.SimulateCacheLockTimeoutAfterHeadersForTesting(); } void MockHttpCache::FailConditionalizations() {
diff --git a/net/http/mock_http_cache.h b/net/http/mock_http_cache.h index 7718f351..ca07304 100644 --- a/net/http/mock_http_cache.h +++ b/net/http/mock_http_cache.h
@@ -207,6 +207,9 @@ // Wrapper to simulate cache lock timeout for new transactions. void SimulateCacheLockTimeout(); + // Wrapper to simulate cache lock timeout for new transactions. + void SimulateCacheLockTimeoutAfterHeaders(); + // Wrapper to fail request conditionalization for new transactions. void FailConditionalizations();
diff --git a/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.cpp b/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.cpp index c0178ca..3255631 100644 --- a/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.cpp +++ b/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.cpp
@@ -359,6 +359,8 @@ : WebRemoteFrameBase(scope), frame_client_(RemoteFrameClientImpl::Create(this)), client_(client), - self_keep_alive_(this) {} + self_keep_alive_(this) { + DCHECK(client); +} } // namespace blink
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp index 435cc451..c1757a9 100644 --- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -8835,23 +8835,12 @@ class SwapMainFrameWhenTitleChangesWebFrameClient : public FrameTestHelpers::TestWebFrameClient { public: - SwapMainFrameWhenTitleChangesWebFrameClient() : remote_frame_(nullptr) {} - - ~SwapMainFrameWhenTitleChangesWebFrameClient() override { - if (remote_frame_) - remote_frame_->Close(); - } + SwapMainFrameWhenTitleChangesWebFrameClient() {} void DidReceiveTitle(const WebString&, WebTextDirection) override { - if (!Frame()->Parent()) { - remote_frame_ = - WebRemoteFrame::Create(WebTreeScopeType::kDocument, nullptr); - Frame()->Swap(remote_frame_); - } + if (!Frame()->Parent()) + Frame()->Swap(FrameTestHelpers::CreateRemote()); } - - private: - WebRemoteFrame* remote_frame_; }; } // anonymous namespace
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/log_utils.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/log_utils.py index a862bd57..7547119 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/log_utils.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/log_utils.py
@@ -28,11 +28,12 @@ _log = logging.getLogger(__name__) -def _default_handlers(stream, logging_level): +def _default_handlers(stream, logging_level, include_time): """Return a list of the default logging handlers to use. Args: stream: See the configure_logging() docstring. + include_time: See the configure_logging() docstring. """ # Create the filter. def should_log(record): @@ -46,10 +47,15 @@ # Create the handler. handler = logging.StreamHandler(stream) - if logging_level == logging.DEBUG: - formatter = logging.Formatter('%(name)s: [%(levelname)s] %(message)s') + if include_time: + prefix = '%(asctime)s - ' else: - formatter = logging.Formatter('%(message)s') + prefix = '' + + if logging_level == logging.DEBUG: + formatter = logging.Formatter(prefix + '%(name)s: [%(levelname)s] %(message)s') + else: + formatter = logging.Formatter(prefix + '%(message)s') handler.setFormatter(formatter) handler.addFilter(logging_filter) @@ -58,7 +64,7 @@ def configure_logging(logging_level=None, logger=None, stream=None, - handlers=None): + handlers=None, include_time=True): """Configure logging for standard purposes. Returns: @@ -80,6 +86,9 @@ handlers: A list of logging.Handler instances to add to the logger being configured. If this parameter is provided, then the stream parameter is not used. + include_time: Include time information at the start of every log message. + Useful for understanding how much time has passed between + subsequent log messages. """ # If the stream does not define an "encoding" data attribute, the # logging module can throw an error like the following: @@ -96,7 +105,7 @@ if stream is None: stream = sys.stderr if handlers is None: - handlers = _default_handlers(stream, logging_level) + handlers = _default_handlers(stream, logging_level, include_time) logger.setLevel(logging_level)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/log_utils_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/log_utils_unittest.py index 28ca6732..a5d471d 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/log_utils_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/log_utils_unittest.py
@@ -47,7 +47,7 @@ logger.propagate = False logging_level = self._logging_level() - self._handlers = configure_logging(logging_level=logging_level, logger=logger, stream=log_stream) + self._handlers = configure_logging(logging_level=logging_level, logger=logger, stream=log_stream, include_time=False) self._log = logger self._log_stream = log_stream
diff --git a/third_party/WebKit/public/web/WebRemoteFrame.h b/third_party/WebKit/public/web/WebRemoteFrame.h index 5c23c51..9b40f3c 100644 --- a/third_party/WebKit/public/web/WebRemoteFrame.h +++ b/third_party/WebKit/public/web/WebRemoteFrame.h
@@ -24,15 +24,19 @@ class WebRemoteFrame : public WebFrame { public: + // Factory methods for creating a WebRemoteFrame. The WebRemoteFrameClient + // argument must be non-null for all creation methods. BLINK_EXPORT static WebRemoteFrame* Create(WebTreeScopeType, WebRemoteFrameClient*, WebFrame* opener = nullptr); - // Functions for the embedder replicate the frame tree between processes. + // Specialized factory methods to allow the embedder to replicate the frame + // tree between processes. // TODO(dcheng): The embedder currently does not replicate local frames in - // insertion order, so the local child version takes a previous sibling to + // insertion order, so the local child version takes |previous_sibling| to // ensure that it is inserted into the correct location in the list of - // children. + // children. If |previous_sibling| is null, the child is inserted at the + // beginning. virtual WebLocalFrame* CreateLocalChild(WebTreeScopeType, const WebString& name, WebSandboxFlags,