diff --git a/base/base_paths_ohos.cc b/base/base_paths_ohos.cc index ec03cd53d7..fb6e3966f6 100644 --- a/base/base_paths_ohos.cc +++ b/base/base_paths_ohos.cc @@ -15,6 +15,11 @@ #include "base/notreached.h" #include "base/process/process_metrics.h" +#if defined(OS_OHOS) +#include "base/command_line.h" +#include "content/public/common/content_switches.h" +#endif + namespace base { bool PathProviderOHOS(int key, FilePath* result) { @@ -49,10 +54,20 @@ bool PathProviderOHOS(int key, FilePath* result) { // set to /data/local directory for W|X permission. *result = FilePath("/data/local"); return true; - case base::DIR_ASSETS: + case base::DIR_ASSETS: { // resource file packed to system images - *result = FilePath("/system/etc/webview"); +#if defined(OS_OHOS) + bool for_test = base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kForTest); + if (for_test) { + *result = FilePath("/data/app/el1/bundle/public/com.ohos.nweb/entry/resources/rawfile"); + } else { + *result = FilePath("/data/storage/el1/bundle/nweb/entry/resources/rawfile"); + } +#else + *result = FilePath("/data/local"); +#endif return true; + } case base::DIR_OHOS_APP_DATA: *result = FilePath("/data/local"); return true; diff --git a/build/config/ohos/BUILD.gn b/build/config/ohos/BUILD.gn index 534f0020d7..881d941065 100644 --- a/build/config/ohos/BUILD.gn +++ b/build/config/ohos/BUILD.gn @@ -131,12 +131,12 @@ config("runtime_library") { } if (use_musl) { ldflags += [ - "-L" + rebase_path("$ohos_sysroot/usr/lib/arm-linux-ohosmusl", root_build_dir), - "-L" + rebase_path("$ohos_toolchain_root/lib/arm-linux-ohosmusl/c++", root_build_dir), - "-L" + rebase_path("$ohos_toolchain_root/lib/clang/10.0.1/lib/arm-linux-ohosmusl", root_build_dir), + "-L" + rebase_path("$ohos_sysroot/usr/lib/arm-linux-ohos", root_build_dir), + "-L" + rebase_path("$ohos_toolchain_root/lib/arm-linux-ohos/c++", root_build_dir), + "-L" + rebase_path("$ohos_toolchain_root/lib/clang/10.0.1/lib/arm-linux-ohos", root_build_dir), ] - ldflags += [ "-Wl,--dynamic-linker,/system/bin/ld-musl-arm.so.1" ] - libclang_rt_file = "$ohos_toolchain_root/lib/clang/10.0.1/lib/arm-linux-ohosmusl/libclang_rt.builtins.a" + ldflags += [ "-Wl,--dynamic-linker,/lib/ld-musl-arm.so.1" ] + libclang_rt_file = "$ohos_toolchain_root/lib/clang/10.0.1/lib/arm-linux-ohos/libclang_rt.builtins.a" libs += [ rebase_path(libclang_rt_file), diff --git a/build/config/ohos/config.gni b/build/config/ohos/config.gni index c2d04f6262..6a2442e261 100644 --- a/build/config/ohos/config.gni +++ b/build/config/ohos/config.gni @@ -13,7 +13,11 @@ if (is_ohos) { } declare_args() { - build_chromium_with_ohos_src = false + build_chromium_with_ohos_src = true + } + + declare_args() { + product_name = "" } # Defines the name the ohos build gives to the current host CPU @@ -42,7 +46,7 @@ if (is_ohos) { ohos_build_root = "//../../.." if (use_musl) { ohos_toolchain_root = "$ohos_ndk_root/clang/ohos/linux-x86_64/llvm" - ohos_sysroot = "$ohos_build_root/out/ohos-arm-release/obj/third_party/musl" + ohos_sysroot = "$ohos_build_root/out/rk3568/obj/third_party/musl" } else { ohos_toolchain_root = "$ohos_ndk_root/clang/host/linux-x86/clang-r353983c" ohos_sysroot = "$ohos_ndk_root/aosp_prebuilt_libs/asdk_libs/ndk/platforms/current/arch-arm" @@ -70,9 +74,19 @@ if (is_ohos) { "$ohos_build_root/base/location/interfaces/innerkits/locator_standard/include", "$ohos_build_root/base/location/location_common/common/include", "$ohos_build_root/foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "$ohos_build_root/utils/system/safwk/native/include", + "$ohos_build_root/foundation/aafwk/standard/interfaces/innerkits/base/include", + "$ohos_build_root/foundation/aafwk/standard/interfaces/innerkits/want/include/ohos/aafwk/content", + "$ohos_build_root/foundation/appexecfwk/standard/common/log/include", + "$ohos_build_root/foundation/appexecfwk/standard/common/perf/include", + "$ohos_build_root/foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include", + "$ohos_build_root/foundation/aafwk/standard/interfaces/innerkits/app_manager/include", + "$ohos_build_root/foundation/distributedschedule/dmsfwk/services/dtbschedmgr/include", + "$ohos_build_root/third_party/jsoncpp/include", + "$ohos_build_root/third_party/json/include" ] ohos_libs_dir = [ - "$ohos_build_root/out/ohos-arm-release/packages/phone/system/lib", + "$ohos_build_root/out/rk3568/packages/phone/system/lib", ] } else { if (use_musl) { diff --git a/cef/libcef/browser/native/menu_runner_linux.cc b/cef/libcef/browser/native/menu_runner_linux.cc index 220d06c302..951deef09f 100644 --- a/cef/libcef/browser/native/menu_runner_linux.cc +++ b/cef/libcef/browser/native/menu_runner_linux.cc @@ -7,6 +7,7 @@ #include "libcef/browser/alloy/alloy_browser_host_impl.h" #include "base/compiler_specific.h" +#include "base/logging.h" #include "base/strings/string_util.h" #include "ui/gfx/geometry/point.h" @@ -16,6 +17,7 @@ bool CefMenuRunnerLinux::RunContextMenu( AlloyBrowserHostImpl* browser, CefMenuModelImpl* model, const content::ContextMenuParams& params) { +#if !defined(OS_OHOS) // will implement for ohos later menu_.reset( new views::MenuRunner(model->model(), views::MenuRunner::CONTEXT_MENU)); @@ -28,13 +30,18 @@ bool CefMenuRunnerLinux::RunContextMenu( menu_->RunMenuAt(parent_widget, nullptr, gfx::Rect(screen_point, gfx::Size()), views::MenuAnchorPosition::kTopRight, ui::MENU_SOURCE_NONE); +#else + LOG(INFO) << "context menu not implement for ohos yet!"; +#endif return true; } void CefMenuRunnerLinux::CancelContextMenu() { +#if !defined(OS_OHOS) // will implement for ohos later if (menu_) menu_->Cancel(); +#endif } bool CefMenuRunnerLinux::FormatLabel(std::u16string& label) { diff --git a/cef/libcef/browser/native/menu_runner_linux.h b/cef/libcef/browser/native/menu_runner_linux.h index 503461370d..89bb3f51b1 100644 --- a/cef/libcef/browser/native/menu_runner_linux.h +++ b/cef/libcef/browser/native/menu_runner_linux.h @@ -22,7 +22,9 @@ class CefMenuRunnerLinux : public CefMenuRunner { bool FormatLabel(std::u16string& label) override; private: +#if !defined(OS_OHOS) // will implement for ohos later std::unique_ptr menu_; +#endif }; #endif // CEF_LIBCEF_BROWSER_NATIVE_MENU_RUNNER_LINUX_H_ diff --git a/cef/libcef/browser/net_service/cookie_helper.cc b/cef/libcef/browser/net_service/cookie_helper.cc index 6b2adf40cc..0f0af971f7 100644 --- a/cef/libcef/browser/net_service/cookie_helper.cc +++ b/cef/libcef/browser/net_service/cookie_helper.cc @@ -192,7 +192,7 @@ void LoadCookies(content::BrowserContext* browser_context, if ((request.load_flags & net::LOAD_DO_NOT_SEND_COOKIES) || request.credentials_mode == network::mojom::CredentialsMode::kOmit || - request.url.IsAboutBlank()) { + request.url.IsAboutBlank() || !request.SendsCookies()) { // Continue immediately without loading cookies. std::move(done_callback).Run(0, {}); return; @@ -213,7 +213,8 @@ void SaveCookies(content::BrowserContext* browser_context, if (request.credentials_mode == network::mojom::CredentialsMode::kOmit || request.url.IsAboutBlank() || !headers || - !headers->HasHeader(net_service::kHTTPSetCookieHeaderName)) { + !headers->HasHeader(net_service::kHTTPSetCookieHeaderName) || + !request.SavesCookies()) { // Continue immediately without saving cookies. std::move(done_callback).Run(0, {}); return; diff --git a/cef/libcef/browser/osr/render_widget_host_view_osr.cc b/cef/libcef/browser/osr/render_widget_host_view_osr.cc index b8ccb16d4f..f52387c298 100644 --- a/cef/libcef/browser/osr/render_widget_host_view_osr.cc +++ b/cef/libcef/browser/osr/render_widget_host_view_osr.cc @@ -972,6 +972,7 @@ void CefRenderWidgetHostViewOSR::WasResized() { SynchronizeVisualProperties(cc::DeadlinePolicy::UseExistingDeadline(), base::nullopt); + ReleaseResizeHold(); } void CefRenderWidgetHostViewOSR::SynchronizeVisualProperties( diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc index 23317546e6..d6236627e3 100644 --- a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc +++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc @@ -324,6 +324,7 @@ void BackgroundFetchDelegateImpl::DownloadUrl( const std::string& download_guid, const std::string& method, const GURL& url, + ::network::mojom::CredentialsMode credentials_mode, const net::NetworkTrafficAnnotationTag& traffic_annotation, const net::HttpRequestHeaders& headers, bool has_request_body) { @@ -339,6 +340,7 @@ void BackgroundFetchDelegateImpl::DownloadUrl( params.request_params.method = method; params.request_params.url = url; params.request_params.request_headers = headers; + params.request_params.credentials_mode = credentials_mode; params.callback = base::BindRepeating(&BackgroundFetchDelegateImpl::OnDownloadReceived, weak_ptr_factory_.GetWeakPtr()); diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.h b/chrome/browser/background_fetch/background_fetch_delegate_impl.h index 16629fb82d..dfffa83b42 100644 --- a/chrome/browser/background_fetch/background_fetch_delegate_impl.h +++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.h @@ -97,6 +97,7 @@ class BackgroundFetchDelegateImpl const std::string& guid, const std::string& method, const GURL& url, + ::network::mojom::CredentialsMode credentials_mode, const net::NetworkTrafficAnnotationTag& traffic_annotation, const net::HttpRequestHeaders& headers, bool has_request_body) override; diff --git a/chrome/browser/chrome_content_browser_client_receiver_bindings.cc b/chrome/browser/chrome_content_browser_client_receiver_bindings.cc index 005625bb1c..127f6fb2c9 100644 --- a/chrome/browser/chrome_content_browser_client_receiver_bindings.cc +++ b/chrome/browser/chrome_content_browser_client_receiver_bindings.cc @@ -205,11 +205,9 @@ void ChromeContentBrowserClient::ExposeInterfacesToRenderer( ui_task_runner); #endif #if defined(OS_ANDROID) - Profile* profile = - Profile::FromBrowserContext(render_process_host->GetBrowserContext()); registry->AddInterface( base::BindRepeating(&android::AvailableOfflineContentProvider::Create, - profile), + render_process_host->GetID()), content::GetUIThreadTaskRunner({})); #endif diff --git a/chrome/browser/chrome_security_exploit_browsertest.cc b/chrome/browser/chrome_security_exploit_browsertest.cc index fd8ec071c4..2ffc8f4b29 100644 --- a/chrome/browser/chrome_security_exploit_browsertest.cc +++ b/chrome/browser/chrome_security_exploit_browsertest.cc @@ -482,8 +482,8 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityExploitBrowserTestMojoBlobURLs, // If the process is killed, this test passes. EXPECT_EQ( - "Received bad user message: Non committable URL passed to " - "BlobURLStore::Register", + "Received bad user message: " + "URL with invalid origin passed to BlobURLStore::Register", crash_observer.Wait()); } @@ -518,7 +518,7 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityExploitBrowserTestMojoBlobURLs, // If the process is killed, this test passes. EXPECT_EQ( - "Received bad user message: Non committable URL passed to " - "BlobURLStore::Register", + "Received bad user message: " + "URL with invalid origin passed to BlobURLStore::Register", crash_observer.Wait()); } diff --git a/chrome/browser/download/android/available_offline_content_provider.cc b/chrome/browser/download/android/available_offline_content_provider.cc index 355efc81c2..680d00ee6f 100644 --- a/chrome/browser/download/android/available_offline_content_provider.cc +++ b/chrome/browser/download/android/available_offline_content_provider.cc @@ -25,6 +25,7 @@ #include "components/offline_items_collection/core/offline_item_state.h" #include "components/offline_pages/core/offline_page_feature.h" #include "components/prefs/pref_service.h" +#include "content/public/browser/render_process_host.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "ui/base/l10n/time_format.h" @@ -217,14 +218,17 @@ chrome::mojom::AvailableOfflineContentPtr CreateAvailableOfflineContent( } // namespace AvailableOfflineContentProvider::AvailableOfflineContentProvider( - Profile* profile) - : profile_(profile) {} + int render_process_host_id) + : render_process_host_id_(render_process_host_id) {} AvailableOfflineContentProvider::~AvailableOfflineContentProvider() = default; void AvailableOfflineContentProvider::List(ListCallback callback) { + Profile* profile = GetProfile(); + if (!profile) + return; offline_items_collection::OfflineContentAggregator* aggregator = - OfflineContentAggregatorFactory::GetForKey(profile_->GetProfileKey()); + OfflineContentAggregatorFactory::GetForKey(profile->GetProfileKey()); aggregator->GetAllItems( base::BindOnce(&AvailableOfflineContentProvider::ListFinalize, weak_ptr_factory_.GetWeakPtr(), std::move(callback), @@ -236,12 +240,15 @@ void AvailableOfflineContentProvider::List(ListCallback callback) { void AvailableOfflineContentProvider::LaunchItem( const std::string& item_id, const std::string& name_space) { + Profile* profile = GetProfile(); + if (!profile) + return; offline_items_collection::OfflineContentAggregator* aggregator = - OfflineContentAggregatorFactory::GetForKey(profile_->GetProfileKey()); + OfflineContentAggregatorFactory::GetForKey(profile->GetProfileKey()); offline_items_collection::OpenParams open_params( offline_items_collection::LaunchLocation::NET_ERROR_SUGGESTION); - open_params.open_in_incognito = profile_->IsOffTheRecord(); + open_params.open_in_incognito = profile->IsOffTheRecord(); aggregator->OpenItem( open_params, offline_items_collection::ContentId(name_space, item_id)); } @@ -254,20 +261,21 @@ void AvailableOfflineContentProvider::LaunchDownloadsPage( } void AvailableOfflineContentProvider::ListVisibilityChanged(bool is_visible) { - profile_->GetPrefs()->SetBoolean(feed::prefs::kArticlesListVisible, - is_visible); + Profile* profile = GetProfile(); + if (!profile) + return; + profile->GetPrefs()->SetBoolean(feed::prefs::kArticlesListVisible, + is_visible); } // static void AvailableOfflineContentProvider::Create( - Profile* profile, + int render_process_host_id, mojo::PendingReceiver receiver) { - // Self owned receiveres remain as long as the pipe is error free. The - // renderer is on the other side of the pipe, and the profile outlives the - // RenderProcessHost, so the profile will outlive the Mojo pipe. + // Self owned receiveres remain as long as the pipe is error free. mojo::MakeSelfOwnedReceiver( - std::make_unique(profile), + std::make_unique(render_process_host_id), std::move(receiver)); } @@ -276,6 +284,10 @@ void AvailableOfflineContentProvider::ListFinalize( AvailableOfflineContentProvider::ListCallback callback, offline_items_collection::OfflineContentAggregator* aggregator, const std::vector& all_items) { + Profile* profile = GetProfile(); + if (!profile) + return; + std::vector selected(kMinInterestingItemCount); const auto end = std::partial_sort_copy(all_items.begin(), all_items.end(), selected.begin(), selected.end(), @@ -296,7 +308,7 @@ void AvailableOfflineContentProvider::ListFinalize( selected_ids.push_back(item.id); bool list_visible_by_prefs = - profile_->GetPrefs()->GetBoolean(feed::prefs::kArticlesListVisible); + profile->GetPrefs()->GetBoolean(feed::prefs::kArticlesListVisible); auto complete = [](AvailableOfflineContentProvider::ListCallback callback, @@ -318,4 +330,12 @@ void AvailableOfflineContentProvider::ListFinalize( list_visible_by_prefs)); } +Profile* AvailableOfflineContentProvider::GetProfile() { + content::RenderProcessHost* render_process_host = + content::RenderProcessHost::FromID(render_process_host_id_); + if (!render_process_host) + return nullptr; + return Profile::FromBrowserContext(render_process_host->GetBrowserContext()); +} + } // namespace android diff --git a/chrome/browser/download/android/available_offline_content_provider.h b/chrome/browser/download/android/available_offline_content_provider.h index c4024a463a..0888c0c487 100644 --- a/chrome/browser/download/android/available_offline_content_provider.h +++ b/chrome/browser/download/android/available_offline_content_provider.h @@ -27,7 +27,7 @@ class AvailableOfflineContentProvider : public chrome::mojom::AvailableOfflineContentProvider { public: // Public for testing. - explicit AvailableOfflineContentProvider(Profile* profile); + explicit AvailableOfflineContentProvider(int render_process_host_id); ~AvailableOfflineContentProvider() override; // chrome::mojom::AvailableOfflineContentProvider methods. @@ -38,7 +38,7 @@ class AvailableOfflineContentProvider void ListVisibilityChanged(bool is_visible) override; static void Create( - Profile* profile, + int render_process_host_id, mojo::PendingReceiver receiver); @@ -48,7 +48,9 @@ class AvailableOfflineContentProvider offline_items_collection::OfflineContentAggregator* aggregator, const std::vector& all_items); - Profile* profile_; + Profile* GetProfile(); + + const int render_process_host_id_; base::WeakPtrFactory weak_ptr_factory_{this}; diff --git a/chrome/browser/download/android/available_offline_content_provider_unittest.cc b/chrome/browser/download/android/available_offline_content_provider_unittest.cc index 234760aff0..bce18ff21b 100644 --- a/chrome/browser/download/android/available_offline_content_provider_unittest.cc +++ b/chrome/browser/download/android/available_offline_content_provider_unittest.cc @@ -15,6 +15,7 @@ #include "chrome/browser/offline_items_collection/offline_content_aggregator_factory.h" #include "chrome/browser/profiles/profile_key.h" #include "chrome/common/available_offline_content.mojom-test-utils.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/testing_profile.h" #include "components/feed/core/shared_prefs/pref_names.h" #include "components/offline_items_collection/core/offline_content_aggregator.h" @@ -124,13 +125,27 @@ OfflineItemVisuals TestThumbnail() { return visuals; } -class AvailableOfflineContentTest : public testing::Test { +class AvailableOfflineContentTest : public ChromeRenderViewHostTestHarness { protected: void SetUp() override { + ChromeRenderViewHostTestHarness::SetUp(); + + content_provider_ = std::make_unique< + offline_items_collection::MockOfflineContentProvider>(); + provider_ = std::make_unique( + main_rfh()->GetProcess()->GetID()); + aggregator_ = - OfflineContentAggregatorFactory::GetForKey(profile_.GetProfileKey()); - aggregator_->RegisterProvider(kProviderNamespace, &content_provider_); - content_provider_.SetVisuals({}); + OfflineContentAggregatorFactory::GetForKey(profile()->GetProfileKey()); + aggregator_->RegisterProvider(kProviderNamespace, content_provider_.get()); + content_provider_->SetVisuals({}); + } + + void TearDown() override { + provider_.release(); + content_provider_.release(); + + ChromeRenderViewHostTestHarness::TearDown(); } std::tuple> @@ -138,18 +153,17 @@ class AvailableOfflineContentTest : public testing::Test { bool list_visible_by_prefs; std::vector suggestions; chrome::mojom::AvailableOfflineContentProviderAsyncWaiter waiter( - &provider_); + provider_.get()); waiter.List(&list_visible_by_prefs, &suggestions); return std::make_tuple(list_visible_by_prefs, std::move(suggestions)); } - content::BrowserTaskEnvironment task_environment_; - TestingProfile profile_; std::unique_ptr scoped_feature_list_ = std::make_unique(); OfflineContentAggregator* aggregator_; - offline_items_collection::MockOfflineContentProvider content_provider_; - AvailableOfflineContentProvider provider_{&profile_}; + std::unique_ptr + content_provider_; + std::unique_ptr provider_; }; TEST_F(AvailableOfflineContentTest, NoContent) { @@ -164,10 +178,10 @@ TEST_F(AvailableOfflineContentTest, NoContent) { TEST_F(AvailableOfflineContentTest, TooFewInterestingItems) { // Adds items so that we're one-ff of reaching the minimum required count so // that any extra item considered interesting would effect the results. - content_provider_.SetItems({UninterestingImageItem(), OfflinePageItem(), - SuggestedOfflinePageItem(), VideoItem(), - TransientItem(), OffTheRecordItem(), - IncompleteItem(), DangerousItem()}); + content_provider_->SetItems({UninterestingImageItem(), OfflinePageItem(), + SuggestedOfflinePageItem(), VideoItem(), + TransientItem(), OffTheRecordItem(), + IncompleteItem(), DangerousItem()}); // Call List(). bool list_visible_by_prefs; @@ -182,11 +196,11 @@ TEST_F(AvailableOfflineContentTest, TooFewInterestingItems) { TEST_F(AvailableOfflineContentTest, FourInterestingItems) { // We need at least 4 interesting items for anything to show up at all. - content_provider_.SetItems({UninterestingImageItem(), VideoItem(), - SuggestedOfflinePageItem(), AudioItem(), - OfflinePageItem()}); + content_provider_->SetItems({UninterestingImageItem(), VideoItem(), + SuggestedOfflinePageItem(), AudioItem(), + OfflinePageItem()}); - content_provider_.SetVisuals( + content_provider_->SetVisuals( {{SuggestedOfflinePageItem().id, TestThumbnail()}}); // Call List(). @@ -226,14 +240,14 @@ TEST_F(AvailableOfflineContentTest, FourInterestingItems) { TEST_F(AvailableOfflineContentTest, ListVisibilityChanges) { // We need at least 4 interesting items for anything to show up at all. - content_provider_.SetItems({UninterestingImageItem(), VideoItem(), - SuggestedOfflinePageItem(), AudioItem(), - OfflinePageItem()}); + content_provider_->SetItems({UninterestingImageItem(), VideoItem(), + SuggestedOfflinePageItem(), AudioItem(), + OfflinePageItem()}); - content_provider_.SetVisuals( + content_provider_->SetVisuals( {{SuggestedOfflinePageItem().id, TestThumbnail()}}); // Set pref to hide the list. - profile_.GetPrefs()->SetBoolean(feed::prefs::kArticlesListVisible, false); + profile()->GetPrefs()->SetBoolean(feed::prefs::kArticlesListVisible, false); // Call List(). bool list_visible_by_prefs; @@ -245,10 +259,10 @@ TEST_F(AvailableOfflineContentTest, ListVisibilityChanges) { EXPECT_FALSE(list_visible_by_prefs); // Simulate visibility changed by the user to "shown". - provider_.ListVisibilityChanged(true); + provider_->ListVisibilityChanged(true); EXPECT_TRUE( - profile_.GetPrefs()->GetBoolean(feed::prefs::kArticlesListVisible)); + profile()->GetPrefs()->GetBoolean(feed::prefs::kArticlesListVisible)); // Call List() again and check list is not visible. std::tie(list_visible_by_prefs, suggestions) = ListAndWait(); diff --git a/chrome/browser/download/save_page_browsertest.cc b/chrome/browser/download/save_page_browsertest.cc index b5e3997002..ef21c3d4fc 100644 --- a/chrome/browser/download/save_page_browsertest.cc +++ b/chrome/browser/download/save_page_browsertest.cc @@ -49,6 +49,7 @@ #include "components/prefs/pref_member.h" #include "components/prefs/pref_service.h" #include "components/security_state/core/security_state.h" +#include "components/services/quarantine/test_support.h" #include "content/public/browser/download_manager.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" @@ -433,6 +434,10 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveFileURL) { EXPECT_TRUE(base::PathExists(full_file_name)); EXPECT_FALSE(base::PathExists(dir)); EXPECT_TRUE(base::ContentsEqual(GetTestDirFile("text.txt"), full_file_name)); +#if defined(OS_WIN) + // Local file URL will not be quarantined. + EXPECT_FALSE(quarantine::IsFileQuarantined(full_file_name, GURL(), GURL())); +#endif } IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, @@ -936,6 +941,25 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveUnauthorizedResource) { EXPECT_FALSE(base::PathExists(dir.AppendASCII("should-not-save.jpg"))); } +#if defined(OS_WIN) +// Save a file and confirm that the file is correctly quarantined. +IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveURLQuarantine) { + GURL url = embedded_test_server()->GetURL("/save_page/text.txt"); + ui_test_utils::NavigateToURL(browser(), url); + + base::FilePath full_file_name, dir; + SaveCurrentTab(url, content::SAVE_PAGE_TYPE_AS_ONLY_HTML, "test", 1, &dir, + &full_file_name); + ASSERT_FALSE(HasFailure()); + + base::ScopedAllowBlockingForTesting allow_blocking; + EXPECT_TRUE(base::PathExists(full_file_name)); + EXPECT_FALSE(base::PathExists(dir)); + EXPECT_TRUE(base::ContentsEqual(GetTestDirFile("text.txt"), full_file_name)); + EXPECT_TRUE(quarantine::IsFileQuarantined(full_file_name, url, GURL())); +} +#endif + // Test suite that allows testing --site-per-process against cross-site frames. // See http://dev.chromium.org/developers/design-documents/site-isolation. class SavePageSitePerProcessBrowserTest : public SavePageBrowserTest { diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc index 4caf88b061..496ae84131 100644 --- a/chrome/browser/extensions/extension_messages_apitest.cc +++ b/chrome/browser/extensions/extension_messages_apitest.cc @@ -1164,6 +1164,93 @@ IN_PROC_BROWSER_TEST_F(MessagingApiTest, MessagingUserGesture) { "});", receiver->id().c_str()))); } +IN_PROC_BROWSER_TEST_F(MessagingApiTest, + RestrictedActivationTriggerBetweenExtensions) { + base::CommandLine::ForCurrentProcess()->AppendSwitch( + embedder_support::kDisablePopupBlocking); + + const char kManifest[] = R"({ + "name": "activation_state_thru_send_reply", + "version": "1.0", + "background": { + "scripts": ["background.js"] + }, + "manifest_version": 2 + })"; + + // The receiver replies back with its transient activation state after a + // delay. + TestExtensionDir receiver_dir; + receiver_dir.WriteManifest(kManifest); + receiver_dir.WriteFile(FILE_PATH_LITERAL("background.js"), + R"( + chrome.runtime.onMessageExternal.addListener( + (msg, sender, callback) => { + setTimeout(() => + callback({active:navigator.userActivation.isActive}), 200); + }); + )"); + const Extension* receiver = LoadExtension(receiver_dir.UnpackedPath()); + ASSERT_TRUE(receiver); + + TestExtensionDir sender_dir; + sender_dir.WriteManifest(kManifest); + sender_dir.WriteFile(FILE_PATH_LITERAL("background.js"), ""); + const Extension* sender = LoadExtension(sender_dir.UnpackedPath()); + ASSERT_TRUE(sender); + + const char send_script_template[] = R"( + log = []; + log.push('sender-initial:' + navigator.userActivation.isActive); + chrome.runtime.sendMessage('%s', {}, response => { + log.push('receiver:' + response.active); + log.push('sender-received:' + navigator.userActivation.isActive); + window.domAutomationController.send(log.toString()); + }); + log.push('sender-sent:' + navigator.userActivation.isActive); + )"; + std::string send_script = + base::StringPrintf(send_script_template, receiver->id().c_str()); + + // Without any user activation, neither the sender nor the receiver should be + // in active state at any moment. + EXPECT_EQ( + "sender-initial:false,sender-sent:false,receiver:false," + "sender-received:false", + ExecuteScriptInBackgroundPage( + sender->id(), send_script, + extensions::browsertest_util::ScriptUserActivation::kDontActivate)); + + // With user activation before sending, the sender should be in active state + // all the time, and the receiver should be in active state. + // + // TODO(crbug.com/957633): The receiver should be inactive here. + EXPECT_EQ( + "sender-initial:true,sender-sent:true,receiver:true," + "sender-received:true", + ExecuteScriptInBackgroundPage( + sender->id(), send_script, + extensions::browsertest_util::ScriptUserActivation::kActivate)); + + std::string send_and_consume_script = send_script + R"( + setTimeout(() => { + open().close(); + log.push('sender-consumed:' + navigator.userActivation.isActive); + }, 0); + )"; + + // With user activation consumed right after sending, the sender should be in + // active state until consumption, and the receiver should be in active state. + // + // TODO(crbug.com/957633): The receiver should be inactive here. + EXPECT_EQ( + "sender-initial:true,sender-sent:true,sender-consumed:false," + "receiver:true,sender-received:false", + ExecuteScriptInBackgroundPage( + sender->id(), send_and_consume_script, + extensions::browsertest_util::ScriptUserActivation::kActivate)); +} + // Tests that a hosted app on a connectable site doesn't interfere with the // connectability of that site. IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, HostedAppOnWebsite) { diff --git a/chrome/browser/external_protocol/external_protocol_handler.cc b/chrome/browser/external_protocol/external_protocol_handler.cc index 94f799b5b4..fc54f9af7a 100644 --- a/chrome/browser/external_protocol/external_protocol_handler.cc +++ b/chrome/browser/external_protocol/external_protocol_handler.cc @@ -64,6 +64,7 @@ constexpr const char* kDeniedSchemes[] = { "hcp", "ie.http", "javascript", + "mk", "ms-help", "nntp", "res", diff --git a/chrome/browser/external_protocol/external_protocol_handler_unittest.cc b/chrome/browser/external_protocol/external_protocol_handler_unittest.cc index 08d35a1844..1aa83951b3 100644 --- a/chrome/browser/external_protocol/external_protocol_handler_unittest.cc +++ b/chrome/browser/external_protocol/external_protocol_handler_unittest.cc @@ -347,6 +347,10 @@ TEST_F(ExternalProtocolHandlerTest, TestGetBlockStateDefaultBlock) { block_state = ExternalProtocolHandler::GetBlockState("ie.http", nullptr, profile_.get()); EXPECT_EQ(ExternalProtocolHandler::BLOCK, block_state); + EXPECT_EQ("mk", GURL("mk:@FooBar:ie.http:res://foo.bar/baz").scheme()); + block_state = + ExternalProtocolHandler::GetBlockState("mk", nullptr, profile_.get()); + EXPECT_EQ(ExternalProtocolHandler::BLOCK, block_state); EXPECT_TRUE( profile_->GetPrefs() ->GetDictionary(prefs::kProtocolHandlerPerOriginAllowedProtocols) diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc index efcc2976aa..c012c830d9 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc @@ -2298,7 +2298,9 @@ void RenderViewContextMenu::ExecuteCommand(int id, int event_flags) { break; case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD: - OpenURLWithExtraHeaders(params_.link_url, GURL(), + // Pass along the |referring_url| so we can show it in browser UI. Note + // that this won't and shouldn't be sent via the referrer header. + OpenURLWithExtraHeaders(params_.link_url, GetDocumentURL(params_), WindowOpenDisposition::OFF_THE_RECORD, ui::PAGE_TRANSITION_LINK, "" /* extra_headers */, true /* started_from_context_menu */); diff --git a/chrome/browser/signin/force_signin_verifier.cc b/chrome/browser/signin/force_signin_verifier.cc index 98671562c4..721e34340c 100644 --- a/chrome/browser/signin/force_signin_verifier.cc +++ b/chrome/browser/signin/force_signin_verifier.cc @@ -64,7 +64,7 @@ void ForceSigninVerifier::OnAccessTokenFetchComplete( backoff_request_timer_.Start( FROM_HERE, backoff_entry_.GetTimeUntilRelease(), base::BindOnce(&ForceSigninVerifier::SendRequest, - base::Unretained(this))); + weak_factory_.GetWeakPtr())); access_token_fetcher_.reset(); } return; @@ -105,7 +105,7 @@ void ForceSigninVerifier::SendRequest() { if (content::GetNetworkConnectionTracker()->GetConnectionType( &type, base::BindOnce(&ForceSigninVerifier::SendRequestIfNetworkAvailable, - base::Unretained(this)))) { + weak_factory_.GetWeakPtr()))) { SendRequestIfNetworkAvailable(type); } } @@ -119,13 +119,11 @@ void ForceSigninVerifier::SendRequestIfNetworkAvailable( signin::ScopeSet oauth2_scopes; oauth2_scopes.insert(GaiaConstants::kChromeSyncOAuth2Scope); - // It is safe to use Unretained(this) here given that the callback - // will not be invoked if this object is deleted. access_token_fetcher_ = std::make_unique( "force_signin_verifier", identity_manager_, oauth2_scopes, base::BindOnce(&ForceSigninVerifier::OnAccessTokenFetchComplete, - base::Unretained(this)), + weak_factory_.GetWeakPtr()), signin::PrimaryAccountAccessTokenFetcher::Mode::kImmediate); } diff --git a/chrome/browser/signin/force_signin_verifier.h b/chrome/browser/signin/force_signin_verifier.h index 6afd376297..70331bf90e 100644 --- a/chrome/browser/signin/force_signin_verifier.h +++ b/chrome/browser/signin/force_signin_verifier.h @@ -76,6 +76,8 @@ class ForceSigninVerifier base::TimeTicks creation_time_; signin::IdentityManager* identity_manager_ = nullptr; + + base::WeakPtrFactory weak_factory_{this}; DISALLOW_COPY_AND_ASSIGN(ForceSigninVerifier); }; diff --git a/chrome/browser/signin/force_signin_verifier_unittest.cc b/chrome/browser/signin/force_signin_verifier_unittest.cc index 3528d687d5..6771b0b850 100644 --- a/chrome/browser/signin/force_signin_verifier_unittest.cc +++ b/chrome/browser/signin/force_signin_verifier_unittest.cc @@ -376,3 +376,28 @@ TEST(ForceSigninVerifierTest, ChangeNetworkFromWIFITo4GWithFinishedRequest) { // No more request because it's verfied already. EXPECT_EQ(nullptr, verifier.access_token_fetcher()); } + +// Regression test for https://crbug.com/1259864 +TEST(ForceSigninVerifierTest, DeleteWithPendingRequestShouldNotCrash) { + base::test::TaskEnvironment scoped_task_env; + signin::IdentityTestEnvironment identity_test_env; + const AccountInfo account_info = + identity_test_env.MakePrimaryAccountAvailable( + "email@test.com", signin::ConsentLevel::kSync); + + ConfigureNetworkConnectionTracker(NetworkConnectionType::Undecided, + NetworkResponseType::Asynchronous); + + { + ForceSigninVerifierWithAccessToInternalsForTesting verifier( + identity_test_env.identity_manager()); + + // There is no network type at first. + ASSERT_EQ(nullptr, verifier.access_token_fetcher()); + + // Delete the verifier while the request is pending. + } + + // Waiting for the network type returns, this should not crash. + SpinCurrentSequenceTaskRunner(); +} diff --git a/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.cc b/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.cc index 441d30c8d0..659af40f83 100644 --- a/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.cc +++ b/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.cc @@ -45,7 +45,7 @@ RecentlyUsedFoldersComboModel::Item::Item(const BookmarkNode* node, type(type) { } -RecentlyUsedFoldersComboModel::Item::~Item() {} +RecentlyUsedFoldersComboModel::Item::~Item() = default; bool RecentlyUsedFoldersComboModel::Item::operator==(const Item& item) const { return item.node == node && item.type == type; @@ -54,8 +54,7 @@ bool RecentlyUsedFoldersComboModel::Item::operator==(const Item& item) const { RecentlyUsedFoldersComboModel::RecentlyUsedFoldersComboModel( BookmarkModel* model, const BookmarkNode* node) - : bookmark_model_(model), - node_parent_index_(0) { + : bookmark_model_(model), parent_node_(node->parent()) { bookmark_model_->AddObserver(this); // Use + 2 to account for bookmark bar and other node. std::vector nodes = @@ -87,10 +86,6 @@ RecentlyUsedFoldersComboModel::RecentlyUsedFoldersComboModel( items_.push_back(Item(model->mobile_node(), Item::TYPE_NODE)); items_.push_back(Item(NULL, Item::TYPE_SEPARATOR)); items_.push_back(Item(NULL, Item::TYPE_CHOOSE_ANOTHER_FOLDER)); - - auto it = std::find(items_.begin(), items_.end(), - Item(node->parent(), Item::TYPE_NODE)); - node_parent_index_ = static_cast(it - items_.begin()); } RecentlyUsedFoldersComboModel::~RecentlyUsedFoldersComboModel() { @@ -122,7 +117,16 @@ bool RecentlyUsedFoldersComboModel::IsItemSeparatorAt(int index) const { } int RecentlyUsedFoldersComboModel::GetDefaultIndex() const { - return node_parent_index_; + // TODO(pbos): Ideally we shouldn't have to handle `parent_node_` removal + // here, the dialog should instead close immediately (and destroy `this`). + // If that can be resolved, this should DCHECK that it != items_.end() and + // a DCHECK should be added in the BookmarkModel observer methods to ensure + // that we don't remove `parent_node_`. + // TODO(pbos): Look at returning -1 here if there's no default index. Right + // now a lot of code in Combobox assumes an index within `items_` bounds. + auto it = std::find(items_.begin(), items_.end(), + Item(parent_node_, Item::TYPE_NODE)); + return it == items_.end() ? 0 : static_cast(it - items_.begin()); } void RecentlyUsedFoldersComboModel::AddObserver( @@ -222,6 +226,7 @@ void RecentlyUsedFoldersComboModel::BookmarkAllUserNodesRemoved( void RecentlyUsedFoldersComboModel::MaybeChangeParent( const BookmarkNode* node, int selected_index) { + DCHECK_LT(selected_index, static_cast(items_.size())); if (items_[selected_index].type != Item::TYPE_NODE) return; @@ -234,7 +239,7 @@ void RecentlyUsedFoldersComboModel::MaybeChangeParent( const BookmarkNode* RecentlyUsedFoldersComboModel::GetNodeAt(int index) { if (index < 0 || index >= static_cast(items_.size())) - return NULL; + return nullptr; return items_[index].node; } diff --git a/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h b/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h index 6db8245e9d..1b6e8d0b9c 100644 --- a/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h +++ b/chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h @@ -83,10 +83,9 @@ class RecentlyUsedFoldersComboModel : public ui::ComboboxModel, struct Item; std::vector items_; - bookmarks::BookmarkModel* bookmark_model_; + bookmarks::BookmarkModel* const bookmark_model_; - // The index of the original parent folder. - int node_parent_index_; + const bookmarks::BookmarkNode* const parent_node_; base::ObserverList observers_; diff --git a/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc b/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc index 4e8bc2e2ab..18a9372661 100644 --- a/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc +++ b/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc @@ -14,11 +14,15 @@ #include "chrome/browser/ui/test/test_browser_dialog.h" #include "chrome/browser/ui/views/external_protocol_dialog.h" #include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test.h" +#include "net/dns/mock_host_resolver.h" +#include "net/test/embedded_test_server/http_request.h" +#include "net/test/embedded_test_server/http_response.h" #include "ui/views/controls/button/checkbox.h" #include "url/gurl.h" @@ -41,6 +45,33 @@ class ExternalProtocolDialogTestApi { } // namespace test +namespace { +constexpr char kInitiatingOrigin[] = "a.test"; +constexpr char kRedirectingOrigin[] = "b.test"; + +class FakeDefaultProtocolClientWorker + : public shell_integration::DefaultProtocolClientWorker { + public: + explicit FakeDefaultProtocolClientWorker(const std::string& protocol) + : DefaultProtocolClientWorker(protocol) {} + FakeDefaultProtocolClientWorker(const FakeDefaultProtocolClientWorker&) = + delete; + FakeDefaultProtocolClientWorker& operator=( + const FakeDefaultProtocolClientWorker&) = delete; + + private: + ~FakeDefaultProtocolClientWorker() override = default; + shell_integration::DefaultWebClientState CheckIsDefaultImpl() override { + return shell_integration::DefaultWebClientState::NOT_DEFAULT; + } + + void SetAsDefaultImpl(base::OnceClosure on_finished_callback) override { + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, std::move(on_finished_callback)); + } +}; +} // namespace + class ExternalProtocolDialogBrowserTest : public DialogBrowserTest, public ExternalProtocolHandler::Delegate { @@ -72,11 +103,11 @@ class ExternalProtocolDialogBrowserTest // ExternalProtocolHander::Delegate: scoped_refptr CreateShellWorker(const std::string& protocol) override { - return nullptr; + return base::MakeRefCounted(protocol); } ExternalProtocolHandler::BlockState GetBlockState(const std::string& scheme, Profile* profile) override { - return ExternalProtocolHandler::DONT_BLOCK; + return ExternalProtocolHandler::UNKNOWN; } void BlockRequest() override {} void RunExternalProtocolDialog( @@ -84,7 +115,10 @@ class ExternalProtocolDialogBrowserTest content::WebContents* web_contents, ui::PageTransition page_transition, bool has_user_gesture, - const base::Optional& initiating_origin) override {} + const base::Optional& initiating_origin) override { + url_did_launch_ = true; + launch_url_ = initiating_origin->host(); + } void LaunchUrlWithoutSecurityCheck( const GURL& url, content::WebContents* web_contents) override { @@ -99,6 +133,12 @@ class ExternalProtocolDialogBrowserTest blocked_state_ = state; } + void SetUpOnMainThread() override { + DialogBrowserTest::SetUpOnMainThread(); + host_resolver()->AddRule(kInitiatingOrigin, "127.0.0.1"); + host_resolver()->AddRule(kRedirectingOrigin, "127.0.0.1"); + } + base::HistogramTester histogram_tester_; protected: @@ -107,6 +147,7 @@ class ExternalProtocolDialogBrowserTest url::Origin blocked_origin_; BlockState blocked_state_ = BlockState::UNKNOWN; bool url_did_launch_ = false; + std::string launch_url_; private: DISALLOW_COPY_AND_ASSIGN(ExternalProtocolDialogBrowserTest); @@ -232,3 +273,21 @@ IN_PROC_BROWSER_TEST_F(ExternalProtocolDialogBrowserTest, TestFocus) { const views::View* focused_view = focus_manager->GetFocusedView(); EXPECT_TRUE(focused_view); } + +IN_PROC_BROWSER_TEST_F(ExternalProtocolDialogBrowserTest, OriginNameTest) { + ASSERT_TRUE(embedded_test_server()->Start()); + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + EXPECT_TRUE(ui_test_utils::NavigateToURL( + browser(), embedded_test_server()->GetURL("a.test", "/empty.html"))); + EXPECT_TRUE(content::ExecJs( + web_contents, + content::JsReplace("location.href = $1", + embedded_test_server()->GetURL( + "b.test", "/server-redirect?ms-calc:")))); + content::WaitForLoadStop(web_contents); + EXPECT_TRUE(url_did_launch_); + // The url should be the url of the last redirecting server and not of the + // request initiator + EXPECT_EQ(launch_url_, "b.test"); +} diff --git a/chrome/browser/ui/views/frame/webui_tab_strip_container_view.cc b/chrome/browser/ui/views/frame/webui_tab_strip_container_view.cc index f22a3ce31b..fcdce3368a 100644 --- a/chrome/browser/ui/views/frame/webui_tab_strip_container_view.cc +++ b/chrome/browser/ui/views/frame/webui_tab_strip_container_view.cc @@ -807,8 +807,15 @@ void WebUITabStripContainerView::ShowEditDialogForGroupAtPoint( tab_groups::TabGroupId group) { ConvertPointToScreen(this, &point); rect.set_origin(point); - TabGroupEditorBubbleView::Show(browser_view_->browser(), group, nullptr, rect, - this); + editor_bubble_widget_ = TabGroupEditorBubbleView::Show( + browser_view_->browser(), group, nullptr, rect, this); + scoped_widget_observation_.Observe(editor_bubble_widget_); +} + +void WebUITabStripContainerView::HideEditDialogForGroup() { + if (editor_bubble_widget_) + editor_bubble_widget_->CloseWithReason( + BrowserFrame::ClosedReason::kUnspecified); } TabStripUILayout WebUITabStripContainerView::GetLayout() { @@ -907,6 +914,14 @@ void WebUITabStripContainerView::OnViewIsDeleting(View* observed_view) { tab_contents_container_ = nullptr; } +void WebUITabStripContainerView::OnWidgetDestroying(views::Widget* widget) { + if (widget != editor_bubble_widget_) + return; + + scoped_widget_observation_.Reset(); + editor_bubble_widget_ = nullptr; +} + bool WebUITabStripContainerView::SetPaneFocusAndFocusDefault() { // Make sure the pane first receives focus, then send a WebUI event to the // front-end so the correct HTML element receives focus. diff --git a/chrome/browser/ui/views/frame/webui_tab_strip_container_view.h b/chrome/browser/ui/views/frame/webui_tab_strip_container_view.h index 536365f0a0..c5e03129ad 100644 --- a/chrome/browser/ui/views/frame/webui_tab_strip_container_view.h +++ b/chrome/browser/ui/views/frame/webui_tab_strip_container_view.h @@ -23,6 +23,7 @@ #include "ui/views/accessible_pane_view.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_observer.h" #if !BUILDFLAG(ENABLE_WEBUI_TAB_STRIP) #error @@ -47,6 +48,7 @@ class ImmersiveRevealedLock; class WebUITabStripContainerView : public TabStripUIEmbedder, public gfx::AnimationDelegate, public views::AccessiblePaneView, + public views::WidgetObserver, public views::ViewObserver { public: WebUITabStripContainerView(BrowserView* browser_view, @@ -114,6 +116,7 @@ class WebUITabStripContainerView : public TabStripUIEmbedder, void ShowEditDialogForGroupAtPoint(gfx::Point point, gfx::Rect rect, tab_groups::TabGroupId group) override; + void HideEditDialogForGroup() override; TabStripUILayout GetLayout() override; SkColor GetColor(int id) const override; SkColor GetSystemColor(ui::NativeTheme::ColorId id) const override; @@ -132,6 +135,9 @@ class WebUITabStripContainerView : public TabStripUIEmbedder, void OnViewBoundsChanged(View* observed_view) override; void OnViewIsDeleting(View* observed_view) override; + // views::WidgetObserver: + void OnWidgetDestroying(views::Widget* widget) override; + // views::AccessiblePaneView bool SetPaneFocusAndFocusDefault() override; @@ -171,6 +177,10 @@ class WebUITabStripContainerView : public TabStripUIEmbedder, base::ScopedMultiSourceObservation view_observations_{this}; + base::ScopedObservation + scoped_widget_observation_{this}; + + views::Widget* editor_bubble_widget_; }; #endif // CHROME_BROWSER_UI_VIEWS_FRAME_WEBUI_TAB_STRIP_CONTAINER_VIEW_H_ diff --git a/chrome/browser/ui/webui/discards/discards_ui.h b/chrome/browser/ui/webui/discards/discards_ui.h index 9f9baf35a0..187dc9573a 100644 --- a/chrome/browser/ui/webui/discards/discards_ui.h +++ b/chrome/browser/ui/webui/discards/discards_ui.h @@ -37,7 +37,6 @@ class DiscardsUI : public ui::MojoWebUIController { private: std::unique_ptr ui_handler_; - std::unique_ptr site_data_provider_; std::string profile_id_; WEB_UI_CONTROLLER_TYPE_DECL(); diff --git a/chrome/browser/ui/webui/settings/settings_startup_pages_handler.cc b/chrome/browser/ui/webui/settings/settings_startup_pages_handler.cc index 0509d30670..eb980b3208 100644 --- a/chrome/browser/ui/webui/settings/settings_startup_pages_handler.cc +++ b/chrome/browser/ui/webui/settings/settings_startup_pages_handler.cc @@ -136,7 +136,7 @@ void StartupPagesHandler::HandleEditStartupPage(const base::ListValue* args) { int index; CHECK(args->GetInteger(1, &index)); - if (index < 0 || index > startup_custom_pages_table_model_.RowCount()) { + if (index < 0 || index >= startup_custom_pages_table_model_.RowCount()) { RejectJavascriptCallback(*callback_id, base::Value()); NOTREACHED(); return; diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_ui_browsertest.cc b/chrome/browser/ui/webui/tab_strip/tab_strip_ui_browsertest.cc index 13f082cfbb..cb9a610cc2 100644 --- a/chrome/browser/ui/webui/tab_strip/tab_strip_ui_browsertest.cc +++ b/chrome/browser/ui/webui/tab_strip/tab_strip_ui_browsertest.cc @@ -45,6 +45,7 @@ class MockTabStripUIEmbedder : public TabStripUIEmbedder { void(gfx::Point, std::unique_ptr)); MOCK_METHOD3(ShowEditDialogForGroupAtPoint, void(gfx::Point, gfx::Rect, tab_groups::TabGroupId)); + MOCK_METHOD0(HideEditDialogForGroup, void()); MOCK_METHOD0(GetLayout, TabStripUILayout()); MOCK_CONST_METHOD1(GetColor, SkColor(int)); MOCK_CONST_METHOD1(GetSystemColor, SkColor(ui::NativeTheme::ColorId)); diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_ui_embedder.h b/chrome/browser/ui/webui/tab_strip/tab_strip_ui_embedder.h index 980326cb29..d04fd92537 100644 --- a/chrome/browser/ui/webui/tab_strip/tab_strip_ui_embedder.h +++ b/chrome/browser/ui/webui/tab_strip/tab_strip_ui_embedder.h @@ -31,6 +31,8 @@ class TabStripUIEmbedder { gfx::Rect rect, tab_groups::TabGroupId group) = 0; + virtual void HideEditDialogForGroup() = 0; + virtual TabStripUILayout GetLayout() = 0; virtual SkColor GetColor(int id) const = 0; diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_ui_handler.cc b/chrome/browser/ui/webui/tab_strip/tab_strip_ui_handler.cc index 3ef87b45d4..b56ce1f842 100644 --- a/chrome/browser/ui/webui/tab_strip/tab_strip_ui_handler.cc +++ b/chrome/browser/ui/webui/tab_strip/tab_strip_ui_handler.cc @@ -228,6 +228,7 @@ void TabStripUIHandler::OnTabGroupChanged(const TabGroupChange& change) { } case TabGroupChange::kClosed: { + embedder_->HideEditDialogForGroup(); FireWebUIListener("tab-group-closed", base::Value(change.group.ToString())); break; diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_ui_handler_unittest.cc b/chrome/browser/ui/webui/tab_strip/tab_strip_ui_handler_unittest.cc index 8dcd0c0a7d..77e9657606 100644 --- a/chrome/browser/ui/webui/tab_strip/tab_strip_ui_handler_unittest.cc +++ b/chrome/browser/ui/webui/tab_strip/tab_strip_ui_handler_unittest.cc @@ -52,6 +52,7 @@ class StubTabStripUIEmbedder : public TabStripUIEmbedder { gfx::Rect rect, tab_groups::TabGroupId group_id) override { } + void HideEditDialogForGroup() override {} TabStripUILayout GetLayout() override { return TabStripUILayout(); } SkColor GetColor(int id) const override { return SK_ColorWHITE; } SkColor GetSystemColor(ui::NativeTheme::ColorId id) const override { diff --git a/components/download/content/internal/download_driver_impl.cc b/components/download/content/internal/download_driver_impl.cc index eb5d6fc2d0..668ae8488d 100644 --- a/components/download/content/internal/download_driver_impl.cc +++ b/components/download/content/internal/download_driver_impl.cc @@ -176,6 +176,7 @@ void DownloadDriverImpl::Start( download_url_params->set_guid(guid); download_url_params->set_transient(true); download_url_params->set_method(request_params.method); + download_url_params->set_credentials_mode(request_params.credentials_mode); download_url_params->set_file_path(file_path); if (request_params.fetch_error_body) download_url_params->set_fetch_error_body(true); @@ -189,6 +190,10 @@ void DownloadDriverImpl::Start( weak_ptr_factory_.GetWeakPtr(), guid)); download_url_params->set_require_safety_checks( request_params.require_safety_checks); + if (request_params.isolation_info) { + download_url_params->set_isolation_info( + request_params.isolation_info.value()); + } download_manager_coordinator_->DownloadUrl(std::move(download_url_params)); } diff --git a/components/download/database/DEPS b/components/download/database/DEPS index 4e8777c36f..727aa9d8f9 100644 --- a/components/download/database/DEPS +++ b/components/download/database/DEPS @@ -1,5 +1,6 @@ include_rules = [ "+components/download/public/common", "+components/leveldb_proto", - "+services/metrics/public" + "+services/metrics/public", + "+services/network/public/mojom", ] diff --git a/components/download/database/download_db_conversions.cc b/components/download/database/download_db_conversions.cc index 2e6291671e..769db52d68 100644 --- a/components/download/database/download_db_conversions.cc +++ b/components/download/database/download_db_conversions.cc @@ -9,6 +9,7 @@ #include "base/notreached.h" #include "base/pickle.h" #include "components/download/public/common/download_features.h" +#include "services/network/public/mojom/fetch_api.mojom-shared.h" namespace download { namespace { @@ -218,7 +219,8 @@ download_pb::InProgressInfo DownloadDBConversions::InProgressInfoToProto( in_progress_info.download_schedule.value())); proto.set_allocated_download_schedule(download_schedule_proto.release()); } - + proto.set_credentials_mode( + static_cast(in_progress_info.credentials_mode)); return proto; } @@ -275,6 +277,10 @@ InProgressInfo DownloadDBConversions::InProgressInfoFromProto( proto.download_schedule(), !proto.metered() /*only_on_wifi*/); DCHECK_NE(info.download_schedule->only_on_wifi(), info.metered); } + if (proto.has_credentials_mode()) { + info.credentials_mode = static_cast<::network::mojom::CredentialsMode>( + proto.credentials_mode()); + } return info; } diff --git a/components/download/database/download_db_conversions_unittest.cc b/components/download/database/download_db_conversions_unittest.cc index a2b80872d1..13d1513df0 100644 --- a/components/download/database/download_db_conversions_unittest.cc +++ b/components/download/database/download_db_conversions_unittest.cc @@ -9,6 +9,7 @@ #include "components/download/public/common/download_features.h" #include "components/download/public/common/download_schedule.h" #include "components/download/public/common/download_url_parameters.h" +#include "services/network/public/mojom/fetch_api.mojom-shared.h" #include "testing/gtest/include/gtest/gtest.h" namespace download { @@ -52,6 +53,7 @@ InProgressInfo CreateInProgressInfo() { std::make_pair("ABC", "def")); info.download_schedule = base::make_optional( false /*only_on_wifi*/, base::nullopt); + info.credentials_mode = ::network::mojom::CredentialsMode::kOmit; return info; } diff --git a/components/download/database/in_progress/in_progress_info.cc b/components/download/database/in_progress/in_progress_info.cc index 61a7afbd02..5ad63174a5 100644 --- a/components/download/database/in_progress/in_progress_info.cc +++ b/components/download/database/in_progress/in_progress_info.cc @@ -31,7 +31,8 @@ bool InProgressInfo::operator==(const InProgressInfo& other) const { interrupt_reason == other.interrupt_reason && paused == other.paused && metered == other.metered && bytes_wasted == other.bytes_wasted && auto_resume_count == other.auto_resume_count && - download_schedule == other.download_schedule; + download_schedule == other.download_schedule && + credentials_mode == other.credentials_mode; } } // namespace download diff --git a/components/download/database/in_progress/in_progress_info.h b/components/download/database/in_progress/in_progress_info.h index 2b67686c04..358964e32c 100644 --- a/components/download/database/in_progress/in_progress_info.h +++ b/components/download/database/in_progress/in_progress_info.h @@ -13,6 +13,7 @@ #include "components/download/public/common/download_item.h" #include "components/download/public/common/download_schedule.h" #include "components/download/public/common/download_url_parameters.h" +#include "services/network/public/mojom/fetch_api.mojom-shared.h" #include "url/gurl.h" namespace download { @@ -126,6 +127,10 @@ struct InProgressInfo { // When to start the download. Used by download later feature. base::Optional download_schedule; + + // The credentials mode of the request. + ::network::mojom::CredentialsMode credentials_mode = + ::network::mojom::CredentialsMode::kInclude; }; } // namespace download diff --git a/components/download/database/proto/download_entry.proto b/components/download/database/proto/download_entry.proto index af78857228..8cbc590dfd 100644 --- a/components/download/database/proto/download_entry.proto +++ b/components/download/database/proto/download_entry.proto @@ -79,6 +79,7 @@ message InProgressInfo { optional int64 bytes_wasted = 26; optional int32 auto_resume_count = 27; optional DownloadSchedule download_schedule = 28; + optional int32 credentials_mode = 30; // network::mojom::CredentialsMode } // Stores various metadata related to a download. diff --git a/components/download/internal/background_service/BUILD.gn b/components/download/internal/background_service/BUILD.gn index e81d8f4668..6097be2417 100644 --- a/components/download/internal/background_service/BUILD.gn +++ b/components/download/internal/background_service/BUILD.gn @@ -89,6 +89,7 @@ static_library("internal") { "//components/download/public/background_service:public", "//components/leveldb_proto", "//net", + "//services/network/public/mojom:url_loader_base", "//services/network/public/cpp", "//storage/browser", ] diff --git a/components/download/internal/background_service/in_memory_download.cc b/components/download/internal/background_service/in_memory_download.cc index f5e369ff66..ccf54bdff7 100644 --- a/components/download/internal/background_service/in_memory_download.cc +++ b/components/download/internal/background_service/in_memory_download.cc @@ -204,6 +204,10 @@ void InMemoryDownloadImpl::SendRequest() { request->request_body = std::move(request_body_); request->enable_upload_progress = true; } + if (request_params_.isolation_info) { + request->site_for_cookies = + request_params_.isolation_info->site_for_cookies(); + } url_chain_.push_back(request_params_.url); diff --git a/components/download/internal/background_service/proto/request.proto b/components/download/internal/background_service/proto/request.proto index 485bf6b6ae..346a201a5e 100644 --- a/components/download/internal/background_service/proto/request.proto +++ b/components/download/internal/background_service/proto/request.proto @@ -20,4 +20,5 @@ message RequestParams { repeated RequestHeader headers = 3; optional bool fetch_error_body = 4; optional bool require_safety_checks = 5 [default = true]; + optional int32 credentials_mode = 6; // network::mojom::CredentialsMode. } diff --git a/components/download/internal/background_service/proto_conversions.cc b/components/download/internal/background_service/proto_conversions.cc index 560fd484d0..1768714f0c 100644 --- a/components/download/internal/background_service/proto_conversions.cc +++ b/components/download/internal/background_service/proto_conversions.cc @@ -9,6 +9,7 @@ #include "components/download/internal/background_service/proto_conversions.h" #include "net/http/http_request_headers.h" #include "net/traffic_annotation/network_traffic_annotation.h" +#include "services/network/public/mojom/fetch_api.mojom-shared.h" namespace download { @@ -250,6 +251,14 @@ RequestParams ProtoConversions::RequestParamsFromProto( request_params.method = proto.method(); request_params.fetch_error_body = proto.fetch_error_body(); request_params.require_safety_checks = proto.require_safety_checks(); + if (proto.has_credentials_mode()) { + request_params.credentials_mode = + static_cast<::network::mojom::CredentialsMode>( + proto.credentials_mode()); + } else { + request_params.credentials_mode = + ::network::mojom::CredentialsMode::kInclude; + } for (int i = 0; i < proto.headers_size(); i++) { protodb::RequestHeader header = proto.headers(i); @@ -265,6 +274,8 @@ void ProtoConversions::RequestParamsToProto(const RequestParams& request_params, proto->set_method(request_params.method); proto->set_fetch_error_body(request_params.fetch_error_body); proto->set_require_safety_checks(request_params.require_safety_checks); + proto->set_credentials_mode( + static_cast(request_params.credentials_mode)); int i = 0; net::HttpRequestHeaders::Iterator iter(request_params.request_headers); diff --git a/components/download/internal/background_service/proto_conversions_unittest.cc b/components/download/internal/background_service/proto_conversions_unittest.cc index 4307d0cbfd..ef4b561bff 100644 --- a/components/download/internal/background_service/proto_conversions_unittest.cc +++ b/components/download/internal/background_service/proto_conversions_unittest.cc @@ -9,6 +9,7 @@ #include "components/download/internal/background_service/entry.h" #include "components/download/internal/background_service/proto_conversions.h" #include "components/download/internal/background_service/test/entry_utils.h" +#include "services/network/public/mojom/fetch_api.mojom-shared.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -99,6 +100,7 @@ TEST_F(ProtoConversionsTest, RequestParamsWithHeadersConversion) { expected.method = "GET"; expected.fetch_error_body = true; expected.require_safety_checks = false; + expected.credentials_mode = ::network::mojom::CredentialsMode::kInclude; expected.request_headers.SetHeader("key1", "value1"); expected.request_headers.SetHeader("key2", "value2"); @@ -110,6 +112,7 @@ TEST_F(ProtoConversionsTest, RequestParamsWithHeadersConversion) { EXPECT_EQ(expected.method, actual.method); EXPECT_EQ(expected.fetch_error_body, actual.fetch_error_body); EXPECT_EQ(expected.require_safety_checks, actual.require_safety_checks); + EXPECT_EQ(expected.credentials_mode, actual.credentials_mode); std::string out; actual.request_headers.GetHeader("key1", &out); @@ -120,6 +123,19 @@ TEST_F(ProtoConversionsTest, RequestParamsWithHeadersConversion) { actual.request_headers.ToString()); } +TEST_F(ProtoConversionsTest, RequestParamsWithMissingCredentialsMode) { + RequestParams expected; + expected.url = GURL(TEST_URL); + expected.method = "GET"; + + protodb::RequestParams proto; + RequestParamsToProto(expected, &proto); + RequestParams actual = RequestParamsFromProto(proto); + + EXPECT_EQ(expected.credentials_mode, + ::network::mojom::CredentialsMode::kInclude); +} + TEST_F(ProtoConversionsTest, EntryConversion) { Entry expected = test::BuildEntry(DownloadClient::TEST, base::GenerateGUID()); Entry actual = EntryFromProto(EntryToProto(expected)); diff --git a/components/download/internal/common/download_create_info.cc b/components/download/internal/common/download_create_info.cc index bba0342d59..c0c4f01d53 100644 --- a/components/download/internal/common/download_create_info.cc +++ b/components/download/internal/common/download_create_info.cc @@ -32,7 +32,9 @@ DownloadCreateInfo::DownloadCreateInfo( connection_info(net::HttpResponseInfo::CONNECTION_INFO_UNKNOWN), method("GET"), ukm_source_id(ukm::kInvalidSourceId), - is_content_initiated(false) {} + is_content_initiated(false), + credentials_mode(::network::mojom::CredentialsMode::kInclude), + isolation_info(base::nullopt) {} DownloadCreateInfo::DownloadCreateInfo() : DownloadCreateInfo(base::Time(), std::make_unique()) {} diff --git a/components/download/internal/common/download_item_impl.cc b/components/download/internal/common/download_item_impl.cc index f557ef8795..100493f1b5 100644 --- a/components/download/internal/common/download_item_impl.cc +++ b/components/download/internal/common/download_item_impl.cc @@ -234,7 +234,9 @@ DownloadItemImpl::RequestInfo::RequestInfo( ui::PageTransition transition_type, bool has_user_gesture, const std::string& remote_address, - base::Time start_time) + base::Time start_time, + ::network::mojom::CredentialsMode credentials_mode, + const base::Optional& isolation_info) : url_chain(url_chain), referrer_url(referrer_url), site_url(site_url), @@ -246,7 +248,9 @@ DownloadItemImpl::RequestInfo::RequestInfo( transition_type(transition_type), has_user_gesture(has_user_gesture), remote_address(remote_address), - start_time(start_time) {} + start_time(start_time), + credentials_mode(credentials_mode), + isolation_info(isolation_info) {} DownloadItemImpl::RequestInfo::RequestInfo(const GURL& url) : url_chain(std::vector(1, url)), start_time(base::Time::Now()) {} @@ -328,7 +332,9 @@ DownloadItemImpl::DownloadItemImpl( ui::PAGE_TRANSITION_LINK, false, std::string(), - start_time), + start_time, + ::network::mojom::CredentialsMode::kInclude, + base::nullopt), guid_(guid), download_id_(download_id), mime_type_(mime_type), @@ -389,7 +395,9 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate, : ui::PAGE_TRANSITION_LINK, info.has_user_gesture, info.remote_address, - info.start_time), + info.start_time, + info.credentials_mode, + info.isolation_info), guid_(info.guid.empty() ? base::GenerateGUID() : info.guid), download_id_(download_id), response_headers_(info.response_headers), @@ -1129,6 +1137,15 @@ const base::Optional& DownloadItemImpl::GetDownloadSchedule() return download_schedule_; } +::network::mojom::CredentialsMode DownloadItemImpl::GetCredentialsMode() const { + return request_info_.credentials_mode; +} + +const base::Optional& DownloadItemImpl::GetIsolationInfo() + const { + return request_info_.isolation_info; +} + void DownloadItemImpl::OnContentCheckCompleted(DownloadDangerType danger_type, DownloadInterruptReason reason) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); diff --git a/components/download/internal/common/download_response_handler.cc b/components/download/internal/common/download_response_handler.cc index a5f785aca0..8bdce0e0d2 100644 --- a/components/download/internal/common/download_response_handler.cc +++ b/components/download/internal/common/download_response_handler.cc @@ -75,6 +75,7 @@ DownloadResponseHandler::DownloadResponseHandler( request_origin_(request_origin), download_source_(download_source), has_strong_validators_(false), + credentials_mode_(resource_request->credentials_mode), is_partial_request_(save_info_->offset > 0), completed_(false), abort_reason_(DOWNLOAD_INTERRUPT_REASON_NONE), @@ -84,6 +85,9 @@ DownloadResponseHandler::DownloadResponseHandler( } if (resource_request->request_initiator.has_value()) request_initiator_ = resource_request->request_initiator; + + if (resource_request->trusted_params) + isolation_info_ = resource_request->trusted_params->isolation_info; } DownloadResponseHandler::~DownloadResponseHandler() = default; @@ -150,6 +154,8 @@ DownloadResponseHandler::CreateDownloadCreateInfo( create_info->request_origin = request_origin_; create_info->download_source = download_source_; create_info->request_initiator = request_initiator_; + create_info->credentials_mode = credentials_mode_; + create_info->isolation_info = isolation_info_; HandleResponseHeaders(head.headers.get(), create_info.get()); return create_info; diff --git a/components/download/internal/common/download_utils.cc b/components/download/internal/common/download_utils.cc index 6ad1043959..5ef7d03541 100644 --- a/components/download/internal/common/download_utils.cc +++ b/components/download/internal/common/download_utils.cc @@ -438,6 +438,7 @@ DownloadDBEntry CreateDownloadDBEntryFromItem(const DownloadItemImpl& item) { in_progress_info.bytes_wasted = item.GetBytesWasted(); in_progress_info.auto_resume_count = item.GetAutoResumeCount(); in_progress_info.download_schedule = item.GetDownloadSchedule(); + in_progress_info.credentials_mode = item.GetCredentialsMode(); download_info.in_progress_info = in_progress_info; diff --git a/components/download/public/background_service/BUILD.gn b/components/download/public/background_service/BUILD.gn index 0e22c563e2..e4d3fad19b 100644 --- a/components/download/public/background_service/BUILD.gn +++ b/components/download/public/background_service/BUILD.gn @@ -27,7 +27,10 @@ source_set("public") { "service_config.h", ] - deps = [ "//components/keyed_service/core" ] + deps = [ + "//components/keyed_service/core", + "//services/network/public/mojom:url_loader_base", + ] # TODO(xingliu): Create blob target that doesn't need to depend on blink. # Currently gn header check will fail even if the code is not built into any targets. diff --git a/components/download/public/background_service/DEPS b/components/download/public/background_service/DEPS index 4d8aa673f1..74b585b295 100644 --- a/components/download/public/background_service/DEPS +++ b/components/download/public/background_service/DEPS @@ -2,9 +2,11 @@ include_rules = [ "-content", "+base", "+components/keyed_service", + "+net/base", "+net/http", "+net/traffic_annotation", "+services/network/public/cpp", + "+services/network/public/mojom", "+storage/browser", "+url", ] diff --git a/components/download/public/background_service/download_params.cc b/components/download/public/background_service/download_params.cc index 00a3ccbd9c..8a1a504a98 100644 --- a/components/download/public/background_service/download_params.cc +++ b/components/download/public/background_service/download_params.cc @@ -21,9 +21,13 @@ bool SchedulingParams::operator==(const SchedulingParams& rhs) const { } RequestParams::RequestParams() - : method("GET"), fetch_error_body(false), require_safety_checks(true) {} + : method("GET"), + fetch_error_body(false), + require_safety_checks(true), + credentials_mode(::network::mojom::CredentialsMode::kInclude) {} RequestParams::RequestParams(const RequestParams& other) = default; +RequestParams::~RequestParams() = default; DownloadParams::DownloadParams() : client(DownloadClient::INVALID) {} diff --git a/components/download/public/background_service/download_params.h b/components/download/public/background_service/download_params.h index b16c150d8a..8aabeab939 100644 --- a/components/download/public/background_service/download_params.h +++ b/components/download/public/background_service/download_params.h @@ -8,8 +8,11 @@ #include "base/callback.h" #include "base/time/time.h" #include "components/download/public/background_service/clients.h" +#include "net/base/isolation_info.h" #include "net/http/http_request_headers.h" #include "net/traffic_annotation/network_traffic_annotation.h" +#include "services/network/public/mojom/fetch_api.mojom-shared.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "url/gurl.h" namespace download { @@ -96,7 +99,7 @@ struct RequestParams { public: RequestParams(); RequestParams(const RequestParams& other); - ~RequestParams() = default; + ~RequestParams(); GURL url; @@ -110,6 +113,12 @@ struct RequestParams { // Whether the download is not trustworthy and requires safe browsing checks. bool require_safety_checks; + + // The credentials mode of the request. + ::network::mojom::CredentialsMode credentials_mode; + // The isolation info of the request, this won't be persisted to db and will + // be invalidate during download resumption in new browser session. + base::Optional isolation_info; }; // The parameters that describe a download request made to the DownloadService. diff --git a/components/download/public/common/BUILD.gn b/components/download/public/common/BUILD.gn index 3c8df71fb8..a0005014bf 100644 --- a/components/download/public/common/BUILD.gn +++ b/components/download/public/common/BUILD.gn @@ -79,6 +79,7 @@ component("public") { "//components/services/quarantine/public/mojom", "//mojo/public/cpp/bindings", "//services/network/public/cpp", + "//services/network/public/mojom:url_loader_base", ] deps = [ diff --git a/components/download/public/common/download_create_info.h b/components/download/public/common/download_create_info.h index b8c6e21b1b..51d58903e0 100644 --- a/components/download/public/common/download_create_info.h +++ b/components/download/public/common/download_create_info.h @@ -25,6 +25,7 @@ #include "net/http/http_response_info.h" #include "net/url_request/referrer_policy.h" #include "services/metrics/public/cpp/ukm_source_id.h" +#include "services/network/public/mojom/fetch_api.mojom-shared.h" #include "ui/base/page_transition_types.h" #include "url/gurl.h" #include "url/origin.h" @@ -176,6 +177,11 @@ struct COMPONENTS_DOWNLOAD_EXPORT DownloadCreateInfo { // Whether download is initated by the content on the page. bool is_content_initiated; + ::network::mojom::CredentialsMode credentials_mode; + + // Isolation info for the download request, mainly for same site cookies. + base::Optional isolation_info; + private: DISALLOW_COPY_AND_ASSIGN(DownloadCreateInfo); }; diff --git a/components/download/public/common/download_item.h b/components/download/public/common/download_item.h index b561de01fb..5d4f74b742 100644 --- a/components/download/public/common/download_item.h +++ b/components/download/public/common/download_item.h @@ -33,6 +33,8 @@ #include "components/download/public/common/download_interrupt_reasons.h" #include "components/download/public/common/download_schedule.h" #include "components/download/public/common/download_source.h" +#include "services/network/public/mojom/fetch_api.mojom-shared.h" +#include "net/base/isolation_info.h" #include "ui/base/page_transition_types.h" #include "url/origin.h" @@ -351,6 +353,13 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadItem : public base::SupportsUserData { // DownloadSource prompting this download. virtual DownloadSource GetDownloadSource() const = 0; + // The credentials mode of the request. + virtual ::network::mojom::CredentialsMode GetCredentialsMode() const = 0; + + // The isolation mode of the request. + virtual const base::Optional& GetIsolationInfo() + const = 0; + // Destination State accessors -------------------------------------------- // Full path to the downloaded or downloading file. This is the path to the diff --git a/components/download/public/common/download_item_impl.h b/components/download/public/common/download_item_impl.h index 2868b25bd9..6d970f5630 100644 --- a/components/download/public/common/download_item_impl.h +++ b/components/download/public/common/download_item_impl.h @@ -31,6 +31,7 @@ #include "components/download/public/common/url_loader_factory_provider.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "services/device/public/mojom/wake_lock_provider.mojom.h" +#include "services/network/public/mojom/fetch_api.mojom-shared.h" #include "url/gurl.h" #include "url/origin.h" @@ -60,7 +61,9 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadItemImpl ui::PageTransition transition_type, bool has_user_gesture, const std::string& remote_address, - base::Time start_time); + base::Time start_time, + ::network::mojom::CredentialsMode credentials_mode, + const base::Optional& isolation_info); RequestInfo(); explicit RequestInfo(const RequestInfo& other); explicit RequestInfo(const GURL& url); @@ -104,6 +107,13 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadItemImpl // Time the download was started. base::Time start_time; + + // The credentials mode of the request. + ::network::mojom::CredentialsMode credentials_mode = + ::network::mojom::CredentialsMode::kInclude; + + // Isolation info for the request. + base::Optional isolation_info; }; // Information about the current state of the download destination. @@ -301,6 +311,8 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadItemImpl bool IsParallelDownload() const override; DownloadCreationType GetDownloadCreationType() const override; const base::Optional& GetDownloadSchedule() const override; + ::network::mojom::CredentialsMode GetCredentialsMode() const override; + const base::Optional& GetIsolationInfo() const override; void OnContentCheckCompleted(DownloadDangerType danger_type, DownloadInterruptReason reason) override; void OnAsyncScanningCompleted(DownloadDangerType danger_type) override; diff --git a/components/download/public/common/download_response_handler.h b/components/download/public/common/download_response_handler.h index e7081025df..d39e0e1c7f 100644 --- a/components/download/public/common/download_response_handler.h +++ b/components/download/public/common/download_response_handler.h @@ -17,6 +17,7 @@ #include "components/download/public/common/download_utils.h" #include "mojo/public/cpp/bindings/remote.h" #include "net/cert/cert_status_flags.h" +#include "services/network/public/mojom/fetch_api.mojom-shared.h" #include "services/network/public/mojom/url_loader.mojom.h" #include "services/network/public/mojom/url_response_head.mojom.h" #include "url/origin.h" @@ -100,6 +101,8 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadResponseHandler net::CertStatus cert_status_; bool has_strong_validators_; base::Optional request_initiator_; + ::network::mojom::CredentialsMode credentials_mode_; + base::Optional isolation_info_; bool is_partial_request_; bool completed_; diff --git a/components/download/public/common/download_url_parameters.cc b/components/download/public/common/download_url_parameters.cc index 0d898ac922..4ae3d9b207 100644 --- a/components/download/public/common/download_url_parameters.cc +++ b/components/download/public/common/download_url_parameters.cc @@ -19,6 +19,7 @@ DownloadUrlParameters::DownloadUrlParameters( : content_initiated_(false), use_if_range_(true), method_("GET"), + credentials_mode_(::network::mojom::CredentialsMode::kInclude), post_id_(-1), prefer_cache_(false), referrer_policy_( diff --git a/components/download/public/common/download_url_parameters.h b/components/download/public/common/download_url_parameters.h index 0be34e0e33..34dab4fae4 100644 --- a/components/download/public/common/download_url_parameters.h +++ b/components/download/public/common/download_url_parameters.h @@ -131,6 +131,12 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadUrlParameters { // HTTP method to use. void set_method(const std::string& method) { method_ = method; } + // The requests' credentials mode. + void set_credentials_mode( + ::network::mojom::CredentialsMode credentials_mode) { + credentials_mode_ = credentials_mode; + } + // Body of the HTTP POST request. void set_post_body(scoped_refptr post_body) { post_body_ = post_body; @@ -266,6 +272,9 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadUrlParameters { const std::string& etag() const { return etag_; } bool use_if_range() const { return use_if_range_; } const std::string& method() const { return method_; } + ::network::mojom::CredentialsMode credentials_mode() const { + return credentials_mode_; + } scoped_refptr post_body() { return post_body_; } int64_t post_id() const { return post_id_; } bool prefer_cache() const { return prefer_cache_; } @@ -331,6 +340,7 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadUrlParameters { std::string etag_; bool use_if_range_; std::string method_; + ::network::mojom::CredentialsMode credentials_mode_; scoped_refptr post_body_; BlobStorageContextGetter blob_storage_context_getter_; int64_t post_id_; diff --git a/components/download/public/common/mock_download_item.h b/components/download/public/common/mock_download_item.h index 2ca3726cbe..3db623e279 100644 --- a/components/download/public/common/mock_download_item.h +++ b/components/download/public/common/mock_download_item.h @@ -127,6 +127,11 @@ class MockDownloadItem : public DownloadItem { MOCK_CONST_METHOD0(GetDownloadCreationType, DownloadCreationType()); MOCK_CONST_METHOD0(GetDownloadSchedule, const base::Optional&()); + MOCK_CONST_METHOD0(GetCredentialsMode, ::network::mojom::CredentialsMode()); + MOCK_METHOD((const base::Optional&), + GetIsolationInfo, + (), + (const override)); MOCK_METHOD2(OnContentCheckCompleted, void(DownloadDangerType, DownloadInterruptReason)); MOCK_METHOD1(SetOpenWhenComplete, void(bool)); diff --git a/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.cc b/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.cc index 60212cae10..ade80fca4f 100644 --- a/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.cc +++ b/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.cc @@ -77,6 +77,8 @@ void BackForwardCachePageLoadMetricsObserver:: OnFirstPaintAfterBackForwardCacheRestoreInPage( const page_load_metrics::mojom::BackForwardCacheTiming& timing, size_t index) { + if (index >= back_forward_cache_navigation_ids_.size()) + return; auto first_paint = timing.first_paint_after_back_forward_cache_restore; DCHECK(!first_paint.is_zero()); if (page_load_metrics:: @@ -109,6 +111,8 @@ void BackForwardCachePageLoadMetricsObserver:: OnRequestAnimationFramesAfterBackForwardCacheRestoreInPage( const page_load_metrics::mojom::BackForwardCacheTiming& timing, size_t index) { + if (index >= back_forward_cache_navigation_ids_.size()) + return; auto request_animation_frames = timing.request_animation_frames_after_back_forward_cache_restore; DCHECK_EQ(request_animation_frames.size(), 3u); @@ -143,6 +147,8 @@ void BackForwardCachePageLoadMetricsObserver:: OnFirstInputAfterBackForwardCacheRestoreInPage( const page_load_metrics::mojom::BackForwardCacheTiming& timing, size_t index) { + if (index >= back_forward_cache_navigation_ids_.size()) + return; auto first_input_delay = timing.first_input_delay_after_back_forward_cache_restore; DCHECK(first_input_delay.has_value()); diff --git a/components/page_load_metrics/browser/page_load_tracker.cc b/components/page_load_metrics/browser/page_load_tracker.cc index 846cfaa16b..f02129066b 100644 --- a/components/page_load_metrics/browser/page_load_tracker.cc +++ b/components/page_load_metrics/browser/page_load_tracker.cc @@ -12,6 +12,7 @@ #include "base/check_op.h" #include "base/metrics/histogram_macros.h" #include "base/notreached.h" +#include "base/strings/stringprintf.h" #include "base/time/default_tick_clock.h" #include "base/trace_event/trace_event.h" #include "components/page_load_metrics/browser/page_load_metrics_embedder_interface.h" @@ -129,7 +130,13 @@ void DispatchEventsAfterBackForwardCacheRestore( last_timings, const std::vector>& new_timings) { - DCHECK_GE(new_timings.size(), last_timings.size()); + if (new_timings.size() < last_timings.size()) { + mojo::ReportBadMessage(base::StringPrintf( + "`new_timings.size()` (%zu) must be equal to or greater than " + "`last_timings.size()` (%zu) but is not", + new_timings.size(), last_timings.size())); + return; + } for (size_t i = 0; i < new_timings.size(); i++) { auto first_paint = diff --git a/components/pdf/renderer/pdf_accessibility_tree.cc b/components/pdf/renderer/pdf_accessibility_tree.cc index 3222c0aef7..269e76928d 100644 --- a/components/pdf/renderer/pdf_accessibility_tree.cc +++ b/components/pdf/renderer/pdf_accessibility_tree.cc @@ -1486,9 +1486,16 @@ content::RenderAccessibility* PdfAccessibilityTree::GetRenderAccessibility() { // If RenderAccessibility is unable to generate valid positive IDs, // we shouldn't use it. This can happen if Blink accessibility is disabled // after we started generating the accessible PDF. + base::WeakPtr weak_this = + weak_ptr_factory_.GetWeakPtr(); if (render_accessibility->GenerateAXID() <= 0) return nullptr; + // GenerateAXID() above can cause self deletion. Returning nullptr will cause + // callers to stop doing work. + if (!weak_this) + return nullptr; + return render_accessibility; } diff --git a/components/pdf/renderer/pdf_accessibility_tree.h b/components/pdf/renderer/pdf_accessibility_tree.h index 16331d527b..55038a28bd 100644 --- a/components/pdf/renderer/pdf_accessibility_tree.h +++ b/components/pdf/renderer/pdf_accessibility_tree.h @@ -11,6 +11,7 @@ #include #include "base/optional.h" +#include "base/memory/weak_ptr.h" #include "content/public/renderer/plugin_ax_tree_source.h" #include "ppapi/c/pp_instance.h" #include "ppapi/c/private/ppb_pdf.h" @@ -171,6 +172,8 @@ class PdfAccessibilityTree : public content::PluginAXTreeSource { // Index of the next expected PDF accessibility page info, used to ignore // outdated calls of SetAccessibilityPageInfo(). uint32_t next_page_index_ = 0; + + base::WeakPtrFactory weak_ptr_factory_{this}; }; } // namespace pdf diff --git a/components/performance_manager/decorators/site_data_recorder_unittest.cc b/components/performance_manager/decorators/site_data_recorder_unittest.cc index 003bea3d06..909533f41a 100644 --- a/components/performance_manager/decorators/site_data_recorder_unittest.cc +++ b/components/performance_manager/decorators/site_data_recorder_unittest.cc @@ -89,8 +89,9 @@ class MockDataCache : public SiteDataCache { } std::unique_ptr GetWriterForOrigin( const url::Origin& origin) override { - scoped_refptr fake_impl = base::WrapRefCounted( - new internal::SiteDataImpl(origin, &delegate_, &data_store_)); + scoped_refptr fake_impl = + base::WrapRefCounted(new internal::SiteDataImpl( + origin, delegate_.GetWeakPtr(), &data_store_)); return std::make_unique(origin, fake_impl); } diff --git a/components/performance_manager/persistence/site_data/site_data_cache_impl.cc b/components/performance_manager/persistence/site_data/site_data_cache_impl.cc index e936a16c5d..547de3ca48 100644 --- a/components/performance_manager/persistence/site_data/site_data_cache_impl.cc +++ b/components/performance_manager/persistence/site_data/site_data_cache_impl.cc @@ -122,8 +122,8 @@ internal::SiteDataImpl* SiteDataCacheImpl::GetOrCreateFeatureImpl( return iter->second; // If not create a new one and add it to the map. - internal::SiteDataImpl* site_data = - new internal::SiteDataImpl(origin, this, data_store_.get()); + internal::SiteDataImpl* site_data = new internal::SiteDataImpl( + origin, weak_factory_.GetWeakPtr(), data_store_.get()); // internal::SiteDataImpl is a ref-counted object, it's safe to store a raw // pointer to it here as this class will get notified when it's about to be diff --git a/components/performance_manager/persistence/site_data/site_data_cache_impl.h b/components/performance_manager/persistence/site_data/site_data_cache_impl.h index c21c0bf72f..f7b6c462a5 100644 --- a/components/performance_manager/persistence/site_data/site_data_cache_impl.h +++ b/components/performance_manager/persistence/site_data/site_data_cache_impl.h @@ -15,6 +15,7 @@ #include "base/files/file_path.h" #include "base/gtest_prod_util.h" #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "base/scoped_observation.h" #include "base/sequence_checker.h" #include "components/performance_manager/persistence/site_data/site_data_cache.h" @@ -102,6 +103,8 @@ class SiteDataCacheImpl : public SiteDataCache, SEQUENCE_CHECKER(sequence_checker_); + base::WeakPtrFactory weak_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(SiteDataCacheImpl); }; diff --git a/components/performance_manager/persistence/site_data/site_data_cache_impl_unittest.cc b/components/performance_manager/persistence/site_data/site_data_cache_impl_unittest.cc index 54c692ef96..26ee928101 100644 --- a/components/performance_manager/persistence/site_data/site_data_cache_impl_unittest.cc +++ b/components/performance_manager/persistence/site_data/site_data_cache_impl_unittest.cc @@ -269,4 +269,19 @@ TEST_F(SiteDataCacheImplTest, InspectorWorks) { browser_context_.UniqueId())); } +// TODO(https://crbug.com/1231933): Turn this into a death test to verify that +// the data cache asserts that no readers outlive the cache. +TEST_F(SiteDataCacheImplTest, NoUAFWhenReaderHeldAfterTeardown) { + { + // Hold on to this reader while destroying the data cache. + // This is a violation of the data cache contract. For the purpose + // of quick-fixing https://crbug.com/1231933, allow and survive this + // for now. + auto reader = data_cache_->GetReaderForOrigin(origin_); + + // This should not UAF under ASAN. + data_cache_.reset(); + } +} + } // namespace performance_manager diff --git a/components/performance_manager/persistence/site_data/site_data_impl.cc b/components/performance_manager/persistence/site_data/site_data_impl.cc index eeb4a5da4c..738021a00a 100644 --- a/components/performance_manager/persistence/site_data/site_data_impl.cc +++ b/components/performance_manager/persistence/site_data/site_data_impl.cc @@ -169,7 +169,7 @@ SiteDataImpl::GetFeatureObservationWindowLengthForTesting() { } SiteDataImpl::SiteDataImpl(const url::Origin& origin, - OnDestroyDelegate* delegate, + base::WeakPtr delegate, SiteDataStore* data_store) : load_duration_(kSampleWeightFactor), cpu_usage_estimate_(kSampleWeightFactor), @@ -198,13 +198,19 @@ SiteDataImpl::~SiteDataImpl() { DCHECK(!IsLoaded()); DCHECK_EQ(0U, loaded_tabs_in_background_count_); - DCHECK(delegate_); - delegate_->OnSiteDataImplDestroyed(this); - - // TODO(sebmarchand): Some data might be lost here if the read operation has - // not completed, add some metrics to measure if this is really an issue. - if (is_dirty_ && fully_initialized_) - data_store_->WriteSiteDataIntoStore(origin_, FlushStateToProto()); + // Make sure not to dispatch a notification to a deleted delegate, and gate + // the DB write on it too, as the delegate and the data store have the + // same lifetime. + // TODO(https://crbug.com/1231933): Fix this properly and restore the end of + // life write here. + if (delegate_) { + delegate_->OnSiteDataImplDestroyed(this); + + // TODO(sebmarchand): Some data might be lost here if the read operation has + // not completed, add some metrics to measure if this is really an issue. + if (is_dirty_ && fully_initialized_) + data_store_->WriteSiteDataIntoStore(origin_, FlushStateToProto()); + } } base::TimeDelta SiteDataImpl::FeatureObservationDuration( diff --git a/components/performance_manager/persistence/site_data/site_data_impl.h b/components/performance_manager/persistence/site_data/site_data_impl.h index f48c7dd1a7..c50fe64925 100644 --- a/components/performance_manager/persistence/site_data/site_data_impl.h +++ b/components/performance_manager/persistence/site_data/site_data_impl.h @@ -172,7 +172,7 @@ class SiteDataImpl : public base::RefCounted { friend class performance_manager::MockDataCache; SiteDataImpl(const url::Origin& origin, - OnDestroyDelegate* delegate, + base::WeakPtr delegate, SiteDataStore* data_store); virtual ~SiteDataImpl(); @@ -283,7 +283,13 @@ class SiteDataImpl : public base::RefCounted { // The delegate that should get notified when this object is about to get // destroyed, it should outlive this object. - OnDestroyDelegate* const delegate_; + // The use of WeakPtr here is a temporary, minimally invasive fix for the UAF + // reported in https://crbug.com/1231933. By using a WeakPtr, the call-out + // is avoided in the case where the OnDestroyDelegate has been deleted before + // all SiteDataImpls have been released. + // The proper fix for this is going to be more invasive and less suitable + // for merging, should it come to that. + base::WeakPtr const delegate_; // Indicates if this object has been fully initialized, either because the // read operation from the database has completed or because it has been diff --git a/components/performance_manager/persistence/site_data/site_data_impl_unittest.cc b/components/performance_manager/persistence/site_data/site_data_impl_unittest.cc index 90edb917b2..0ce8da8a0b 100644 --- a/components/performance_manager/persistence/site_data/site_data_impl_unittest.cc +++ b/components/performance_manager/persistence/site_data/site_data_impl_unittest.cc @@ -26,9 +26,10 @@ class TestSiteDataImpl : public SiteDataImpl { using SiteDataImpl::site_characteristics_for_testing; using SiteDataImpl::TimeDeltaToInternalRepresentation; - explicit TestSiteDataImpl(const url::Origin& origin, - SiteDataImpl::OnDestroyDelegate* delegate, - SiteDataStore* data_store) + explicit TestSiteDataImpl( + const url::Origin& origin, + base::WeakPtr delegate, + SiteDataStore* data_store) : SiteDataImpl(origin, delegate, data_store) {} base::TimeDelta FeatureObservationTimestamp( @@ -90,7 +91,7 @@ class SiteDataImplTest : public ::testing::Test { scoped_refptr GetDataImpl( const url::Origin& origin, - SiteDataImpl::OnDestroyDelegate* destroy_delegate, + base::WeakPtr destroy_delegate, SiteDataStore* data_store) { return base::MakeRefCounted(origin, destroy_delegate, data_store); @@ -100,7 +101,7 @@ class SiteDataImplTest : public ::testing::Test { // locally so it can be run later. scoped_refptr GetDataImplAndInterceptReadCallback( const url::Origin& origin, - SiteDataImpl::OnDestroyDelegate* destroy_delegate, + base::WeakPtr destroy_delegate, MockDataStore* mock_data_store, SiteDataStore::ReadSiteDataFromStoreCallback* read_cb) { auto read_from_store_mock_impl = @@ -113,7 +114,7 @@ class SiteDataImplTest : public ::testing::Test { OnReadSiteDataFromStore(::testing::_, ::testing::_)) .WillOnce(::testing::Invoke(read_from_store_mock_impl)); auto local_site_data = - GetDataImpl(origin, &destroy_delegate_, mock_data_store); + GetDataImpl(origin, destroy_delegate_.GetWeakPtr(), mock_data_store); ::testing::Mock::VerifyAndClear(mock_data_store); return local_site_data; } @@ -134,7 +135,7 @@ class SiteDataImplTest : public ::testing::Test { TEST_F(SiteDataImplTest, BasicTestEndToEnd) { auto local_site_data = - GetDataImpl(kDummyOrigin, &destroy_delegate_, &data_store); + GetDataImpl(kDummyOrigin, destroy_delegate_.GetWeakPtr(), &data_store); local_site_data->NotifySiteLoaded(); local_site_data->NotifyLoadedSiteBackgrounded(); @@ -191,7 +192,7 @@ TEST_F(SiteDataImplTest, BasicTestEndToEnd) { TEST_F(SiteDataImplTest, LastLoadedTime) { auto local_site_data = - GetDataImpl(kDummyOrigin, &destroy_delegate_, &data_store); + GetDataImpl(kDummyOrigin, destroy_delegate_.GetWeakPtr(), &data_store); // Create a second instance of this object, simulates having several tab // owning it. @@ -222,7 +223,7 @@ TEST_F(SiteDataImplTest, LastLoadedTime) { TEST_F(SiteDataImplTest, GetFeatureUsageForUnloadedSite) { auto local_site_data = - GetDataImpl(kDummyOrigin, &destroy_delegate_, &data_store); + GetDataImpl(kDummyOrigin, destroy_delegate_.GetWeakPtr(), &data_store); local_site_data->NotifySiteLoaded(); local_site_data->NotifyLoadedSiteBackgrounded(); @@ -275,7 +276,7 @@ TEST_F(SiteDataImplTest, AllDurationGetSavedOnUnload) { // This test helps making sure that the observation/timestamp fields get saved // for all the features being tracked. auto local_site_data = - GetDataImpl(kDummyOrigin, &destroy_delegate_, &data_store); + GetDataImpl(kDummyOrigin, destroy_delegate_.GetWeakPtr(), &data_store); const base::TimeDelta kInterval = base::TimeDelta::FromSeconds(1); const auto kIntervalInternalRepresentation = @@ -340,7 +341,7 @@ TEST_F(SiteDataImplTest, DestroyNotifiesDelegate) { strict_delegate; { auto local_site_data = - GetDataImpl(kDummyOrigin, &strict_delegate, &data_store); + GetDataImpl(kDummyOrigin, strict_delegate.GetWeakPtr(), &data_store); EXPECT_CALL(strict_delegate, OnSiteDataImplDestroyed(local_site_data.get())); } @@ -357,7 +358,7 @@ TEST_F(SiteDataImplTest, OnInitCallbackMergePreviousObservations) { SiteDataStore::ReadSiteDataFromStoreCallback read_cb; auto local_site_data = GetDataImplAndInterceptReadCallback( - kDummyOrigin, &destroy_delegate_, &mock_data_store, &read_cb); + kDummyOrigin, destroy_delegate_.GetWeakPtr(), &mock_data_store, &read_cb); // Simulates audio in background usage before the callback gets called. local_site_data->NotifySiteLoaded(); @@ -481,7 +482,7 @@ TEST_F(SiteDataImplTest, LateAsyncReadDoesntEraseData) { SiteDataStore::ReadSiteDataFromStoreCallback read_cb; auto local_site_data_writer = GetDataImplAndInterceptReadCallback( - kDummyOrigin, &destroy_delegate_, &mock_data_store, &read_cb); + kDummyOrigin, destroy_delegate_.GetWeakPtr(), &mock_data_store, &read_cb); local_site_data_writer->NotifySiteLoaded(); local_site_data_writer->NotifyLoadedSiteBackgrounded(); @@ -510,7 +511,7 @@ TEST_F(SiteDataImplTest, LateAsyncReadDoesntBypassClearEvent) { SiteDataStore::ReadSiteDataFromStoreCallback read_cb; auto local_site_data = GetDataImplAndInterceptReadCallback( - kDummyOrigin, &destroy_delegate_, &mock_data_store, &read_cb); + kDummyOrigin, destroy_delegate_.GetWeakPtr(), &mock_data_store, &read_cb); local_site_data->NotifySiteLoaded(); local_site_data->NotifyLoadedSiteBackgrounded(); @@ -527,7 +528,7 @@ TEST_F(SiteDataImplTest, LateAsyncReadDoesntBypassClearEvent) { TEST_F(SiteDataImplTest, BackgroundedCountTests) { auto local_site_data = - GetDataImpl(kDummyOrigin, &destroy_delegate_, &data_store); + GetDataImpl(kDummyOrigin, destroy_delegate_.GetWeakPtr(), &data_store); // By default the tabs are expected to be foregrounded. EXPECT_EQ(0U, local_site_data->loaded_tabs_in_background_count_for_testing()); @@ -585,7 +586,7 @@ TEST_F(SiteDataImplTest, OptionalFieldsNotPopulatedWhenClean) { SiteDataStore::ReadSiteDataFromStoreCallback read_cb; auto local_site_data = GetDataImplAndInterceptReadCallback( - kDummyOrigin, &destroy_delegate_, &mock_data_store, &read_cb); + kDummyOrigin, destroy_delegate_.GetWeakPtr(), &mock_data_store, &read_cb); EXPECT_EQ(0u, local_site_data->cpu_usage_estimate().num_datums()); EXPECT_EQ(0u, local_site_data->private_footprint_kb_estimate().num_datums()); @@ -622,9 +623,9 @@ TEST_F(SiteDataImplTest, FlushingStateToProtoDoesntAffectData) { // calling FlushStateToProto doesn't affect the data that gets recorded. auto local_site_data = - GetDataImpl(kDummyOrigin, &destroy_delegate_, &data_store); + GetDataImpl(kDummyOrigin, destroy_delegate_.GetWeakPtr(), &data_store); auto local_site_data_ref = - GetDataImpl(kDummyOrigin2, &destroy_delegate_, &data_store); + GetDataImpl(kDummyOrigin2, destroy_delegate_.GetWeakPtr(), &data_store); local_site_data->NotifySiteLoaded(); local_site_data->NotifyLoadedSiteBackgrounded(); @@ -663,7 +664,7 @@ TEST_F(SiteDataImplTest, DataLoadedCallbackInvoked) { SiteDataStore::ReadSiteDataFromStoreCallback read_cb; auto local_site_data = GetDataImplAndInterceptReadCallback( - kDummyOrigin, &destroy_delegate_, &mock_data_store, &read_cb); + kDummyOrigin, destroy_delegate_.GetWeakPtr(), &mock_data_store, &read_cb); EXPECT_FALSE(local_site_data->DataLoaded()); diff --git a/components/performance_manager/persistence/site_data/site_data_reader_unittest.cc b/components/performance_manager/persistence/site_data/site_data_reader_unittest.cc index 7145a122c9..e3b85b5e6e 100644 --- a/components/performance_manager/persistence/site_data/site_data_reader_unittest.cc +++ b/components/performance_manager/persistence/site_data/site_data_reader_unittest.cc @@ -71,8 +71,9 @@ class SiteDataReaderTest : public ::testing::Test { // SiteDataImpl is protected and not visible to // base::MakeRefCounted. SiteDataReaderTest() { - test_impl_ = base::WrapRefCounted(new internal::SiteDataImpl( - url::Origin::Create(GURL("foo.com")), &delegate_, &data_store_)); + test_impl_ = base::WrapRefCounted( + new internal::SiteDataImpl(url::Origin::Create(GURL("foo.com")), + delegate_.GetWeakPtr(), &data_store_)); test_impl_->NotifySiteLoaded(); test_impl_->NotifyLoadedSiteBackgrounded(); SiteDataReader* reader = new SiteDataReader(test_impl_.get()); @@ -153,9 +154,9 @@ TEST_F(SiteDataReaderTest, FreeingReaderDoesntCauseWriteOperation) { ::testing::_)) .WillOnce(::testing::Invoke(read_from_store_mock_impl)); - std::unique_ptr reader = - base::WrapUnique(new SiteDataReader(base::WrapRefCounted( - new internal::SiteDataImpl(kOrigin, &delegate_, &data_store)))); + std::unique_ptr reader = base::WrapUnique( + new SiteDataReader(base::WrapRefCounted(new internal::SiteDataImpl( + kOrigin, delegate_.GetWeakPtr(), &data_store)))); ::testing::Mock::VerifyAndClear(&data_store); EXPECT_TRUE(reader->impl_for_testing()->fully_initialized_for_testing()); @@ -177,7 +178,7 @@ TEST_F(SiteDataReaderTest, OnDataLoadedCallbackInvoked) { kOrigin.Serialize()), ::testing::_)); scoped_refptr impl = base::WrapRefCounted( - new internal::SiteDataImpl(kOrigin, &delegate_, &data_store)); + new internal::SiteDataImpl(kOrigin, delegate_.GetWeakPtr(), &data_store)); // Create the reader. std::unique_ptr reader = @@ -208,7 +209,7 @@ TEST_F(SiteDataReaderTest, DestroyingReaderCancelsPendingCallbacks) { kOrigin.Serialize()), ::testing::_)); scoped_refptr impl = base::WrapRefCounted( - new internal::SiteDataImpl(kOrigin, &delegate_, &data_store)); + new internal::SiteDataImpl(kOrigin, delegate_.GetWeakPtr(), &data_store)); // Create the reader. std::unique_ptr reader = diff --git a/components/performance_manager/persistence/site_data/site_data_writer_unittest.cc b/components/performance_manager/persistence/site_data/site_data_writer_unittest.cc index 272089fd17..bc5500237b 100644 --- a/components/performance_manager/persistence/site_data/site_data_writer_unittest.cc +++ b/components/performance_manager/persistence/site_data/site_data_writer_unittest.cc @@ -24,7 +24,7 @@ class SiteDataWriterTest : public ::testing::Test { SiteDataWriterTest() : test_impl_(base::WrapRefCounted( new internal::SiteDataImpl(url::Origin::Create(GURL("foo.com")), - &delegate_, + delegate_.GetWeakPtr(), &data_store_))) { SiteDataWriter* writer = new SiteDataWriter(test_impl_.get()); writer_ = base::WrapUnique(writer); diff --git a/components/performance_manager/persistence/site_data/unittest_utils.h b/components/performance_manager/persistence/site_data/unittest_utils.h index a5451e4fb3..75d7d698e7 100644 --- a/components/performance_manager/persistence/site_data/unittest_utils.h +++ b/components/performance_manager/persistence/site_data/unittest_utils.h @@ -9,6 +9,7 @@ #include #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "components/performance_manager/performance_manager_impl.h" #include "components/performance_manager/persistence/site_data/site_data_impl.h" #include "components/performance_manager/persistence/site_data/site_data_store.h" @@ -27,7 +28,13 @@ class MockSiteDataImplOnDestroyDelegate MOCK_METHOD1(OnSiteDataImplDestroyed, void(internal::SiteDataImpl*)); + base::WeakPtr GetWeakPtr() { + return weak_factory_.GetWeakPtr(); + } + private: + base::WeakPtrFactory weak_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(MockSiteDataImplOnDestroyDelegate); }; diff --git a/components/permissions/permission_request_manager.cc b/components/permissions/permission_request_manager.cc index f3148d318d..f41c73a8fc 100644 --- a/components/permissions/permission_request_manager.cc +++ b/components/permissions/permission_request_manager.cc @@ -545,13 +545,13 @@ void PermissionRequestManager::ScheduleDequeueRequestIfNeeded() { } void PermissionRequestManager::ShowBubble() { - // There is a race condition where the request might have been removed already - // so double-checking that there is a request in progress (crbug.com/1041222). - if (!IsRequestInProgress()) + // There is a race condition where the request might have been removed + // already so double-checking that there is a request in progress. + // + // There is no need to show a new bubble if the previous one still exists. + if (!IsRequestInProgress() || view_) return; - DCHECK(!requests_.empty()); - DCHECK(!view_); DCHECK(web_contents()->IsDocumentOnLoadCompletedInMainFrame()); DCHECK(current_request_ui_to_use_); diff --git a/components/renderer_context_menu/render_view_context_menu_base.cc b/components/renderer_context_menu/render_view_context_menu_base.cc index bb98c91e7c..3250f7d556 100644 --- a/components/renderer_context_menu/render_view_context_menu_base.cc +++ b/components/renderer_context_menu/render_view_context_menu_base.cc @@ -466,9 +466,14 @@ void RenderViewContextMenuBase::OpenURLWithExtraHeaders( ui::PageTransition transition, const std::string& extra_headers, bool started_from_context_menu) { + // Do not send the referrer url to OTR windows. We still need the + // |referring_url| to populate the |initiator_origin| below for browser UI. + GURL referrer_url; + if (disposition != WindowOpenDisposition::OFF_THE_RECORD) + referrer_url = referring_url.GetAsReferrer(); + content::Referrer referrer = content::Referrer::SanitizeForRequest( - url, content::Referrer(referring_url.GetAsReferrer(), - params_.referrer_policy)); + url, content::Referrer(referrer_url, params_.referrer_policy)); if (params_.link_url == url && disposition != WindowOpenDisposition::OFF_THE_RECORD) diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc index 9974db23eb..50ac01b8f5 100644 --- a/content/app/content_main_runner_impl.cc +++ b/content/app/content_main_runner_impl.cc @@ -106,6 +106,7 @@ #include "ui/base/ui_base_switches.h" #include "ui/display/display_switches.h" #include "ui/gfx/switches.h" +#include "content/renderer/render_remote_proxy.h" #if defined(OS_WIN) #include @@ -909,6 +910,11 @@ int ContentMainRunnerImpl::Run(bool start_minimal_browser) { if (process_type != switches::kZygoteProcess) { // Zygotes will run this at a later point in time when the command line // has been updated. +#if defined(OS_OHOS) + if (!RunRenderRemoteProxy(command_line)) { + return -1; + } +#endif InitializeFieldTrialAndFeatureList(); delegate_->PostFieldTrialInitialization(); @@ -1068,6 +1074,22 @@ int ContentMainRunnerImpl::RunBrowser(MainFunctionParams& main_params, return RunBrowserProcessMain(main_params, delegate_); } +#if defined(OS_OHOS) +bool ContentMainRunnerImpl::RunRenderRemoteProxy( + const base::CommandLine& command_line) { + std::string process_type = + command_line.GetSwitchValueASCII(switches::kProcessType); + if (process_type != switches::kRendererProcess) { + return true; + } + RenderRemoteProxy::CreateAndRegist(command_line); + if (!RenderRemoteProxy::WaitForBrowserFd()) { + return false; + } + return true; +} +#endif + void ContentMainRunnerImpl::Shutdown() { DCHECK(is_initialized_); DCHECK(!is_shutdown_); diff --git a/content/app/content_main_runner_impl.h b/content/app/content_main_runner_impl.h index 090171f7db..6bef22cb2f 100644 --- a/content/app/content_main_runner_impl.h +++ b/content/app/content_main_runner_impl.h @@ -58,6 +58,9 @@ class CONTENT_EXPORT ContentMainRunnerImpl : public ContentMainRunner { private: int RunBrowser(MainFunctionParams& main_function_params, bool start_minimal_browser); +#if defined(OS_OHOS) + bool RunRenderRemoteProxy(const base::CommandLine& command_line); +#endif bool is_browser_main_loop_started_ = false; diff --git a/content/browser/background_fetch/background_fetch_cross_origin_filter.cc b/content/browser/background_fetch/background_fetch_cross_origin_filter.cc index 50d79fe628..1fcc93ffdd 100644 --- a/content/browser/background_fetch/background_fetch_cross_origin_filter.cc +++ b/content/browser/background_fetch/background_fetch_cross_origin_filter.cc @@ -7,6 +7,7 @@ #include #include "base/strings/string_split.h" +#include "base/strings/string_util.h" #include "content/browser/background_fetch/background_fetch_request_info.h" #include "url/gurl.h" @@ -15,6 +16,8 @@ namespace content { namespace { const char kAccessControlAllowOriginHeader[] = "access-control-allow-origin"; +const char kAccessControlAllowCredentialsHeader[] = + "access-control-allow-credentials"; const char kAnyOriginValue[] = "*"; // Parses the header list (including "any origin") value from a given response @@ -67,20 +70,29 @@ BackgroundFetchCrossOriginFilter::BackgroundFetchCrossOriginFilter( response_header_map.find(kAccessControlAllowOriginHeader); if (access_control_allow_origin_iter != response_header_map.end()) { - bool access_control_allow_any_origin = false; std::set access_control_allow_origins; if (ParseOriginListHeader(access_control_allow_origin_iter->second, - &access_control_allow_any_origin, + &access_control_allow_origin_any_, &access_control_allow_origins)) { - access_control_allow_origin_ = - access_control_allow_any_origin || + access_control_allow_origin_exact_ = access_control_allow_origins.count(source_origin) == 1; } } - // TODO(crbug.com/711354): Consider the Access-Control-Allow-Credentials - // header. + // Access-Control-Allow-Credentials checks. The header's values must be valid + // for it to not be completely discarded. + auto access_control_allow_credentials_iter = + response_header_map.find(kAccessControlAllowCredentialsHeader); + if (access_control_allow_credentials_iter != response_header_map.end()) { + access_control_allow_credentials_ = + base::ToLowerASCII(access_control_allow_credentials_iter->second) == + "true"; + } + + include_credentials_ = request.fetch_request()->credentials_mode == + ::network::mojom::CredentialsMode::kInclude; + // TODO(crbug.com/711354): Consider the Access-Control-Allow-Headers header. // TODO(crbug.com/711354): Consider the Access-Control-Allow-Methods header. // TODO(crbug.com/711354): Consider the Access-Control-Expose-Headers header. @@ -89,12 +101,28 @@ BackgroundFetchCrossOriginFilter::BackgroundFetchCrossOriginFilter( BackgroundFetchCrossOriginFilter::~BackgroundFetchCrossOriginFilter() = default; bool BackgroundFetchCrossOriginFilter::CanPopulateBody() const { - // The body will be populated if: - // (1) The source and the response share their origin. - // (2) The Access-Control-Allow-Origin method allows any origin. - // (3) The Access-Control-Allow-Origin method allows the source origin. + if (is_same_origin_) { + // Same origin requests are always OK. + return true; + } + + // For cross-origin requests, the body will be populated if: + + // (1) The Access-Control-Allow-Origin method allows the source origin / any + // origin. + if (!access_control_allow_origin_exact_ && + !access_control_allow_origin_any_) { + return false; + } + + // (2) For requests with credentials, the Access-Control-Allow-Credentials is + // set and the Access-Control-Allow-Origin contains the exact origin. + if (include_credentials_ && (!access_control_allow_credentials_ || + !access_control_allow_origin_exact_)) { + return false; + } - return is_same_origin_ || access_control_allow_origin_; + return true; } } // namespace content diff --git a/content/browser/background_fetch/background_fetch_cross_origin_filter.h b/content/browser/background_fetch/background_fetch_cross_origin_filter.h index 042856bb56..20e14c2240 100644 --- a/content/browser/background_fetch/background_fetch_cross_origin_filter.h +++ b/content/browser/background_fetch/background_fetch_cross_origin_filter.h @@ -32,8 +32,19 @@ class CONTENT_EXPORT BackgroundFetchCrossOriginFilter { // Whether the response comes from the same origin as the requester. bool is_same_origin_ = false; - // Whether the Access-Control-Allow-Origin header includes the source origin. - bool access_control_allow_origin_ = false; + // Whether the Access-Control-Allow-Origin header includes the exact source + // origin. + bool access_control_allow_origin_exact_ = false; + + // Whether the Access-Control-Allow-Origin header includes any source origin + // (*). + bool access_control_allow_origin_any_ = false; + + // Whether the Access-Control-Allow-Credentials header is included. + bool access_control_allow_credentials_ = false; + + // Whether credentials were included for cross-origin requests. + bool include_credentials_ = false; DISALLOW_COPY_AND_ASSIGN(BackgroundFetchCrossOriginFilter); }; diff --git a/content/browser/background_fetch/background_fetch_cross_origin_filter_unittest.cc b/content/browser/background_fetch/background_fetch_cross_origin_filter_unittest.cc index ace470460c..7c5e41055e 100644 --- a/content/browser/background_fetch/background_fetch_cross_origin_filter_unittest.cc +++ b/content/browser/background_fetch/background_fetch_cross_origin_filter_unittest.cc @@ -20,6 +20,8 @@ const char kFirstOriginFile[] = "https://example.com/cat.jpg"; const char kSecondOriginFile[] = "https://chrome.com/cat.jpg"; const char kAccessControlAllowOriginHeader[] = "access-control-allow-origin"; +const char kAccessControlAllowCredentialsHeader[] = + "access-control-allow-credentials"; class BackgroundFetchCrossOriginFilterTest : public ::testing::Test { public: @@ -35,7 +37,8 @@ class BackgroundFetchCrossOriginFilterTest : public ::testing::Test { const char* response_url, std::initializer_list< typename std::map::value_type> - response_headers) { + response_headers, + bool allow_credentials = false) { scoped_refptr request_info = base::MakeRefCounted( 0 /* request_info */, blink::mojom::FetchAPIRequest::New(), @@ -43,6 +46,13 @@ class BackgroundFetchCrossOriginFilterTest : public ::testing::Test { request_info->response_headers_ = response_headers; request_info->url_chain_ = {GURL(response_url)}; + if (allow_credentials) { + request_info->fetch_request()->credentials_mode = + network::mojom::CredentialsMode::kInclude; + } else { + request_info->fetch_request()->credentials_mode = + network::mojom::CredentialsMode::kSameOrigin; + } return request_info; } @@ -113,4 +123,54 @@ TEST_F(BackgroundFetchCrossOriginFilterTest, CrossOriginAllowSpecificOrigin) { } } +TEST_F(BackgroundFetchCrossOriginFilterTest, CrossOriginCredentials) { + // 1: No headers. + { + auto request = + CreateRequestInfo(kSecondOriginFile, {}, /*include_credentials=*/true); + BackgroundFetchCrossOriginFilter filter(source_, *request); + EXPECT_FALSE(filter.CanPopulateBody()); + } + + // 2: Valid request. + { + auto request = + CreateRequestInfo(kSecondOriginFile, + {{kAccessControlAllowOriginHeader, kFirstOrigin}, + {kAccessControlAllowCredentialsHeader, "true"}}, + /*include_credentials=*/true); + BackgroundFetchCrossOriginFilter filter(source_, *request); + EXPECT_TRUE(filter.CanPopulateBody()); + } + + // 3: Missing ACAO Header. + { + auto request = CreateRequestInfo( + kSecondOriginFile, {{kAccessControlAllowCredentialsHeader, "true"}}, + /*include_credentials=*/true); + BackgroundFetchCrossOriginFilter filter(source_, *request); + EXPECT_FALSE(filter.CanPopulateBody()); + } + + // 4: Missing ACAC header. + { + auto request = CreateRequestInfo( + kSecondOriginFile, {{kAccessControlAllowOriginHeader, kFirstOrigin}}, + /*include_credentials=*/true); + BackgroundFetchCrossOriginFilter filter(source_, *request); + EXPECT_FALSE(filter.CanPopulateBody()); + } + + // 5: ACAO any origin. + { + auto request = + CreateRequestInfo(kSecondOriginFile, + {{kAccessControlAllowOriginHeader, "*"}, + {kAccessControlAllowCredentialsHeader, "true"}}, + /*include_credentials=*/true); + BackgroundFetchCrossOriginFilter filter(source_, *request); + EXPECT_FALSE(filter.CanPopulateBody()); + } +} + } // namespace content diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy.cc b/content/browser/background_fetch/background_fetch_delegate_proxy.cc index 7fdbb99fbc..efcbcfcc19 100644 --- a/content/browser/background_fetch/background_fetch_delegate_proxy.cc +++ b/content/browser/background_fetch/background_fetch_delegate_proxy.cc @@ -160,7 +160,8 @@ class BackgroundFetchDelegateProxy::Core delegate->DownloadUrl( job_unique_id, request->download_guid(), fetch_request->method, - fetch_request->url, traffic_annotation, headers, + fetch_request->url, fetch_request->credentials_mode, traffic_annotation, + headers, /* has_request_body= */ request->request_body_size() > 0u); } diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc b/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc index 9564453073..3a1d773294 100644 --- a/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc +++ b/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc @@ -55,6 +55,7 @@ class FakeBackgroundFetchDelegate : public BackgroundFetchDelegate { const std::string& guid, const std::string& method, const GURL& url, + ::network::mojom::CredentialsMode credentials_mode, const net::NetworkTrafficAnnotationTag& traffic_annotation, const net::HttpRequestHeaders& headers, bool has_request_body) override { diff --git a/content/browser/background_fetch/background_fetch_job_controller.cc b/content/browser/background_fetch/background_fetch_job_controller.cc index f424cadba0..0d08d1f744 100644 --- a/content/browser/background_fetch/background_fetch_job_controller.cc +++ b/content/browser/background_fetch/background_fetch_job_controller.cc @@ -173,6 +173,8 @@ void BackgroundFetchJobController::DidStartRequest( // TODO(crbug.com/884672): Stop the fetch if the cross origin filter fails. BackgroundFetchCrossOriginFilter filter(registration_id_.origin(), *request); request->set_can_populate_body(filter.CanPopulateBody()); + if (!request->can_populate_body()) + has_failed_cors_request_ = true; } void BackgroundFetchJobController::DidUpdateRequest(const std::string& guid, @@ -253,7 +255,14 @@ uint64_t BackgroundFetchJobController::GetInProgressUploadedBytes() { void BackgroundFetchJobController::AbortFromDelegate( BackgroundFetchFailureReason failure_reason) { - failure_reason_ = failure_reason; + if (failure_reason == BackgroundFetchFailureReason::DOWNLOAD_TOTAL_EXCEEDED && + has_failed_cors_request_) { + // Don't expose that the download total has been exceeded. Use a less + // specific error. + failure_reason_ = BackgroundFetchFailureReason::FETCH_ERROR; + } else { + failure_reason_ = failure_reason; + } Finish(failure_reason_, base::DoNothing()); } diff --git a/content/browser/background_fetch/background_fetch_job_controller.h b/content/browser/background_fetch/background_fetch_job_controller.h index e635c86c1e..66a1c94e9d 100644 --- a/content/browser/background_fetch/background_fetch_job_controller.h +++ b/content/browser/background_fetch/background_fetch_job_controller.h @@ -210,6 +210,10 @@ class CONTENT_EXPORT BackgroundFetchJobController blink::mojom::BackgroundFetchFailureReason failure_reason_ = blink::mojom::BackgroundFetchFailureReason::NONE; + // Whether one of the requests handled by the controller failed + // the CORS checks and should not have its response exposed. + bool has_failed_cors_request_ = false; + // Custom callback that runs after the controller is finished. FinishedCallback finished_callback_; diff --git a/content/browser/background_fetch/background_fetch_job_controller_unittest.cc b/content/browser/background_fetch/background_fetch_job_controller_unittest.cc index ad9a313672..eb0e8fc337 100644 --- a/content/browser/background_fetch/background_fetch_job_controller_unittest.cc +++ b/content/browser/background_fetch/background_fetch_job_controller_unittest.cc @@ -433,6 +433,39 @@ TEST_F(BackgroundFetchJobControllerTest, Abort) { GetCompletionStatus(registration_id)); } +TEST_F(BackgroundFetchJobControllerTest, AbortDownloadExceededCrossOrigin) { + BackgroundFetchRegistrationId registration_id; + + auto requests = CreateRegistrationForRequests( + ®istration_id, {{GURL("https://example2.com/funny_cat.png"), "GET"}}, + /* auto_complete_requests= */ true); + + EXPECT_EQ(JobCompletionStatus::kRunning, + GetCompletionStatus(registration_id)); + + std::unique_ptr controller = + CreateJobController(registration_id, requests.size()); + + controller->StartRequest(requests[0], base::DoNothing()); + + controller->DidStartRequest( + requests[0]->download_guid(), + std::make_unique( + std::vector{GURL("https://example2.com/funny_cat.png")}, + nullptr)); + EXPECT_FALSE(requests[0]->can_populate_body()); + + controller->AbortFromDelegate( + blink::mojom::BackgroundFetchFailureReason::DOWNLOAD_TOTAL_EXCEEDED); + + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(JobCompletionStatus::kAborted, + GetCompletionStatus(registration_id)); + EXPECT_EQ(finished_requests_[registration_id], + blink::mojom::BackgroundFetchFailureReason::FETCH_ERROR); +} + TEST_F(BackgroundFetchJobControllerTest, Progress) { BackgroundFetchRegistrationId registration_id; diff --git a/content/browser/background_fetch/mock_background_fetch_delegate.cc b/content/browser/background_fetch/mock_background_fetch_delegate.cc index 4ebfb985b7..c4bbfe9f43 100644 --- a/content/browser/background_fetch/mock_background_fetch_delegate.cc +++ b/content/browser/background_fetch/mock_background_fetch_delegate.cc @@ -88,6 +88,7 @@ void MockBackgroundFetchDelegate::DownloadUrl( const std::string& guid, const std::string& method, const GURL& url, + ::network::mojom::CredentialsMode credentials_mode, const net::NetworkTrafficAnnotationTag& traffic_annotation, const net::HttpRequestHeaders& headers, bool has_request_body) { diff --git a/content/browser/background_fetch/mock_background_fetch_delegate.h b/content/browser/background_fetch/mock_background_fetch_delegate.h index 499bca6eb7..8796655b9c 100644 --- a/content/browser/background_fetch/mock_background_fetch_delegate.h +++ b/content/browser/background_fetch/mock_background_fetch_delegate.h @@ -80,6 +80,7 @@ class MockBackgroundFetchDelegate : public BackgroundFetchDelegate { const std::string& guid, const std::string& method, const GURL& url, + ::network::mojom::CredentialsMode credentials_mode, const net::NetworkTrafficAnnotationTag& traffic_annotation, const net::HttpRequestHeaders& headers, bool has_request_body) override; diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h index c27331d1cb..583e54e218 100644 --- a/content/browser/bad_message.h +++ b/content/browser/bad_message.h @@ -268,6 +268,7 @@ enum BadMessageReason { WCI_INVALID_FULLSCREEN_OPTIONS = 240, PAYMENTS_WITHOUT_PERMISSION = 241, WEB_BUNDLE_INVALID_NAVIGATION_URL = 242, + RFH_CREATE_CHILD_FRAME_SANDBOX_FLAGS = 254, // Please add new elements here. The naming convention is abbreviated class // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the diff --git a/content/browser/blob_storage/blob_url_unittest.cc b/content/browser/blob_storage/blob_url_unittest.cc index 0a7e8fb928..9c2bac10bb 100644 --- a/content/browser/blob_storage/blob_url_unittest.cc +++ b/content/browser/blob_storage/blob_url_unittest.cc @@ -182,15 +182,14 @@ class BlobURLTest : public testing::Test { void TestRequest(const std::string& method, const net::HttpRequestHeaders& extra_headers) { - GURL url("blob:blah"); + auto origin = url::Origin::Create(GURL("https://example.com")); + auto url = GURL("blob:" + origin.Serialize() + "/id1"); network::ResourceRequest request; request.url = url; request.method = method; request.headers = extra_headers; - storage::MockBlobRegistryDelegate delegate; - storage::BlobURLStoreImpl url_store(blob_url_registry_.AsWeakPtr(), - &delegate); + storage::BlobURLStoreImpl url_store(origin, blob_url_registry_.AsWeakPtr()); mojo::PendingRemote blob_remote; storage::BlobImpl::Create( diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc index 9c39184123..d0073ca0c8 100644 --- a/content/browser/browser_child_process_host_impl.cc +++ b/content/browser/browser_child_process_host_impl.cc @@ -672,6 +672,9 @@ void BrowserChildProcessHostImpl::RegisterCoordinatorClient( mojo::PendingReceiver receiver, mojo::PendingRemote client_process) { + // Intentionally disallow non-browser processes from getting a Coordinator. + receiver.reset(); + // The child process may have already terminated by the time this message is // dispatched. We do nothing in that case. if (!IsProcessLaunched()) diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc index 141a96c2ef..8ba6265041 100644 --- a/content/browser/browser_interface_binders.cc +++ b/content/browser/browser_interface_binders.cc @@ -377,10 +377,22 @@ void BindTextSuggestionHostForFrame( } #endif +// Get the service worker's worker process ID and post a task to bind the +// receiver on a USER_VISIBLE task runner. +// This is necessary because: +// - Binding the host itself and checking the ID on the task's thread may cause +// a UAF if the host has been deleted in the meantime. +// - The process ID is not yet populated at the time `PopulateInterfaceBinders` +// is called. void BindFileUtilitiesHost( - const ServiceWorkerHost* host, + ServiceWorkerHost* host, mojo::PendingReceiver receiver) { - FileUtilitiesHostImpl::Create(host->worker_process_id(), std::move(receiver)); + auto task_runner = base::ThreadPool::CreateSequencedTaskRunner( + {base::MayBlock(), base::TaskPriority::USER_VISIBLE}); + task_runner->PostTask( + FROM_HERE, + base::BindOnce(&FileUtilitiesHostImpl::Create, host->worker_process_id(), + std::move(receiver))); } template @@ -1166,9 +1178,7 @@ void PopulateServiceWorkerBinders(ServiceWorkerHost* host, // static binders map->Add( - base::BindRepeating(&BindFileUtilitiesHost, host), - base::ThreadPool::CreateSequencedTaskRunner( - {base::MayBlock(), base::TaskPriority::USER_VISIBLE})); + base::BindRepeating(&BindFileUtilitiesHost, host)); map->Add( base::BindRepeating(&BindBarcodeDetectionProvider)); map->Add( diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc index 634d72af38..c5be9cd6e5 100644 --- a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc +++ b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc @@ -446,10 +446,10 @@ blink::mojom::FetchAPIResponsePtr CreateResponse( padding = storage::ComputeRandomResponsePadding(); } - // Note that |has_range_requested| can be safely set to false since it only - // affects HTTP 206 (Partial) responses, which are blocked from cache storage. - // See https://fetch.spec.whatwg.org/#main-fetch for usage of - // |has_range_requested|. + // While we block most partial responses from being stored, we can have + // partial responses for bgfetch or opaque responses. + bool has_range_requested = headers.contains(net::HttpRequestHeaders::kRange); + return blink::mojom::FetchAPIResponse::New( url_list, metadata.response().status_code(), metadata.response().status_text(), @@ -467,7 +467,7 @@ blink::mojom::FetchAPIResponsePtr CreateResponse( static_cast( metadata.response().connection_info()), alpn_negotiated_protocol, metadata.response().was_fetched_via_spdy(), - /*has_range_requested=*/false, /*auth_challenge_info=*/base::nullopt); + has_range_requested, /*auth_challenge_info=*/base::nullopt); } int64_t CalculateSideDataPadding( @@ -1907,7 +1907,13 @@ void LegacyCacheStorageCache::PutDidCreateEntry( } proto::CacheResponse* response_metadata = metadata.mutable_response(); - DCHECK_NE(put_context->response->status_code, net::HTTP_PARTIAL_CONTENT); + if (owner_ != storage::mojom::CacheStorageOwner::kBackgroundFetch && + put_context->response->response_type != + network::mojom::FetchResponseType::kOpaque && + put_context->response->response_type != + network::mojom::FetchResponseType::kOpaqueRedirect) { + DCHECK_NE(put_context->response->status_code, net::HTTP_PARTIAL_CONTENT); + } response_metadata->set_status_code(put_context->response->status_code); response_metadata->set_status_text(put_context->response->status_text); response_metadata->set_response_type(FetchResponseTypeToProtoResponseType( diff --git a/content/browser/child_process_launcher_helper.h b/content/browser/child_process_launcher_helper.h index 532b80efe9..7b78341112 100644 --- a/content/browser/child_process_launcher_helper.h +++ b/content/browser/child_process_launcher_helper.h @@ -47,6 +47,10 @@ #include "content/public/common/zygote/zygote_handle.h" // nogncheck #endif +#if defined(OS_OHOS) +#include "appmgr/app_mgr_client.h" +#endif + namespace base { class CommandLine; } @@ -252,6 +256,10 @@ class ChildProcessLauncherHelper : #if defined(OS_FUCHSIA) std::unique_ptr sandbox_policy_; #endif + +#if defined(OS_OHOS) + std::unique_ptr app_mgr_client_{nullptr}; +#endif }; } // namespace internal diff --git a/content/browser/child_process_launcher_helper_linux.cc b/content/browser/child_process_launcher_helper_linux.cc index 7efc41048b..422d3a0183 100644 --- a/content/browser/child_process_launcher_helper_linux.cc +++ b/content/browser/child_process_launcher_helper_linux.cc @@ -99,7 +99,37 @@ ChildProcessLauncherHelper::LaunchProcessOnLauncherThread( } Process process; +#if defined(OS_OHOS) + bool for_test = base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kForTest); + if (for_test) { + process.process = base::LaunchProcess(*command_line(), options); + } else { + const std::vector argv_str = command_line()->argv(); + std::stringstream argv_ss; + const char separator = '#'; + for (int i=0; i(); + } + int ret = app_mgr_client_->StartRenderProcess(argv_ss.str(), ipc_fd, shared_fd, render_pid); + if (ret != 0) { + LOG(ERROR) << "start render process error, ret=" << ret << ", render pid=" << render_pid; + process.process = base::Process(); + } else { + process.process = base::Process(render_pid); + } + } +#else process.process = base::LaunchProcess(*command_line(), options); +#endif *launch_result = process.process.IsValid() ? LAUNCH_RESULT_SUCCESS : LAUNCH_RESULT_FAILURE; return process; diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc index 3c3fcebab8..fcfe6a0722 100644 --- a/content/browser/download/download_browsertest.cc +++ b/content/browser/download/download_browsertest.cc @@ -3596,6 +3596,53 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, UpdateSiteForCookies) { site_a.GetURL("a.test", "/"))); } +// Verifies that isolation info set in DownloadUrlParameters can be populated. +IN_PROC_BROWSER_TEST_F(DownloadContentTest, + SiteForCookies_DownloadUrl_IsolationInfoPopulated) { + // Setup a server that sets cookie. + net::EmbeddedTestServer site_a; + base::StringPairs cookie_headers; + cookie_headers.push_back(std::make_pair(std::string("Set-Cookie"), + std::string("A=lax; SameSite=Lax"))); + cookie_headers.push_back(std::make_pair( + std::string("Set-Cookie"), std::string("B=strict; SameSite=Strict"))); + site_a.RegisterRequestHandler(CreateBasicResponseHandler( + "/sets-samesite-cookies", net::HTTP_OK, cookie_headers, + "application/octet-stream", "abcd")); + ASSERT_TRUE(site_a.Start()); + + // Download the file. + SetupEnsureNoPendingDownloads(); + GURL download_url = site_a.GetURL("a.test", "/sets-samesite-cookies"); + std::unique_ptr download_parameters( + DownloadRequestUtils::CreateDownloadForWebContentsMainFrame( + shell()->web_contents(), download_url, TRAFFIC_ANNOTATION_FOR_TESTS)); + + // Mark this request a third party request, cookie should be blocked. + net::IsolationInfo isolation_info = + net::IsolationInfo::CreateForInternalRequest( + url::Origin::Create(GURL("http://www.example.com"))); + download_parameters->set_isolation_info(isolation_info); + + // Verify the isolation info. + std::unique_ptr observer(CreateWaiter(shell(), 1)); + ExpectRequestIsolationInfo(download_url, isolation_info, + base::BindLambdaForTesting([&]() { + DownloadManagerForShell(shell())->DownloadUrl( + std::move(download_parameters)); + observer->WaitForFinished(); + })); + + // Get the important info from other threads and check it. + EXPECT_TRUE(EnsureNoPendingDownloads()); + + // Check no cookies are written for URL a.test since it's a third party + // cookie. + EXPECT_TRUE(content::GetCookies(shell()->web_contents()->GetBrowserContext(), + download_url) + .empty()); +} + // A filename suggestion specified via a @download attribute should not be // effective if the final download URL is in another origin from the original // download URL. diff --git a/content/browser/download/download_manager_impl.h b/content/browser/download/download_manager_impl.h index 69fcf9abbe..0deb3b7c77 100644 --- a/content/browser/download/download_manager_impl.h +++ b/content/browser/download/download_manager_impl.h @@ -170,6 +170,11 @@ class CONTENT_EXPORT DownloadManagerImpl int frame_tree_node_id, bool from_download_cross_origin_redirect); + // DownloadItemImplDelegate overrides. + download::QuarantineConnectionCallback GetQuarantineConnectionCallback() + override; + std::string GetApplicationClientIdForFileScanning() const override; + private: using DownloadSet = std::set; using DownloadGuidMap = @@ -237,7 +242,6 @@ class CONTENT_EXPORT DownloadManagerImpl bool ShouldOpenDownload(download::DownloadItemImpl* item, ShouldOpenDownloadCallback callback) override; void CheckForFileRemoval(download::DownloadItemImpl* download_item) override; - std::string GetApplicationClientIdForFileScanning() const override; void ResumeInterruptedDownload( std::unique_ptr params, const GURL& site_url) override; @@ -249,8 +253,6 @@ class CONTENT_EXPORT DownloadManagerImpl void ReportBytesWasted(download::DownloadItemImpl* download) override; void BindWakeLockProvider( mojo::PendingReceiver receiver) override; - download::QuarantineConnectionCallback GetQuarantineConnectionCallback() - override; std::unique_ptr GetRenameHandlerForDownload( download::DownloadItemImpl* download_item) override; diff --git a/content/browser/download/save_file.cc b/content/browser/download/save_file.cc index 72331e60fc..110f66250e 100644 --- a/content/browser/download/save_file.cc +++ b/content/browser/download/save_file.cc @@ -63,10 +63,15 @@ void SaveFile::Finish() { file_.Finish(); } -void SaveFile::AnnotateWithSourceInformation() { - // TODO(gbillock): If this method is called, it should set the - // file_.SetClientGuid() method first. - NOTREACHED(); +void SaveFile::AnnotateWithSourceInformation( + const std::string& client_guid, + const GURL& source_url, + const GURL& referrer_url, + mojo::PendingRemote remote_quarantine, + download::BaseFile::OnAnnotationDoneCallback on_annotation_done_callback) { + file_.AnnotateWithSourceInformation(client_guid, source_url, referrer_url, + std::move(remote_quarantine), + std::move(on_annotation_done_callback)); } base::FilePath SaveFile::FullPath() const { diff --git a/content/browser/download/save_file.h b/content/browser/download/save_file.h index 688574b07f..1893a0031f 100644 --- a/content/browser/download/save_file.h +++ b/content/browser/download/save_file.h @@ -34,7 +34,12 @@ class SaveFile { void Detach(); void Cancel(); void Finish(); - void AnnotateWithSourceInformation(); + void AnnotateWithSourceInformation( + const std::string& client_guid, + const GURL& source_url, + const GURL& referrer_url, + mojo::PendingRemote remote_quarantine, + download::BaseFile::OnAnnotationDoneCallback on_annotation_done_callback); base::FilePath FullPath() const; bool InProgress() const; int64_t BytesSoFar() const; diff --git a/content/browser/download/save_file_manager.cc b/content/browser/download/save_file_manager.cc index 91786d976f..2489b47cf8 100644 --- a/content/browser/download/save_file_manager.cc +++ b/content/browser/download/save_file_manager.cc @@ -50,6 +50,7 @@ static SaveFileManager* g_save_file_manager = nullptr; class SaveFileManager::SimpleURLLoaderHelper : public network::SimpleURLLoaderStreamConsumer { public: + using URLLoaderCompleteCallback = base::OnceCallback; static std::unique_ptr CreateAndStartDownload( std::unique_ptr resource_request, SaveItemId save_item_id, @@ -58,11 +59,12 @@ class SaveFileManager::SimpleURLLoaderHelper int render_frame_routing_id, const net::NetworkTrafficAnnotationTag& annotation_tag, network::mojom::URLLoaderFactory* url_loader_factory, - SaveFileManager* save_file_manager) { + SaveFileManager* save_file_manager, + URLLoaderCompleteCallback on_complete_cb) { return std::unique_ptr(new SimpleURLLoaderHelper( std::move(resource_request), save_item_id, save_package_id, render_process_id, render_frame_routing_id, annotation_tag, - url_loader_factory, save_file_manager)); + url_loader_factory, save_file_manager, std::move(on_complete_cb))); } ~SimpleURLLoaderHelper() override = default; @@ -76,10 +78,12 @@ class SaveFileManager::SimpleURLLoaderHelper int render_frame_routing_id, const net::NetworkTrafficAnnotationTag& annotation_tag, network::mojom::URLLoaderFactory* url_loader_factory, - SaveFileManager* save_file_manager) + SaveFileManager* save_file_manager, + URLLoaderCompleteCallback on_complete_cb) : save_file_manager_(save_file_manager), save_item_id_(save_item_id), - save_package_id_(save_package_id) { + save_package_id_(save_package_id), + on_complete_cb_(std::move(on_complete_cb)) { GURL url = resource_request->url; url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request), annotation_tag); @@ -124,9 +128,7 @@ class SaveFileManager::SimpleURLLoaderHelper void OnComplete(bool success) override { download::GetDownloadTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(&SaveFileManager::SaveFinished, save_file_manager_, - save_item_id_, save_package_id_, success)); + FROM_HERE, base::BindOnce(std::move(on_complete_cb_), success)); } void OnRetry(base::OnceClosure start_retry) override { @@ -138,6 +140,7 @@ class SaveFileManager::SimpleURLLoaderHelper SaveItemId save_item_id_; SavePackageId save_package_id_; std::unique_ptr url_loader_; + URLLoaderCompleteCallback on_complete_cb_; DISALLOW_COPY_AND_ASSIGN(SimpleURLLoaderHelper); }; @@ -188,17 +191,20 @@ SavePackage* SaveFileManager::LookupPackage(SaveItemId save_item_id) { } // Call from SavePackage for starting a saving job -void SaveFileManager::SaveURL(SaveItemId save_item_id, - const GURL& url, - const Referrer& referrer, - int render_process_host_id, - int render_view_routing_id, - int render_frame_routing_id, - SaveFileCreateInfo::SaveFileSource save_source, - const base::FilePath& file_full_path, - BrowserContext* context, - StoragePartition* storage_partition, - SavePackage* save_package) { +void SaveFileManager::SaveURL( + SaveItemId save_item_id, + const GURL& url, + const Referrer& referrer, + int render_process_host_id, + int render_view_routing_id, + int render_frame_routing_id, + SaveFileCreateInfo::SaveFileSource save_source, + const base::FilePath& file_full_path, + BrowserContext* context, + StoragePartition* storage_partition, + SavePackage* save_package, + const std::string& client_guid, + mojo::PendingRemote remote_quarantine) { DCHECK_CURRENTLY_ON(BrowserThread::UI); // Insert started saving job to tracking list. @@ -285,11 +291,18 @@ void SaveFileManager::SaveURL(SaveItemId save_item_id, factory = storage_partition->GetURLLoaderFactoryForBrowserProcess().get(); } + base::OnceCallback save_finished_cb = + base::BindOnce(&SaveFileManager::OnURLLoaderComplete, this, + save_item_id, save_package->id(), + context->IsOffTheRecord() ? GURL() : url, + context->IsOffTheRecord() ? GURL() : referrer.url, + client_guid, std::move(remote_quarantine)); + url_loader_helpers_[save_item_id] = SimpleURLLoaderHelper::CreateAndStartDownload( std::move(request), save_item_id, save_package->id(), render_process_host_id, render_frame_routing_id, traffic_annotation, - factory, this); + factory, this, std::move(save_finished_cb)); } else { // We manually start the save job. auto info = std::make_unique( @@ -344,6 +357,36 @@ void SaveFileManager::SendCancelRequest(SaveItemId save_item_id) { base::BindOnce(&SaveFileManager::CancelSave, this, save_item_id)); } +void SaveFileManager::OnURLLoaderComplete( + SaveItemId save_item_id, + SavePackageId save_package_id, + const GURL& url, + const GURL& referrer_url, + const std::string& client_guid, + mojo::PendingRemote remote_quarantine, + bool is_success) { + DCHECK(download::GetDownloadTaskRunner()->RunsTasksInCurrentSequence()); + SaveFile* save_file = LookupSaveFile(save_item_id); + if (!is_success || !save_file) { + SaveFinished(save_item_id, save_package_id, is_success); + return; + } + + save_file->AnnotateWithSourceInformation( + client_guid, url, referrer_url, std::move(remote_quarantine), + base::BindOnce(&SaveFileManager::OnQuarantineComplete, this, save_item_id, + save_package_id)); +} + +void SaveFileManager::OnQuarantineComplete( + SaveItemId save_item_id, + SavePackageId save_package_id, + download::DownloadInterruptReason result) { + DCHECK(download::GetDownloadTaskRunner()->RunsTasksInCurrentSequence()); + SaveFinished(save_item_id, save_package_id, + result == download::DOWNLOAD_INTERRUPT_REASON_NONE); +} + // Notifications sent from the IO thread and run on the file thread: // The IO thread created |info|, but the file thread (this method) uses it diff --git a/content/browser/download/save_file_manager.h b/content/browser/download/save_file_manager.h index 51eb63a9b1..0d4290b273 100644 --- a/content/browser/download/save_file_manager.h +++ b/content/browser/download/save_file_manager.h @@ -61,6 +61,8 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "components/download/public/common/download_interrupt_reasons.h" +#include "components/services/quarantine/quarantine.h" #include "content/browser/download/save_types.h" #include "content/common/content_export.h" @@ -90,17 +92,20 @@ class CONTENT_EXPORT SaveFileManager // Saves the specified URL |url|. |save_package| must not be deleted before // the call to RemoveSaveFile. Should be called on the UI thread, - void SaveURL(SaveItemId save_item_id, - const GURL& url, - const Referrer& referrer, - int render_process_host_id, - int render_view_routing_id, - int render_frame_routing_id, - SaveFileCreateInfo::SaveFileSource save_source, - const base::FilePath& file_full_path, - BrowserContext* context, - StoragePartition* storage_partition, - SavePackage* save_package); + void SaveURL( + SaveItemId save_item_id, + const GURL& url, + const Referrer& referrer, + int render_process_host_id, + int render_view_routing_id, + int render_frame_routing_id, + SaveFileCreateInfo::SaveFileSource save_source, + const base::FilePath& file_full_path, + BrowserContext* context, + StoragePartition* storage_partition, + SavePackage* save_package, + const std::string& client_guid, + mojo::PendingRemote remote_quarantine); // Notifications sent from the IO thread and run on the file thread: void StartSave(std::unique_ptr info); @@ -159,6 +164,21 @@ class CONTENT_EXPORT SaveFileManager // Help function for sending notification of canceling specific request. void SendCancelRequest(SaveItemId save_item_id); + // Called on the file thread when the URLLoader completes saving a SaveItem. + void OnURLLoaderComplete( + SaveItemId save_item_id, + SavePackageId save_package_id, + const GURL& url, + const GURL& referrer_url, + const std::string& client_guid, + mojo::PendingRemote remote_quarantine, + bool is_success); + + // Called on the file thread when file quarantine finishes on a SaveItem. + void OnQuarantineComplete(SaveItemId save_item_id, + SavePackageId save_package_id, + download::DownloadInterruptReason result); + // Notifications sent from the file thread and run on the UI thread. // Lookup the SaveManager for this WebContents' saving browser context and diff --git a/content/browser/download/save_package.cc b/content/browser/download/save_package.cc index 4ceea290dc..5eaed4a726 100644 --- a/content/browser/download/save_package.cc +++ b/content/browser/download/save_package.cc @@ -843,6 +843,12 @@ void SavePackage::SaveNextFile(bool process_all_remaining_items) { RenderFrameHostImpl* requester_frame = requester_frame_tree_node->current_frame_host(); + mojo::PendingRemote quarantine; + auto quarantine_callback = + download_manager_->GetQuarantineConnectionCallback(); + if (quarantine_callback) + quarantine_callback.Run(quarantine.InitWithNewPipeAndPassReceiver()); + file_manager_->SaveURL( save_item_ptr->id(), save_item_ptr->url(), save_item_ptr->referrer(), requester_frame->GetProcess()->GetID(), @@ -854,7 +860,8 @@ void SavePackage::SaveNextFile(bool process_all_remaining_items) { ->GetRenderViewHost() ->GetProcess() ->GetStoragePartition(), - this); + this, download_manager_->GetApplicationClientIdForFileScanning(), + std::move(quarantine)); } while (process_all_remaining_items && !waiting_item_queue_.empty()); } diff --git a/content/browser/file_system_access/file_system_access_manager_impl.cc b/content/browser/file_system_access/file_system_access_manager_impl.cc index e58be73ae4..a47eceba37 100644 --- a/content/browser/file_system_access/file_system_access_manager_impl.cc +++ b/content/browser/file_system_access/file_system_access_manager_impl.cc @@ -448,6 +448,11 @@ void FileSystemAccessManagerImpl::ResolveDefaultDirectory( std::move(callback)))); } +void FileSystemAccessManagerImpl::Shutdown() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + permission_context_ = nullptr; +} + void FileSystemAccessManagerImpl::SetDefaultPathAndShowPicker( const BindingContext& context, blink::mojom::FilePickerOptionsPtr options, diff --git a/content/browser/file_system_access/file_system_access_manager_impl.h b/content/browser/file_system_access/file_system_access_manager_impl.h index 4c9303aa11..e06a3d347f 100644 --- a/content/browser/file_system_access/file_system_access_manager_impl.h +++ b/content/browser/file_system_access/file_system_access_manager_impl.h @@ -257,6 +257,8 @@ class CONTENT_EXPORT FileSystemAccessManagerImpl PathType path_type, const base::FilePath& path); + void Shutdown(); + private: friend class FileSystemAccessFileHandleImpl; diff --git a/content/browser/indexed_db/database_impl.cc b/content/browser/indexed_db/database_impl.cc index d6ee1e0e10..037345a2f6 100644 --- a/content/browser/indexed_db/database_impl.cc +++ b/content/browser/indexed_db/database_impl.cc @@ -87,6 +87,13 @@ void DatabaseImpl::RenameObjectStore(int64_t transaction_id, return; } + if (!transaction->IsAcceptingRequests()) { + mojo::ReportBadMessage( + "RenameObjectStore was called after committing or aborting the " + "transaction"); + return; + } + transaction->ScheduleTask( blink::mojom::IDBTaskType::Preemptive, BindWeakOperation(&IndexedDBDatabase::RenameObjectStoreOperation, @@ -175,6 +182,12 @@ void DatabaseImpl::Get(int64_t transaction_id, return; } + if (!transaction->IsAcceptingRequests()) { + mojo::ReportBadMessage( + "Get was called after committing or aborting the transaction"); + return; + } + blink::mojom::IDBDatabase::GetCallback aborting_callback = CreateCallbackAbortOnDestruct( @@ -225,6 +238,12 @@ void DatabaseImpl::GetAll(int64_t transaction_id, return; } + if (!transaction->IsAcceptingRequests()) { + mojo::ReportBadMessage( + "GetAll was called after committing or aborting the transaction"); + return; + } + // Hypothetically, this could pass the receiver to the callback immediately. // However, for result ordering issues, we need to PostTask to mimic // all of the other operations. @@ -264,6 +283,12 @@ void DatabaseImpl::SetIndexKeys( return; } + if (!transaction->IsAcceptingRequests()) { + mojo::ReportBadMessage( + "SetIndexKeys was called after committing or aborting the transaction"); + return; + } + transaction->ScheduleTask( blink::mojom::IDBTaskType::Preemptive, BindWeakOperation(&IndexedDBDatabase::SetIndexKeysOperation, @@ -290,6 +315,13 @@ void DatabaseImpl::SetIndexesReady(int64_t transaction_id, return; } + if (!transaction->IsAcceptingRequests()) { + mojo::ReportBadMessage( + "SetIndexesReady was called after committing or aborting the " + "transaction"); + return; + } + transaction->ScheduleTask( blink::mojom::IDBTaskType::Preemptive, BindWeakOperation(&IndexedDBDatabase::SetIndexesReadyOperation, @@ -327,6 +359,12 @@ void DatabaseImpl::OpenCursor( return; } + if (!transaction->IsAcceptingRequests()) { + mojo::ReportBadMessage( + "OpenCursor was called after committing or aborting the transaction"); + return; + } + blink::mojom::IDBDatabase::OpenCursorCallback aborting_callback = CreateCallbackAbortOnDestruct< blink::mojom::IDBDatabase::OpenCursorCallback, @@ -376,6 +414,12 @@ void DatabaseImpl::Count( if (!transaction) return; + if (!transaction->IsAcceptingRequests()) { + mojo::ReportBadMessage( + "Count was called after committing or aborting the transaction"); + return; + } + transaction->ScheduleTask(BindWeakOperation( &IndexedDBDatabase::CountOperation, connection_->database()->AsWeakPtr(), object_store_id, index_id, @@ -401,6 +445,12 @@ void DatabaseImpl::DeleteRange( if (!transaction) return; + if (!transaction->IsAcceptingRequests()) { + mojo::ReportBadMessage( + "DeleteRange was called after committing or aborting the transaction"); + return; + } + transaction->ScheduleTask(BindWeakOperation( &IndexedDBDatabase::DeleteRangeOperation, connection_->database()->AsWeakPtr(), object_store_id, @@ -424,6 +474,13 @@ void DatabaseImpl::GetKeyGeneratorCurrentNumber( if (!transaction) return; + if (!transaction->IsAcceptingRequests()) { + mojo::ReportBadMessage( + "GetKeyGeneratorCurrentNumber was called after committing or aborting " + "the transaction"); + return; + } + transaction->ScheduleTask(BindWeakOperation( &IndexedDBDatabase::GetKeyGeneratorCurrentNumberOperation, connection_->database()->AsWeakPtr(), object_store_id, @@ -447,6 +504,12 @@ void DatabaseImpl::Clear( if (!transaction) return; + if (!transaction->IsAcceptingRequests()) { + mojo::ReportBadMessage( + "Clear was called after committing or aborting the transaction"); + return; + } + transaction->ScheduleTask(BindWeakOperation( &IndexedDBDatabase::ClearOperation, connection_->database()->AsWeakPtr(), object_store_id, std::move(callbacks))); @@ -474,6 +537,12 @@ void DatabaseImpl::CreateIndex(int64_t transaction_id, return; } + if (!transaction->IsAcceptingRequests()) { + mojo::ReportBadMessage( + "CreateIndex was called after committing or aborting the transaction"); + return; + } + transaction->ScheduleTask( blink::mojom::IDBTaskType::Preemptive, BindWeakOperation(&IndexedDBDatabase::CreateIndexOperation, @@ -499,6 +568,12 @@ void DatabaseImpl::DeleteIndex(int64_t transaction_id, return; } + if (!transaction->IsAcceptingRequests()) { + mojo::ReportBadMessage( + "DeleteIndex was called after committing or aborting the transaction"); + return; + } + transaction->ScheduleTask(BindWeakOperation( &IndexedDBDatabase::DeleteIndexOperation, connection_->database()->AsWeakPtr(), object_store_id, index_id)); @@ -523,6 +598,12 @@ void DatabaseImpl::RenameIndex(int64_t transaction_id, return; } + if (!transaction->IsAcceptingRequests()) { + mojo::ReportBadMessage( + "RenameIndex was called after committing or aborting the transaction"); + return; + } + transaction->ScheduleTask( BindWeakOperation(&IndexedDBDatabase::RenameIndexOperation, connection_->database()->AsWeakPtr(), object_store_id, diff --git a/content/browser/indexed_db/indexed_db_transaction.h b/content/browser/indexed_db/indexed_db_transaction.h index 6acdd5db56..7536d35f00 100644 --- a/content/browser/indexed_db/indexed_db_transaction.h +++ b/content/browser/indexed_db/indexed_db_transaction.h @@ -67,6 +67,14 @@ class CONTENT_EXPORT IndexedDBTransaction { // Signals the transaction for commit. void SetCommitFlag(); + // Returns false if the transaction has been signalled to commit, is in the + // process of committing, or finished committing or was aborted. Essentially + // when this returns false no tasks should be scheduled that try to modify + // the transaction. + bool IsAcceptingRequests() { + return !is_commit_pending_ && state_ != COMMITTING && state_ != FINISHED; + } + // This transaction is ultimately backed by a LevelDBScope. Aborting a // transaction rolls back the LevelDBScopes, which (if LevelDBScopes is in // single-sequence mode) can fail. This returns the result of that rollback, diff --git a/content/browser/indexed_db/transaction_impl.cc b/content/browser/indexed_db/transaction_impl.cc index 1abde1c784..b0b19dd059 100644 --- a/content/browser/indexed_db/transaction_impl.cc +++ b/content/browser/indexed_db/transaction_impl.cc @@ -57,6 +57,13 @@ void TransactionImpl::CreateObjectStore(int64_t object_store_id, return; } + if (!transaction_->IsAcceptingRequests()) { + mojo::ReportBadMessage( + "CreateObjectStore was called after committing or aborting the " + "transaction"); + return; + } + IndexedDBConnection* connection = transaction_->connection(); if (!connection->IsConnected()) return; @@ -79,6 +86,13 @@ void TransactionImpl::DeleteObjectStore(int64_t object_store_id) { return; } + if (!transaction_->IsAcceptingRequests()) { + mojo::ReportBadMessage( + "DeleteObjectStore was called after committing or aborting the " + "transaction"); + return; + } + IndexedDBConnection* connection = transaction_->connection(); if (!connection->IsConnected()) return; @@ -111,6 +125,12 @@ void TransactionImpl::Put( return; } + if (!transaction_->IsAcceptingRequests()) { + mojo::ReportBadMessage( + "Put was called after committing or aborting the transaction"); + return; + } + IndexedDBConnection* connection = transaction_->connection(); if (!connection->IsConnected()) { IndexedDBDatabaseError error(blink::mojom::IDBException::kUnknownError, @@ -170,6 +190,12 @@ void TransactionImpl::PutAll(int64_t object_store_id, return; } + if (!transaction_->IsAcceptingRequests()) { + mojo::ReportBadMessage( + "PutAll was called after committing or aborting the transaction"); + return; + } + std::vector> external_objects_per_put( puts.size()); for (size_t i = 0; i < puts.size(); i++) { @@ -268,6 +294,12 @@ void TransactionImpl::Commit(int64_t num_errors_handled) { if (!transaction_) return; + if (!transaction_->IsAcceptingRequests()) { + // This really shouldn't be happening, but seems to be happening anyway. So + // rather than killing the renderer, simply ignore the request. + return; + } + IndexedDBConnection* connection = transaction_->connection(); if (!connection->IsConnected()) return; diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc index 6b1bdfa3fd..552a9cfe82 100644 --- a/content/browser/loader/navigation_url_loader_impl.cc +++ b/content/browser/loader/navigation_url_loader_impl.cc @@ -620,6 +620,13 @@ NavigationURLLoaderImpl::PrepareForNonInterceptedRequest( if (known_schemes_.find(resource_request_->url.scheme()) == known_schemes_.end()) { mojo::PendingRemote loader_factory; + base::Optional initiating_origin; + if (url_chain_.size() > 1) { + initiating_origin = + url::Origin::Create(url_chain_[url_chain_.size() - 2]); + } else { + initiating_origin = resource_request_->request_initiator; + } bool handled = GetContentClient()->browser()->HandleExternalProtocol( resource_request_->url, web_contents_getter_, ChildProcessHost::kInvalidUniqueID, frame_tree_node_id_, @@ -628,7 +635,7 @@ NavigationURLLoaderImpl::PrepareForNonInterceptedRequest( static_cast(blink::mojom::ResourceType::kMainFrame), static_cast(resource_request_->transition_type), resource_request_->has_user_gesture, - resource_request_->request_initiator, &loader_factory); + initiating_origin, &loader_factory); if (!handled) { handled = GetContentClient()->browser()->HandleExternalProtocol( diff --git a/content/browser/media/ohos/ohos_media_player_renderer.cc b/content/browser/media/ohos/ohos_media_player_renderer.cc index 69bbd72e2f..54db096c88 100644 --- a/content/browser/media/ohos/ohos_media_player_renderer.cc +++ b/content/browser/media/ohos/ohos_media_player_renderer.cc @@ -123,15 +123,21 @@ void OHOSMediaPlayerRenderer::FinishPaint(int32_t fd) { void OHOSMediaPlayerRenderer::OnFrameAvailable(int fd, uint32_t size, - int32_t width, - int32_t height) { + int32_t coded_width, + int32_t coded_height, + int32_t visible_width, + int32_t visible_height, + int32_t format) { if (client_extension_) { auto ohos_buffer = media::mojom::OhosSurfaceBufferHandle::New(); ohos_buffer->buffer_size = size; base::ScopedFD buffer_fd(dup(fd)); ohos_buffer->fd_browser = fd; - ohos_buffer->width = width; - ohos_buffer->height = height; + ohos_buffer->coded_width = coded_width; + ohos_buffer->coded_height = coded_height; + ohos_buffer->visible_width = visible_width; + ohos_buffer->visible_height = visible_height; + ohos_buffer->format = format; ohos_buffer->buffer_fd = mojo::PlatformHandle(std::move(buffer_fd)); client_extension_->OnFrameUpdate(std::move(ohos_buffer)); } diff --git a/content/browser/media/ohos/ohos_media_player_renderer.h b/content/browser/media/ohos/ohos_media_player_renderer.h index 38c5d0c224..21753d6ccd 100644 --- a/content/browser/media/ohos/ohos_media_player_renderer.h +++ b/content/browser/media/ohos/ohos_media_player_renderer.h @@ -58,8 +58,11 @@ class CONTENT_EXPORT OHOSMediaPlayerRenderer // media::OHOSMediaPlayerBridge::Client implementation void OnFrameAvailable(int fd, uint32_t size, - int32_t width, - int32_t height) override; + int32_t coded_width, + int32_t coded_height, + int32_t visible_width, + int32_t visible_height, + int32_t format) override; void OnMediaDurationChanged(base::TimeDelta duration) override; void OnPlaybackComplete() override; void OnError(int error) override; diff --git a/content/browser/renderer_host/frame_tree_node.cc b/content/browser/renderer_host/frame_tree_node.cc index b0b02bf700..2a9ce12ff0 100644 --- a/content/browser/renderer_host/frame_tree_node.cc +++ b/content/browser/renderer_host/frame_tree_node.cc @@ -475,6 +475,12 @@ bool FrameTreeNode::HasPendingCrossDocumentNavigation() const { bool FrameTreeNode::CommitFramePolicy( const blink::FramePolicy& new_frame_policy) { + // Documents create iframes, iframes host new documents. Both are associated + // with sandbox flags. They are required to be stricter or equal to their + // owner when they change, as we go down. + // TODO(https://crbug.com/1262061). Enforce the invariant mentioned above, + // once the interactions with FencedIframe has been tested and clarified. + bool did_change_flags = new_frame_policy.sandbox_flags != replication_state_->frame_policy.sandbox_flags; bool did_change_container_policy = diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index f86413d26f..7bca1e9446 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc @@ -826,9 +826,11 @@ enum class VerifyDidCommitParamsDifference { }; bool ValidateCSPAttribute(const std::string& value) { + static const size_t kMaxLengthCSPAttribute = 4096; if (!base::IsStringASCII(value)) return false; - if (value.find('\n') != std::string::npos || + if (value.length() > kMaxLengthCSPAttribute || + value.find('\n') != std::string::npos || value.find('\r') != std::string::npos) { return false; } @@ -2781,6 +2783,16 @@ void RenderFrameHostImpl::CreateChildFrame( return; } + // Documents create iframes, iframes host new documents. Both are associated + // with sandbox flags. They are required to be stricter or equal to their + // owner when they are created, as we go down. + if (frame_policy.sandbox_flags != + (frame_policy.sandbox_flags | active_sandbox_flags())) { + bad_message::ReceivedBadMessage( + GetProcess(), bad_message::RFH_CREATE_CHILD_FRAME_SANDBOX_FLAGS); + return; + } + // TODO(crbug.com/1145708). The interface exposed to tests should // match the mojo interface. OnCreateChildFrame(new_routing_id, std::move(frame_remote), diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index d186f75e51..f0e8942562 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc @@ -2581,6 +2581,9 @@ void RenderProcessHostImpl::RegisterCoordinatorClient( mojo::PendingReceiver receiver, mojo::PendingRemote client_process) { + // Intentionally disallow non-browser processes from getting a Coordinator. + receiver.reset(); + if (!GetProcess().IsValid()) { // If the process dies before we get this message. we have no valid PID // and there's nothing to register. @@ -3341,6 +3344,9 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer( #endif #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) switches::kSchedulerBoostUrgent, +#endif +#if defined(OS_OHOS) + switches::kForTest, #endif }; renderer_cmd->CopySwitchesFrom(browser_cmd, kSwitchNames, diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc index 2ff6de6333..cfef02b3a1 100644 --- a/content/browser/security_exploit_browsertest.cc +++ b/content/browser/security_exploit_browsertest.cc @@ -680,7 +680,7 @@ IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTestMojoBlobURLs, // If the process is killed, this test passes. EXPECT_EQ( "Received bad user message: " - "Non committable URL passed to BlobURLStore::Register", + "URL with invalid origin passed to BlobURLStore::Register", crash_observer.Wait()); } diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc index 99753b0b4b..c0c6f1ecaf 100644 --- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc +++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc @@ -449,8 +449,10 @@ class ServiceWorkerFetchDispatcher::URLLoaderAssets // NetworkService. URLLoaderAssets( scoped_refptr shared_url_loader_factory, + mojo::PendingRemote url_loader, std::unique_ptr url_loader_client) : shared_url_loader_factory_(std::move(shared_url_loader_factory)), + url_loader_(std::move(url_loader)), url_loader_client_(std::move(url_loader_client)) {} void MaybeReportToDevTools(std::pair worker_id, @@ -467,6 +469,7 @@ class ServiceWorkerFetchDispatcher::URLLoaderAssets // NetworkService: scoped_refptr shared_url_loader_factory_; + mojo::PendingRemote url_loader_; // Both: std::unique_ptr url_loader_client_; @@ -625,7 +628,8 @@ void ServiceWorkerFetchDispatcher::DispatchFetchEvent() { auto params = blink::mojom::DispatchFetchEventParams::New(); params->request = std::move(request_); params->client_id = client_id_; - params->preload_handle = std::move(preload_handle_); + params->preload_url_loader_client_receiver = + std::move(preload_url_loader_client_receiver_); params->is_offline_capability_check = is_offline_capability_check_; // TODO(https://crbug.com/900700): Make the remote connected to a receiver @@ -710,13 +714,9 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload( // When the fetch event is for an offline capability check, respond to the // navigation preload with a network disconnected error, to simulate offline. if (is_offline_capability_check_) { - mojo::PendingRemote url_loader_to_pass; mojo::Remote url_loader_client; - auto dummy_receiver = url_loader_to_pass.InitWithNewPipeAndPassReceiver(); - preload_handle_ = blink::mojom::FetchEventPreloadHandle::New(); - preload_handle_->url_loader = std::move(url_loader_to_pass); - preload_handle_->url_loader_client_receiver = + preload_url_loader_client_receiver_ = url_loader_client.BindNewPipeAndPassReceiver(); url_loader_client->OnComplete( @@ -755,12 +755,10 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload( factory = base::MakeRefCounted( std::move(network_factory)); - preload_handle_ = blink::mojom::FetchEventPreloadHandle::New(); - // Create the DelegatingURLLoaderClient, which becomes the // URLLoaderClient for the navigation preload network request. mojo::PendingRemote inner_url_loader_client; - preload_handle_->url_loader_client_receiver = + preload_url_loader_client_receiver_ = inner_url_loader_client.InitWithNewPipeAndPassReceiver(); auto url_loader_client = std::make_unique( std::move(inner_url_loader_client), resource_request); @@ -795,11 +793,9 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload( net::MutableNetworkTrafficAnnotationTag( kNavigationPreloadTrafficAnnotation)); - preload_handle_->url_loader = std::move(url_loader); - DCHECK(!url_loader_assets_); url_loader_assets_ = base::MakeRefCounted( - std::move(factory), std::move(url_loader_client)); + std::move(factory), std::move(url_loader), std::move(url_loader_client)); return true; } diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.h b/content/browser/service_worker/service_worker_fetch_dispatcher.h index d436dbfba3..056b1ec439 100644 --- a/content/browser/service_worker/service_worker_fetch_dispatcher.h +++ b/content/browser/service_worker/service_worker_fetch_dispatcher.h @@ -123,10 +123,11 @@ class CONTENT_EXPORT ServiceWorkerFetchDispatcher { scoped_refptr url_loader_assets_; - // |preload_handle_| holds the URLLoader and URLLoaderClient for the service - // worker to receive the navigation preload response. It's passed to the - // service worker along with the fetch event. - blink::mojom::FetchEventPreloadHandlePtr preload_handle_; + // Holds the URLLoaderClient for the service worker to receive the navigation + // preload response. It's passed to the service worker along with the fetch + // event. + mojo::PendingReceiver + preload_url_loader_client_receiver_; // Whether to dispatch an offline-capability-check fetch event. const bool is_offline_capability_check_ = false; diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc index 65c4f1049f..7a517fe224 100644 --- a/content/browser/storage_partition_impl.cc +++ b/content/browser/storage_partition_impl.cc @@ -1064,6 +1064,9 @@ StoragePartitionImpl::~StoragePartitionImpl() { GetDatabaseTracker())); } + if (GetFileSystemAccessManager()) + GetFileSystemAccessManager()->Shutdown(); + if (GetFileSystemContext()) GetFileSystemContext()->Shutdown(); diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 3e19bacca3..e3a9179342 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc @@ -2586,7 +2586,7 @@ void WebContentsImpl::SetSlowWebPreferences( // Otherwise default is disabled. std::string touch_enabled_default_switch = switches::kTouchEventFeatureDetectionDisabled; -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_OHOS) touch_enabled_default_switch = switches::kTouchEventFeatureDetectionEnabled; #endif // defined(OS_ANDROID) const std::string touch_enabled_switch = diff --git a/content/browser/webauth/authenticator_common.cc b/content/browser/webauth/authenticator_common.cc index 069543a490..16d3a019fa 100644 --- a/content/browser/webauth/authenticator_common.cc +++ b/content/browser/webauth/authenticator_common.cc @@ -894,6 +894,13 @@ void AuthenticatorCommon::MakeCredential( return; } + if (!security_checker_->DeduplicateCredentialDescriptorListAndValidateLength( + &options->exclude_credentials)) { + mojo::ReportBadMessage("invalid exclude_credentials length"); + InvokeCallbackAndCleanup(std::move(callback), blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR); + return; + } + request_delegate_ = CreateRequestDelegate(); if (!request_delegate_) { InvokeCallbackAndCleanup(std::move(callback), @@ -1155,6 +1162,13 @@ void AuthenticatorCommon::GetAssertion( return; } + if (!security_checker_->DeduplicateCredentialDescriptorListAndValidateLength( + &options->allow_credentials)) { + mojo::ReportBadMessage("invalid allow_credentials length"); + InvokeCallbackAndCleanup(std::move(callback), blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR); + return; + } + request_delegate_ = CreateRequestDelegate(); if (!request_delegate_) { InvokeCallbackAndCleanup(std::move(callback), diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc index 333d020662..fd43d3902d 100644 --- a/content/browser/webauth/authenticator_impl_unittest.cc +++ b/content/browser/webauth/authenticator_impl_unittest.cc @@ -67,6 +67,7 @@ #include "device/fido/multiple_virtual_fido_device_factory.h" #include "device/fido/pin.h" #include "device/fido/public_key.h" +#include "device/fido/public_key_credential_descriptor.h" #include "device/fido/test_callback_receiver.h" #include "device/fido/virtual_fido_device.h" #include "device/fido/virtual_fido_device_factory.h" @@ -459,6 +460,9 @@ class AuthenticatorTestBase : public content::RenderViewHostTestHarness { void SetUp() override { content::RenderViewHostTestHarness::SetUp(); + mojo::SetDefaultProcessErrorHandler(base::BindRepeating( + &AuthenticatorTestBase::OnMojoError, base::Unretained(this))); + #if BUILDFLAG(IS_CHROMEOS_ASH) chromeos::U2FClient::InitializeFake(); #endif @@ -469,6 +473,8 @@ class AuthenticatorTestBase : public content::RenderViewHostTestHarness { void TearDown() override { content::RenderViewHostTestHarness::TearDown(); + mojo::SetDefaultProcessErrorHandler(base::NullCallback()); + #if BUILDFLAG(IS_CHROMEOS_ASH) chromeos::U2FClient::Shutdown(); #endif @@ -483,7 +489,23 @@ class AuthenticatorTestBase : public content::RenderViewHostTestHarness { std::move(virtual_device_factory)); } + void SetMojoErrorHandler( + base::RepeatingCallback callback) { + mojo_error_handler_ = callback; + } + device::test::VirtualFidoDeviceFactory* virtual_device_factory_; + + private: + void OnMojoError(const std::string& error) { + if (mojo_error_handler_) { + mojo_error_handler_.Run(error); + return; + } + FAIL() << "Unhandled mojo error: " << error; + } + + base::RepeatingCallback mojo_error_handler_; }; class AuthenticatorImplTest : public AuthenticatorTestBase { @@ -632,18 +654,17 @@ class AuthenticatorImplTest : public AuthenticatorTestBase { scoped_feature_list_->InitAndDisableFeature(feature); } - protected: + scoped_refptr<::testing::NiceMock> + mock_adapter_ = base::MakeRefCounted< + ::testing::NiceMock>(); + + private: std::unique_ptr authenticator_impl_; base::Optional scoped_feature_list_; std::unique_ptr bluetooth_global_values_ = device::BluetoothAdapterFactory::Get()->InitGlobalValuesForTesting(); - scoped_refptr<::testing::NiceMock> - mock_adapter_ = base::MakeRefCounted< - ::testing::NiceMock>(); data_decoder::test::InProcessDataDecoder data_decoder_service_; - - private: url::ScopedSchemeRegistryForTests scoped_registry_; }; @@ -3523,7 +3544,7 @@ TEST_F(AuthenticatorImplTest, AllowListWithOnlyOversizedCredentialIds) { for (const bool has_app_id : {false, true}) { SCOPED_TRACE(has_app_id); - virtual_device_factory_->mutable_state()->allow_list_sizes.clear(); + virtual_device_factory_->mutable_state()->allow_list_history.clear(); PublicKeyCredentialRequestOptionsPtr options = GetTestPublicKeyCredentialRequestOptions(); @@ -3535,14 +3556,200 @@ TEST_F(AuthenticatorImplTest, AllowListWithOnlyOversizedCredentialIds) { EXPECT_EQ(AuthenticatorGetAssertion(std::move(options)).status, AuthenticatorStatus::NOT_ALLOWED_ERROR); - const auto& allow_list_sizes = - virtual_device_factory_->mutable_state()->allow_list_sizes; + const auto& allow_list_history = + virtual_device_factory_->mutable_state()->allow_list_history; // No empty allow-list requests should have been made. - EXPECT_TRUE(std::none_of(allow_list_sizes.cbegin(), allow_list_sizes.cend(), - [](size_t size) { return size == 0; })); + EXPECT_TRUE(std::none_of( + allow_list_history.cbegin(), allow_list_history.cend(), + [](const std::vector& + allow_list) { return allow_list.empty(); })); } } +// Tests that duplicate credential IDs are filtered from an assertion allow_list +// parameter. +TEST_F(AuthenticatorImplTest, AllowListWithDuplicateCredentialIds) { + NavigateAndCommit(GURL(kTestOrigin1)); + + device::VirtualCtap2Device::Config config; + config.u2f_support = true; + config.max_credential_id_length = kTestCredentialIdLength; + config.max_credential_count_in_list = 10; + virtual_device_factory_->SetCtap2Config(config); + + device::PublicKeyCredentialDescriptor cred_a( + device::CredentialType::kPublicKey, + std::vector(kTestCredentialIdLength, 1), {}); + device::PublicKeyCredentialDescriptor cred_b( + device::CredentialType::kPublicKey, + std::vector(kTestCredentialIdLength, 2), + {device::FidoTransportProtocol::kUsbHumanInterfaceDevice}); + // Same ID as `cred_a` and `cred_b` but with different transports. + device::PublicKeyCredentialDescriptor cred_c( + device::CredentialType::kPublicKey, + std::vector(kTestCredentialIdLength, 1), + {device::FidoTransportProtocol::kBluetoothLowEnergy}); + device::PublicKeyCredentialDescriptor cred_d( + device::CredentialType::kPublicKey, + std::vector(kTestCredentialIdLength, 2), + {device::FidoTransportProtocol::kBluetoothLowEnergy}); + + ASSERT_TRUE(virtual_device_factory_->mutable_state()->InjectRegistration( + cred_b.id(), kTestRelyingPartyId)); + + PublicKeyCredentialRequestOptionsPtr options = + GetTestPublicKeyCredentialRequestOptions(); + options->allow_credentials.clear(); + options->allow_credentials.insert(options->allow_credentials.end(), 5, + cred_a); + options->allow_credentials.push_back(cred_b); + options->allow_credentials.insert(options->allow_credentials.end(), 3, + cred_c); + options->allow_credentials.insert(options->allow_credentials.end(), 2, + cred_d); + + EXPECT_EQ(AuthenticatorGetAssertion(std::move(options)).status, + AuthenticatorStatus::SUCCESS); + EXPECT_EQ(virtual_device_factory_->mutable_state()->allow_list_history.size(), + 1u); + // Transport hints from descriptors with equal IDs should be merged. + device::PublicKeyCredentialDescriptor cred_a_and_c( + device::CredentialType::kPublicKey, + std::vector(kTestCredentialIdLength, 1), + // The union of the empty transports in `cred_a` plus the non-empty set + // from `cred_c` should still be empty, since empty set is interpreted to + // mean "any available transport". + {}); + device::PublicKeyCredentialDescriptor cred_b_and_d( + device::CredentialType::kPublicKey, + std::vector(kTestCredentialIdLength, 2), + {device::FidoTransportProtocol::kUsbHumanInterfaceDevice, + device::FidoTransportProtocol::kBluetoothLowEnergy}); + EXPECT_THAT( + virtual_device_factory_->mutable_state()->allow_list_history.at(0), + testing::UnorderedElementsAre(cred_a_and_c, cred_b_and_d)); +} + +// Tests that duplicate credential IDs are filtered from a registration +// exclude_list parameter. +TEST_F(AuthenticatorImplTest, ExcludeListWithDuplicateCredentialIds) { + NavigateAndCommit(GURL(kTestOrigin1)); + + device::VirtualCtap2Device::Config config; + config.u2f_support = true; + config.max_credential_id_length = kTestCredentialIdLength; + config.max_credential_count_in_list = 100; + virtual_device_factory_->SetCtap2Config(config); + + device::PublicKeyCredentialDescriptor cred_a( + device::CredentialType::kPublicKey, + std::vector(kTestCredentialIdLength, 1), {}); + device::PublicKeyCredentialDescriptor cred_b( + device::CredentialType::kPublicKey, + std::vector(kTestCredentialIdLength, 2), + {device::FidoTransportProtocol::kUsbHumanInterfaceDevice}); + // Same ID as `cred_a` and `cred_b` but with different transports. + device::PublicKeyCredentialDescriptor cred_c( + device::CredentialType::kPublicKey, + std::vector(kTestCredentialIdLength, 1), + {device::FidoTransportProtocol::kBluetoothLowEnergy}); + device::PublicKeyCredentialDescriptor cred_d( + device::CredentialType::kPublicKey, + std::vector(kTestCredentialIdLength, 2), + {device::FidoTransportProtocol::kBluetoothLowEnergy}); + + PublicKeyCredentialCreationOptionsPtr options = + GetTestPublicKeyCredentialCreationOptions(); + options->exclude_credentials.clear(); + options->exclude_credentials.insert(options->exclude_credentials.end(), 5, + cred_a); + options->exclude_credentials.push_back(cred_b); + options->exclude_credentials.insert(options->exclude_credentials.end(), 3, + cred_c); + options->exclude_credentials.insert(options->exclude_credentials.end(), 2, + cred_d); + + EXPECT_EQ(AuthenticatorMakeCredential(std::move(options)).status, + AuthenticatorStatus::SUCCESS); + EXPECT_EQ( + virtual_device_factory_->mutable_state()->exclude_list_history.size(), + 1u); + // Transport hints from descriptors with equal IDs should be merged. + device::PublicKeyCredentialDescriptor cred_a_and_c( + device::CredentialType::kPublicKey, + std::vector(kTestCredentialIdLength, 1), + // The union of the empty transports in `cred_a` plus the non-empty set + // from `cred_c` should still be empty, since empty set is interpreted to + // mean "any available transport". + {}); + device::PublicKeyCredentialDescriptor cred_b_and_d( + device::CredentialType::kPublicKey, + std::vector(kTestCredentialIdLength, 2), + {device::FidoTransportProtocol::kUsbHumanInterfaceDevice, + device::FidoTransportProtocol::kBluetoothLowEnergy}); + EXPECT_THAT( + virtual_device_factory_->mutable_state()->exclude_list_history.at(0), + testing::UnorderedElementsAre(cred_a_and_c, cred_b_and_d)); +} + +// Test that allow lists over 64 entries are verboten. +TEST_F(AuthenticatorImplTest, OversizedAllowList) { + NavigateAndCommit(GURL(kTestOrigin1)); + + device::VirtualCtap2Device::Config config; + config.u2f_support = true; + config.max_credential_id_length = kTestCredentialIdLength; + config.max_credential_count_in_list = 100; + virtual_device_factory_->SetCtap2Config(config); + + auto test_credentials = GetTestCredentials( + /*num_credentials=*/blink::mojom:: + kPublicKeyCredentialDescriptorListMaxSize + + 1); + ASSERT_TRUE(virtual_device_factory_->mutable_state()->InjectRegistration( + test_credentials.at(0).id(), kTestRelyingPartyId)); + + PublicKeyCredentialRequestOptionsPtr options = + GetTestPublicKeyCredentialRequestOptions(); + options->allow_credentials = test_credentials; + + bool has_mojo_error = false; + SetMojoErrorHandler(base::BindLambdaForTesting( + [&](const std::string& error) { has_mojo_error = true; })); + + EXPECT_EQ(AuthenticatorGetAssertion(std::move(options)).status, + AuthenticatorStatus::NOT_ALLOWED_ERROR); + EXPECT_TRUE(has_mojo_error); +} + +// Test that exclude lists over 64 entries are verboten. +TEST_F(AuthenticatorImplTest, OversizedExcludeList) { + NavigateAndCommit(GURL(kTestOrigin1)); + + device::VirtualCtap2Device::Config config; + config.u2f_support = true; + config.max_credential_id_length = kTestCredentialIdLength; + config.max_credential_count_in_list = 100; + virtual_device_factory_->SetCtap2Config(config); + + auto test_credentials = GetTestCredentials( + /*num_credentials=*/blink::mojom:: + kPublicKeyCredentialDescriptorListMaxSize + + 1); + + PublicKeyCredentialCreationOptionsPtr options = + GetTestPublicKeyCredentialCreationOptions(); + options->exclude_credentials = test_credentials; + + bool has_mojo_error = false; + SetMojoErrorHandler(base::BindLambdaForTesting( + [&](const std::string& error) { has_mojo_error = true; })); + + EXPECT_EQ(AuthenticatorMakeCredential(std::move(options)).status, + AuthenticatorStatus::NOT_ALLOWED_ERROR); + EXPECT_TRUE(has_mojo_error); +} + TEST_F(AuthenticatorImplTest, NoUnexpectedAuthenticatorExtensions) { NavigateAndCommit(GURL(kTestOrigin1)); diff --git a/content/browser/webauth/webauth_browsertest.cc b/content/browser/webauth/webauth_browsertest.cc index 038bd22a6e..cb80baef7d 100644 --- a/content/browser/webauth/webauth_browsertest.cc +++ b/content/browser/webauth/webauth_browsertest.cc @@ -124,6 +124,14 @@ constexpr char kCrossOriginAncestorMessage[] = "storage/retrieval of 'PasswordCredential' and 'FederatedCredential', " "storage of 'PublicKeyCredential'."; +constexpr char kAllowCredentialsRangeErrorMessage[] = + "webauth: RangeError: The `allowCredentials` attribute exceeds the maximum " + "allowed size (64)."; + +constexpr char kExcludeCredentialsRangeErrorMessage[] = + "webauth: RangeError: The `excludeCredentials` attribute exceeds the " + "maximum allowed size (64)."; + // Templates to be used with base::ReplaceStringPlaceholders. Can be // modified to include up to 9 replacements. The default values for // any additional replacements added should also be added to the @@ -139,14 +147,14 @@ constexpr char kCreatePublicKeyTemplate[] = " icon: '$8'}," " pubKeyCredParams: [{ type: 'public-key', alg: '$4'}]," " timeout: _timeout_," - " excludeCredentials: []," + " excludeCredentials: $9," " authenticatorSelection: {" " requireResidentKey: $1," " userVerification: '$2'," " authenticatorAttachment: '$5'," " }," " attestation: '$6'," - "}}).then(c => window.domAutomationController.send('webauth: OK' + $9)," + "}}).then(c => window.domAutomationController.send('webauth: OK')," " e => window.domAutomationController.send(" " 'webauth: ' + e.toString()));"; @@ -161,40 +169,33 @@ constexpr char kCreatePublicKeyWithAbortSignalTemplate[] = " icon: '$8'}," " pubKeyCredParams: [{ type: 'public-key', alg: '$4'}]," " timeout: _timeout_," - " excludeCredentials: []," + " excludeCredentials: $9," " authenticatorSelection: {" " requireResidentKey: $1," " userVerification: '$2'," " authenticatorAttachment: '$5'," " }," " attestation: '$6'," - "}, signal: $9}" + "}, signal: _signal_}" ").then(c => window.domAutomationController.send('webauth: OK')," " e => window.domAutomationController.send(" " 'webauth: ' + e.toString()));"; -constexpr char kPlatform[] = "platform"; -constexpr char kCrossPlatform[] = "cross-platform"; -constexpr char kPreferredVerification[] = "preferred"; -constexpr char kRequiredVerification[] = "required"; constexpr char kShortTimeout[] = "100"; // Default values for kCreatePublicKeyTemplate. struct CreateParameters { - const char* rp_id = "acme.com"; + std::string rp_id = "acme.com"; bool require_resident_key = false; - const char* user_verification = kPreferredVerification; - const char* authenticator_attachment = kCrossPlatform; - const char* algorithm_identifier = "-7"; - const char* attestation = "none"; - const char* rp_icon = "https://pics.acme.com/00/p/aBjjjpqPb.png"; - const char* user_icon = "https://pics.acme.com/00/p/aBjjjpqPb.png"; - const char* signal = ""; - // extra_ok_output is a Javascript expression which must evaluate to a string. - // It can use the |PublicKeyCredential| object named |c| to extract useful - // fields. - const char* extra_ok_output = "''"; - const char* timeout = "1000"; + std::string user_verification = "preferred"; + std::string authenticator_attachment = "cross-platform"; + std::string algorithm_identifier = "-7"; + std::string attestation = "none"; + std::string rp_icon = "https://pics.acme.com/00/p/aBjjjpqPb.png"; + std::string user_icon = "https://pics.acme.com/00/p/aBjjjpqPb.png"; + std::string exclude_credentials = "[]"; + std::string signal = ""; + std::string timeout = "1000"; }; std::string BuildCreateCallWithParameters(const CreateParameters& parameters) { @@ -207,16 +208,17 @@ std::string BuildCreateCallWithParameters(const CreateParameters& parameters) { substitutions.push_back(parameters.attestation); substitutions.push_back(parameters.rp_icon); substitutions.push_back(parameters.user_icon); + substitutions.push_back(parameters.exclude_credentials); std::string result; - if (strlen(parameters.signal) == 0) { - substitutions.push_back(parameters.extra_ok_output); + if (parameters.signal.empty()) { result = base::ReplaceStringPlaceholders(kCreatePublicKeyTemplate, substitutions, nullptr); } else { - substitutions.push_back(parameters.signal); result = base::ReplaceStringPlaceholders( kCreatePublicKeyWithAbortSignalTemplate, substitutions, nullptr); + base::ReplaceFirstSubstringAfterOffset(&result, 0, "_signal_", + parameters.signal); } base::ReplaceFirstSubstringAfterOffset(&result, 0, "_timeout_", @@ -227,45 +229,40 @@ std::string BuildCreateCallWithParameters(const CreateParameters& parameters) { constexpr char kGetPublicKeyTemplate[] = "navigator.credentials.get({ publicKey: {" " challenge: new TextEncoder().encode('climb a mountain')," - " timeout: $4," " userVerification: '$1'," - " $2}" - "}).then(c => window.domAutomationController.send('webauth: OK' + $3)," + " allowCredentials: $2," + " timeout: $3}" + "}).then(c => window.domAutomationController.send('webauth: OK')," " e => window.domAutomationController.send(" " 'webauth: ' + e.toString()));"; constexpr char kGetPublicKeyWithAbortSignalTemplate[] = "navigator.credentials.get({ publicKey: {" " challenge: new TextEncoder().encode('climb a mountain')," - " timeout: $4," " userVerification: '$1'," - " $2}," - " signal: $5" - "}).catch(c => window.domAutomationController.send(" + " allowCredentials: $2," + " timeout: $3," + "}, signal: $4}" + ").catch(c => window.domAutomationController.send(" " 'webauth: ' + c.toString()));"; // Default values for kGetPublicKeyTemplate. struct GetParameters { - const char* user_verification = kPreferredVerification; - const char* allow_credentials = - "allowCredentials: [{ type: 'public-key'," - " id: new TextEncoder().encode('allowedCredential')," - " transports: ['usb', 'nfc', 'ble']}]"; - const char* signal = ""; - const char* timeout = "1000"; - // extra_ok_output is a Javascript expression which must evaluate to a string. - // It can use the |PublicKeyCredential| object named |c| to extract useful - // fields. - const char* extra_ok_output = "''"; + std::string user_verification = "preferred"; + std::string allow_credentials = + "[{type: 'public-key'," + " id: new TextEncoder().encode('allowedCredential')," + " transports: ['usb', 'nfc', 'ble']}]"; + std::string signal = ""; + std::string timeout = "1000"; }; std::string BuildGetCallWithParameters(const GetParameters& parameters) { std::vector substitutions; substitutions.push_back(parameters.user_verification); substitutions.push_back(parameters.allow_credentials); - substitutions.push_back(parameters.extra_ok_output); substitutions.push_back(parameters.timeout); - if (strlen(parameters.signal) == 0) { + if (parameters.signal.empty()) { return base::ReplaceStringPlaceholders(kGetPublicKeyTemplate, substitutions, nullptr); } @@ -886,7 +883,7 @@ IN_PROC_BROWSER_TEST_F(WebAuthJavascriptClientBrowserTest, virtual_device_factory->SetSupportedProtocol(protocol); CreateParameters parameters; - parameters.user_verification = kRequiredVerification; + parameters.user_verification = "required"; parameters.timeout = kShortTimeout; std::string result; ASSERT_TRUE(content::ExecuteScriptAndExtractString( @@ -944,7 +941,7 @@ IN_PROC_BROWSER_TEST_F(WebAuthJavascriptClientBrowserTest, virtual_device_factory->SetSupportedProtocol(protocol); CreateParameters parameters; - parameters.authenticator_attachment = kPlatform; + parameters.authenticator_attachment = "platform"; parameters.timeout = kShortTimeout; std::string result; ASSERT_TRUE(content::ExecuteScriptAndExtractString( @@ -1052,7 +1049,7 @@ IN_PROC_BROWSER_TEST_F(WebAuthJavascriptClientBrowserTest, GetParameters parameters; parameters.allow_credentials = - "allowCredentials: [{" + "[{" " type: 'public-key'," " id: new TextEncoder().encode('allowedCredential')," " transports: ['carrierpigeon']," @@ -1071,7 +1068,7 @@ IN_PROC_BROWSER_TEST_F(WebAuthJavascriptClientBrowserTest, GetPublicKeyCredentialEmptyAllowCredentialsList) { InjectVirtualFidoDeviceFactory(); GetParameters parameters; - parameters.allow_credentials = ""; + parameters.allow_credentials = "[]"; std::string result; ASSERT_TRUE(content::ExecuteScriptAndExtractString( shell()->web_contents()->GetMainFrame(), @@ -1252,16 +1249,14 @@ IN_PROC_BROWSER_TEST_F(WebAuthJavascriptClientBrowserTest, EXPECT_EQ(kCrossOriginAncestorMessage, result); } + GetParameters get_params; const int credential_id = test.cross_origin ? kInnerCredentialID : kOuterCredentialID; - const std::string allow_credentials = base::StringPrintf( - "allowCredentials: " + get_params.allow_credentials = base::StringPrintf( "[{ type: 'public-key'," " id: new Uint8Array([%d])," "}]", credential_id); - GetParameters get_params; - get_params.allow_credentials = allow_credentials.c_str(); ASSERT_TRUE(content::ExecuteScriptAndExtractString( iframe, BuildGetCallWithParameters(get_params), &result)); if (test.get_should_work) { @@ -1369,7 +1364,7 @@ IN_PROC_BROWSER_TEST_F(WebAuthJavascriptClientBrowserTest, InjectVirtualFidoDeviceFactory(); GetParameters parameters; parameters.allow_credentials = - "allowCredentials: [{ type: 'public-key'," + "[{ type: 'public-key'," " id: new TextEncoder().encode('allowedCredential')," " transports: ['cable']}]," "extensions: {" @@ -1466,8 +1461,7 @@ IN_PROC_BROWSER_TEST_F(WebAuthJavascriptClientBrowserTest, WinGetAssertion) { GetParameters get_parameters; get_parameters.allow_credentials = - "allowCredentials: [{ type: 'public-key', id: new " - "TextEncoder().encode('AAA')}]"; + "[{ type: 'public-key', id: new TextEncoder().encode('AAA')}]"; base::Optional result = ExecuteScriptAndExtractPrefixedString( shell()->web_contents(), BuildGetCallWithParameters(get_parameters), @@ -1505,6 +1499,39 @@ IN_PROC_BROWSER_TEST_F(WebAuthJavascriptClientBrowserTest, } #endif +IN_PROC_BROWSER_TEST_F(WebAuthJavascriptClientBrowserTest, + GetAssertionOversizedAllowList) { + EXPECT_TRUE( + NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title1.html"))); + + GetParameters get_parameters; + get_parameters.allow_credentials = + "Array(65).fill({ type: 'public-key', id: new " + "TextEncoder().encode('A')})"; + + absl::optional result = ExecuteScriptAndExtractPrefixedString( + shell()->web_contents(), BuildGetCallWithParameters(get_parameters), + "webauth: "); + ASSERT_TRUE(result); + ASSERT_EQ(kAllowCredentialsRangeErrorMessage, *result); +} + +IN_PROC_BROWSER_TEST_F(WebAuthJavascriptClientBrowserTest, + MakeCredentialOversizedExcludeList) { + EXPECT_TRUE( + NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title1.html"))); + + CreateParameters parameters; + parameters.exclude_credentials = + "Array(65).fill({type: 'public-key', id: new TextEncoder().encode('A')})"; + + absl::optional result = ExecuteScriptAndExtractPrefixedString( + shell()->web_contents(), BuildCreateCallWithParameters(parameters), + "webauth: "); + ASSERT_TRUE(result); + ASSERT_EQ(kExcludeCredentialsRangeErrorMessage, *result); +} + class WebAuthLocalClientBackForwardCacheBrowserTest : public WebAuthLocalClientBrowserTest { protected: diff --git a/content/browser/webauth/webauth_request_security_checker.cc b/content/browser/webauth/webauth_request_security_checker.cc index 57201e51bc..e4db00509e 100644 --- a/content/browser/webauth/webauth_request_security_checker.cc +++ b/content/browser/webauth/webauth_request_security_checker.cc @@ -10,6 +10,7 @@ #include "content/public/browser/render_frame_host.h" #include "content/public/common/content_features.h" #include "device/fido/features.h" +#include "device/fido/fido_transport_protocol.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" #include "services/network/public/cpp/is_potentially_trustworthy.h" #include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom.h" @@ -185,4 +186,51 @@ WebAuthRequestSecurityChecker::ValidateAPrioriAuthenticatedUrl( return blink::mojom::AuthenticatorStatus::SUCCESS; } +bool WebAuthRequestSecurityChecker:: + DeduplicateCredentialDescriptorListAndValidateLength( + std::vector* list) { + // Credential descriptor lists should not exceed 64 entries, which is enforced + // by renderer code. Any duplicate entries they contain should be ignored. + // This is to guard against sites trying to amplify small timing differences + // in the processing of different types of credentials when sending probing + // requests to physical security keys (https://crbug.com/1248862). + if (list->size() > blink::mojom::kPublicKeyCredentialDescriptorListMaxSize) { + return false; + } + auto credential_descriptor_compare_without_transport = + [](const device::PublicKeyCredentialDescriptor& a, + const device::PublicKeyCredentialDescriptor& b) { + return a.credential_type() < b.credential_type() || + (a.credential_type() == b.credential_type() && a.id() < b.id()); + }; + std::set + unique_credential_descriptors( + credential_descriptor_compare_without_transport); + for (const auto& credential_descriptor : *list) { + auto it = unique_credential_descriptors.find(credential_descriptor); + if (it == unique_credential_descriptors.end()) { + unique_credential_descriptors.insert(credential_descriptor); + } else { + // Combine transport hints of descriptors with identical IDs. Empty + // transport list means _any_ transport, so the union should still be + // empty. + base::flat_set merged_transports; + if (!it->transports().empty() && + !credential_descriptor.transports().empty()) { + base::ranges::set_union( + it->transports(), credential_descriptor.transports(), + std::inserter(merged_transports, merged_transports.begin())); + } + unique_credential_descriptors.erase(it); + unique_credential_descriptors.insert( + {credential_descriptor.credential_type(), credential_descriptor.id(), + std::move(merged_transports)}); + } + } + *list = {unique_credential_descriptors.begin(), + unique_credential_descriptors.end()}; + return true; +} + } // namespace content diff --git a/content/browser/webauth/webauth_request_security_checker.h b/content/browser/webauth/webauth_request_security_checker.h index d1cb8f730e..9e26ed2524 100644 --- a/content/browser/webauth/webauth_request_security_checker.h +++ b/content/browser/webauth/webauth_request_security_checker.h @@ -10,6 +10,7 @@ #include "base/memory/ref_counted.h" #include "base/optional.h" #include "content/common/content_export.h" +#include "device/fido/public_key_credential_descriptor.h" #include "third_party/blink/public/mojom/webauthn/authenticator.mojom.h" namespace url { @@ -71,6 +72,10 @@ class CONTENT_EXPORT WebAuthRequestSecurityChecker blink::mojom::AuthenticatorStatus ValidateAPrioriAuthenticatedUrl( const GURL& url); + bool DeduplicateCredentialDescriptorListAndValidateLength( + std::vector* list) + WARN_UNUSED_RESULT; + protected: friend class RefCounted; virtual ~WebAuthRequestSecurityChecker(); diff --git a/content/public/browser/background_fetch_delegate.h b/content/public/browser/background_fetch_delegate.h index 09436ef773..02e1255480 100644 --- a/content/public/browser/background_fetch_delegate.h +++ b/content/public/browser/background_fetch_delegate.h @@ -16,6 +16,7 @@ #include "base/optional.h" #include "content/common/content_export.h" #include "content/public/browser/web_contents.h" +#include "services/network/public/mojom/fetch_api.mojom-shared.h" #include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -140,6 +141,7 @@ class CONTENT_EXPORT BackgroundFetchDelegate { const std::string& download_guid, const std::string& method, const GURL& url, + ::network::mojom::CredentialsMode credentials_mode, const net::NetworkTrafficAnnotationTag& traffic_annotation, const net::HttpRequestHeaders& headers, bool has_request_body) = 0; diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index f2f81b235f..b4ae72f795 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h @@ -1718,10 +1718,12 @@ class CONTENT_EXPORT ContentBrowserClient { // Otherwise child_id will be the process id and |navigation_ui_data| will be // nullptr. // - // |initiating_origin| is the origin that initiated the navigation to the - // external protocol, and may be null, e.g. in the case of browser-initiated - // navigations. The initiating origin is intended to help users make security - // decisions about whether to allow an external application to launch. + // |initiating_origin| is the origin of the last redirecting server (falling + // back to the request initiator if there were no redirects / if the request + // goes straight to an external protocol, or null, e.g. in the case of + // browser-initiated navigations. The initiating origin is intended to help + // users make security decisions about whether to allow an external + // application to launch. virtual bool HandleExternalProtocol( const GURL& url, base::OnceCallback web_contents_getter, diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 3e6645553b..b07486bc45 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc @@ -649,7 +649,7 @@ const base::Feature kServiceWorkerTerminationOnNoControllee{ // isolated renderers. const base::Feature kSharedArrayBuffer { "SharedArrayBuffer", -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_OHOS) base::FEATURE_DISABLED_BY_DEFAULT #else base::FEATURE_ENABLED_BY_DEFAULT @@ -814,7 +814,7 @@ const base::Feature kWebAssemblyTiering{"WebAssemblyTiering", // isolated renderers. const base::Feature kWebAssemblyThreads { "WebAssemblyThreads", -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_OHOS) base::FEATURE_DISABLED_BY_DEFAULT #else base::FEATURE_ENABLED_BY_DEFAULT diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc index f543db60a3..61ccb23398 100644 --- a/content/public/common/content_switches.cc +++ b/content/public/common/content_switches.cc @@ -973,6 +973,7 @@ const char kEnableSpeechDispatcher[] = "enable-speech-dispatcher"; #if defined(OS_OHOS) const char kEnableMultiRendererProcess[] = "enable-multi-renderer-process"; +const char kForTest[] = "for-test"; #endif #if defined(OS_WIN) diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index 31d0a72c4b..deb45f55a2 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h @@ -267,6 +267,7 @@ CONTENT_EXPORT extern const char kRendererWaitForJavaDebugger[]; // of lacros-chrome is complete. #if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) || defined(OS_OHOS) CONTENT_EXPORT extern const char kEnableSpeechDispatcher[]; +CONTENT_EXPORT extern const char kForTest[]; #endif #if defined(OS_OHOS) diff --git a/content/public/test/fake_download_item.cc b/content/public/test/fake_download_item.cc index 5cd2ba5ff4..5bc7cc74f4 100644 --- a/content/public/test/fake_download_item.cc +++ b/content/public/test/fake_download_item.cc @@ -207,6 +207,15 @@ FakeDownloadItem::GetDownloadSchedule() const { return download_schedule_; } +::network::mojom::CredentialsMode FakeDownloadItem::GetCredentialsMode() const { + return ::network::mojom::CredentialsMode::kInclude; +} + +const absl::optional& FakeDownloadItem::GetIsolationInfo() + const { + return isolation_info_; +} + void FakeDownloadItem::SetIsDone(bool is_done) { is_done_ = is_done; } diff --git a/content/public/test/fake_download_item.h b/content/public/test/fake_download_item.h index 7d6bb806ca..caa7ebc255 100644 --- a/content/public/test/fake_download_item.h +++ b/content/public/test/fake_download_item.h @@ -59,6 +59,8 @@ class FakeDownloadItem : public download::DownloadItem { DownloadCreationType GetDownloadCreationType() const override; const base::Optional& GetDownloadSchedule() const override; + ::network::mojom::CredentialsMode GetCredentialsMode() const override; + const absl::optional& GetIsolationInfo() const override; bool IsDone() const override; const std::string& GetETag() const override; const std::string& GetLastModifiedTime() const override; @@ -186,6 +188,7 @@ class FakeDownloadItem : public download::DownloadItem { std::string last_modified_time_; std::string hash_; base::Optional download_schedule_; + absl::optional isolation_info_; // The members below are to be returned by methods, which return by reference. std::string dummy_string; diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn index dd529be39b..9325b96383 100644 --- a/content/renderer/BUILD.gn +++ b/content/renderer/BUILD.gn @@ -19,6 +19,26 @@ if (is_component_build) { link_target_type = "static_library" } +if (is_ohos) { + import("//build/config/ohos/config.gni") + config("ohos_system_libs") { + libs = [ + "hilog", + "utils.z", + "eventhandler.z", + "app_manager.z", + "base.z", + "want.z", + "appexecfwk_common.z", + "appexecfwk_base.z", + "samgr_proxy.z", + "ipc_core.z", + ] + include_dirs = ohos_src_includes + lib_dirs = ohos_libs_dir + } +} + target(link_target_type, "renderer") { # Only the public target should depend on this. All other targets (even # internal content ones) should depend on the public one. @@ -216,11 +236,14 @@ target(link_target_type, "renderer") { } if (is_ohos) { + configs += [ ":ohos_system_libs" ] sources += [ "media/ohos/ohos_media_player_renderer_client.cc", "media/ohos/ohos_media_player_renderer_client.h", "media/ohos/ohos_media_player_renderer_client_factory.cc", "media/ohos/ohos_media_player_renderer_client_factory.h", + "render_remote_proxy.h", + "render_remote_proxy.cc", ] } diff --git a/content/renderer/media/ohos/ohos_media_player_renderer_client.cc b/content/renderer/media/ohos/ohos_media_player_renderer_client.cc index 4f2b9c1043..666e08857c 100644 --- a/content/renderer/media/ohos/ohos_media_player_renderer_client.cc +++ b/content/renderer/media/ohos/ohos_media_player_renderer_client.cc @@ -8,6 +8,8 @@ #include #include +#include +#include #include "base/logging.h" #include "media/base/video_frame.h" @@ -30,7 +32,7 @@ OHOSMediaPlayerRendererClient::OHOSMediaPlayerRendererClient( OHOSMediaPlayerRendererClient::~OHOSMediaPlayerRendererClient() { while (!cached_buffers_.empty()) { - CachedBuffer &temp_buffer = cached_buffers_.front(); + CachedBuffer& temp_buffer = cached_buffers_.front(); munmap(temp_buffer.mapped_, temp_buffer.buffer_size_); close(temp_buffer.fd_); cached_buffers_.pop_front(); @@ -73,7 +75,7 @@ void OHOSMediaPlayerRendererClient::OnFinishPaintCallback() { return; } if (cached_buffers_.size() > 1) { - CachedBuffer &temp_buffer = cached_buffers_.front(); + CachedBuffer& temp_buffer = cached_buffers_.front(); munmap(temp_buffer.mapped_, temp_buffer.buffer_size_); close(temp_buffer.fd_); renderer_extension_remote_->FinishPaint(temp_buffer.fd_browser_); @@ -120,21 +122,69 @@ void OHOSMediaPlayerRendererClient::OnFrameUpdate( auto fd = ohos_surface_buffer_handle->buffer_fd.TakeFD().release(); uint32_t buffer_size = ohos_surface_buffer_handle->buffer_size; int fd_browser = ohos_surface_buffer_handle->fd_browser; - int32_t width = ohos_surface_buffer_handle->width; - int32_t height = ohos_surface_buffer_handle->height; - + int32_t coded_width = ohos_surface_buffer_handle->coded_width; + int32_t coded_height = ohos_surface_buffer_handle->coded_height; + int32_t visible_width = ohos_surface_buffer_handle->visible_width; + int32_t visible_height = ohos_surface_buffer_handle->visible_height; + int32_t src_format = ohos_surface_buffer_handle->format; + errno = 0; uint8_t* mapped = (uint8_t*)mmap(NULL, buffer_size, PROT_READ, MAP_SHARED, fd, 0); + int temp_errno = errno; + if (temp_errno != 0) { + LOG(ERROR) << "Render client map failed err:" << temp_errno + << " coded_width:" << coded_width + << " coded_height:" << coded_height + << " visible_width:" << visible_width + << " visible_height:" << visible_height + << " mmap:" << (void*)mapped + << " fd:" << fd + << " format:" << src_format << " size:" << buffer_size; + } + gfx::Size coded_size = gfx::Size(coded_width, coded_height); + gfx::Rect visible_rect = gfx::Rect(0, 0, visible_width, visible_height); + gfx::Size natural_size = gfx::Size(visible_width, visible_height); const base::TimeDelta kZero; + if (src_format == PIXEL_FMT_YCBCR_420_SP) { + PaintNV12VideoFrame(coded_size, visible_rect, natural_size, mapped, + buffer_size, fd, fd_browser); + } else { + scoped_refptr dst_frame = + media::VideoFrame::WrapExternalData( + media::VideoPixelFormat::PIXEL_FORMAT_ABGR, coded_size, + visible_rect, natural_size, mapped, buffer_size, kZero); + sink_->PaintSingleFrame(std::move(dst_frame)); + cached_buffers_.push_back( + CachedBuffer{fd_browser, fd, mapped, buffer_size}); + } +} - media::VideoPixelFormat format = media::VideoPixelFormat::PIXEL_FORMAT_ABGR; - gfx::Size size = gfx::Size(width, height); - scoped_refptr frame = media::VideoFrame::WrapExternalData( - format, size, gfx::Rect(size), size, mapped, buffer_size, kZero); - - auto unique_frame = media::VideoFrame::WrapVideoFrame( - frame, frame->format(), frame->visible_rect(), frame->natural_size()); - sink_->PaintSingleFrame(std::move(unique_frame)); +void OHOSMediaPlayerRendererClient::PaintNV12VideoFrame( + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, + const gfx::Size& natural_size, + uint8_t* mapped, + const uint32_t& buffer_size, + const int& fd, + const int& fd_browser) { + const base::TimeDelta kZero; + scoped_refptr src_frame = + media::VideoFrame::WrapExternalData( + media::VideoPixelFormat::PIXEL_FORMAT_NV12, coded_size, visible_rect, + natural_size, mapped, buffer_size, kZero); + scoped_refptr dst_frame = media::VideoFrame::CreateFrame( + media::VideoPixelFormat::PIXEL_FORMAT_I420, coded_size, visible_rect, + natural_size, src_frame->timestamp()); + auto convert_status = + media::ConvertAndScaleFrame(*src_frame, *dst_frame, resize_buf_); + if (!convert_status.is_ok()) { + LOG(ERROR) << "Convert failed msg:" << convert_status.message(); + munmap(mapped, buffer_size); + close(fd); + renderer_extension_remote_->FinishPaint(fd_browser); + return; + } + sink_->PaintSingleFrame(std::move(dst_frame)); cached_buffers_.push_back(CachedBuffer{fd_browser, fd, mapped, buffer_size}); } diff --git a/content/renderer/media/ohos/ohos_media_player_renderer_client.h b/content/renderer/media/ohos/ohos_media_player_renderer_client.h index 8f1f6cf0da..040f39fc9f 100644 --- a/content/renderer/media/ohos/ohos_media_player_renderer_client.h +++ b/content/renderer/media/ohos/ohos_media_player_renderer_client.h @@ -16,6 +16,7 @@ #include "media/base/renderer.h" #include "media/base/renderer_client.h" #include "media/base/video_renderer_sink.h" +#include "media/base/video_util.h" #include "media/mojo/clients/mojo_renderer.h" #include "media/mojo/clients/mojo_renderer_wrapper.h" #include "media/mojo/mojom/renderer_extensions.mojom.h" @@ -62,6 +63,14 @@ class OHOSMediaPlayerRendererClient void OnRemoteRendererInitialized(media::PipelineStatus status); void OnFinishPaintCallback(); + void PaintNV12VideoFrame(const gfx::Size& coded_size, + const gfx::Rect& visible_rect, + const gfx::Size& natural_size, + uint8_t* mapped, + const uint32_t& buffer_size, + const int& fd, + const int& fd_browser); + media::MediaResource* media_resource_; std::deque cached_buffers_; @@ -74,6 +83,8 @@ class OHOSMediaPlayerRendererClient media::PipelineStatusCallback init_cb_; + std::vector resize_buf_; + // This class is constructed on the main task runner, and used on // |media_task_runner_|. These member are used to delay calls to Bind() for // |renderer_extension_ptr_| and |client_extension_binding_|, until we are on diff --git a/content/renderer/render_remote_proxy.cc b/content/renderer/render_remote_proxy.cc new file mode 100644 index 0000000000..2fada4e83b --- /dev/null +++ b/content/renderer/render_remote_proxy.cc @@ -0,0 +1,78 @@ +// Copyright 2022 The Huawei 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 "render_remote_proxy.h" + +#include +#include "appmgr/app_mgr_client.h" +#include "base/command_line.h" +#include "base/posix/global_descriptors.h" +#include "content/public/common/content_descriptors.h" +#include "content/public/common/content_switches.h" +#include "refbase.h" + +namespace content { +std::unique_ptr g_app_mgr_client{nullptr}; +OHOS::sptr g_render_remote_proxy{nullptr}; + +std::mutex RenderRemoteProxy::browser_fd_mtx_; +std::condition_variable RenderRemoteProxy::browser_fd_cv_; +bool RenderRemoteProxy::is_browser_fd_received_{false}; +bool RenderRemoteProxy::is_for_test_{false}; + +void RenderRemoteProxy::NotifyBrowserFd(int32_t ipcFd, int32_t sharedFd) { + base::GlobalDescriptors* g_fds = base::GlobalDescriptors::GetInstance(); + if (g_fds != nullptr) { + int new_ipc_fd; + if ((new_ipc_fd = dup(ipcFd)) < 0) { + LOG(ERROR) << "ipcFd duplicate error"; + g_fds->Set(kMojoIPCChannel, ipcFd); + ipc_fd_ = ipcFd; + } else { + g_fds->Set(kMojoIPCChannel, new_ipc_fd); + ipc_fd_ = new_ipc_fd; + close(ipcFd); + } + + int new_shared_fd; + if ((new_shared_fd = dup(sharedFd)) < 0) { + LOG(ERROR) << "sharedFd duplicate error"; + g_fds->Set(kFieldTrialDescriptor, sharedFd); + shared_fd_ = sharedFd; + } else { + g_fds->Set(kFieldTrialDescriptor, new_shared_fd); + shared_fd_ = new_shared_fd; + close(sharedFd); + } + } + RenderRemoteProxy::is_browser_fd_received_ = true; + RenderRemoteProxy::browser_fd_cv_.notify_one(); +} + +void RenderRemoteProxy::CreateAndRegist(const base::CommandLine& command_line) { + is_for_test_ = command_line.HasSwitch(switches::kForTest); + if (!is_for_test_) { + g_app_mgr_client = std::make_unique(); + g_render_remote_proxy = new RenderRemoteProxy(); + g_app_mgr_client->AttachRenderProcess(g_render_remote_proxy); + } +} + +bool RenderRemoteProxy::WaitForBrowserFd() { + if (is_for_test_) { + return true; + } + LOG(INFO) << "wait for browser fd start"; + std::unique_lock lk(browser_fd_mtx_); + constexpr int kTimeOutDur = 5; // seconds + if (!browser_fd_cv_.wait_for(lk, std::chrono::seconds(kTimeOutDur), + []() { return is_browser_fd_received_; })) { + LOG(ERROR) << "wait for browser fd timeout(" << kTimeOutDur << "s)"; + return false; + } + LOG(INFO) << "wait for browser fd end"; + return true; +} + +} // namespace content \ No newline at end of file diff --git a/content/renderer/render_remote_proxy.h b/content/renderer/render_remote_proxy.h new file mode 100644 index 0000000000..1127280fbf --- /dev/null +++ b/content/renderer/render_remote_proxy.h @@ -0,0 +1,39 @@ +// Copyright 2022 The Huawei 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_RENDERER_RENDER_REMOTE_PROXY_H_ +#define CONTENT_RENDERER_RENDER_REMOTE_PROXY_H_ + +#include +#include +#include "appmgr/render_scheduler_host.h" + +namespace base { +class CommandLine; +} + +namespace content { +class RenderRemoteProxy : public OHOS::AppExecFwk::RenderSchedulerHost { + public: + RenderRemoteProxy() = default; + ~RenderRemoteProxy() = default; + + virtual void NotifyBrowserFd(int32_t ipcFd, int32_t sharedFd) override; + + static void CreateAndRegist(const base::CommandLine& command_line); + static bool WaitForBrowserFd(); + + private: + int32_t ipc_fd_ = 0; + int32_t shared_fd_ = 0; + + static std::mutex browser_fd_mtx_; + static std::condition_variable browser_fd_cv_; + static bool is_browser_fd_received_; + static bool is_for_test_; +}; + +} // namespace content + +#endif // CONTENT_RENDERER_RENDER_REMOTE_PROXY_H_ \ No newline at end of file diff --git a/content/renderer/service_worker/navigation_preload_request.cc b/content/renderer/service_worker/navigation_preload_request.cc index 231e947e15..0e8d77666e 100644 --- a/content/renderer/service_worker/navigation_preload_request.cc +++ b/content/renderer/service_worker/navigation_preload_request.cc @@ -17,12 +17,12 @@ NavigationPreloadRequest::NavigationPreloadRequest( ServiceWorkerContextClient* owner, int fetch_event_id, const GURL& url, - blink::mojom::FetchEventPreloadHandlePtr preload_handle) + mojo::PendingReceiver + preload_url_loader_client_receiver) : owner_(owner), fetch_event_id_(fetch_event_id), url_(url), - url_loader_(std::move(preload_handle->url_loader)), - receiver_(this, std::move(preload_handle->url_loader_client_receiver)) {} + receiver_(this, std::move(preload_url_loader_client_receiver)) {} NavigationPreloadRequest::~NavigationPreloadRequest() = default; diff --git a/content/renderer/service_worker/navigation_preload_request.h b/content/renderer/service_worker/navigation_preload_request.h index 639cc6f086..fc9c5c66b4 100644 --- a/content/renderer/service_worker/navigation_preload_request.h +++ b/content/renderer/service_worker/navigation_preload_request.h @@ -34,7 +34,8 @@ class NavigationPreloadRequest final : public network::mojom::URLLoaderClient { ServiceWorkerContextClient* owner, int fetch_event_id, const GURL& url, - blink::mojom::FetchEventPreloadHandlePtr preload_handle); + mojo::PendingReceiver + preload_url_loader_client_receiver); ~NavigationPreloadRequest() override; // network::mojom::URLLoaderClient: @@ -58,11 +59,10 @@ class NavigationPreloadRequest final : public network::mojom::URLLoaderClient { void ReportErrorToOwner(const std::string& message, blink::WebServiceWorkerError::Mode error_mode); - ServiceWorkerContextClient* owner_; + ServiceWorkerContextClient* owner_ = nullptr; - const int fetch_event_id_; + const int fetch_event_id_ = -1; const GURL url_; - mojo::Remote url_loader_; mojo::Receiver receiver_; std::unique_ptr response_; diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc index 79334c2ebf..9a1e9a6594 100644 --- a/content/renderer/service_worker/service_worker_context_client.cc +++ b/content/renderer/service_worker/service_worker_context_client.cc @@ -475,14 +475,14 @@ void ServiceWorkerContextClient::SendWorkerStarted( void ServiceWorkerContextClient::SetupNavigationPreload( int fetch_event_id, const blink::WebURL& url, - std::unique_ptr preload_handle) { + blink::CrossVariantMojoReceiver< + network::mojom::URLLoaderClientInterfaceBase> + preload_url_loader_client_receiver) { DCHECK(worker_task_runner_->RunsTasksInCurrentSequence()); DCHECK(context_); auto preload_request = std::make_unique( this, fetch_event_id, GURL(url), - blink::mojom::FetchEventPreloadHandle::New( - std::move(preload_handle->url_loader), - std::move(preload_handle->url_loader_client_receiver))); + std::move(preload_url_loader_client_receiver)); context_->preload_requests.AddWithID(std::move(preload_request), fetch_event_id); } diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h index 8191aaec6e..5abd533c6c 100644 --- a/content/renderer/service_worker/service_worker_context_client.h +++ b/content/renderer/service_worker/service_worker_context_client.h @@ -159,8 +159,9 @@ class CONTENT_EXPORT ServiceWorkerContextClient const blink::WebString& source_url) override; void SetupNavigationPreload(int fetch_event_id, const blink::WebURL& url, - std::unique_ptr - preload_handle) override; + blink::CrossVariantMojoReceiver< + network::mojom::URLLoaderClientInterfaceBase> + preload_url_loader_client_receiver) override; void RequestTermination(RequestTerminationCallback callback) override; scoped_refptr CreateWorkerFetchContextOnInitiatorThread() override; diff --git a/content/test/data/gpu/webgpu-stress-request-device-and-remove-loop.html b/content/test/data/gpu/webgpu-stress-request-device-and-remove-loop.html new file mode 100644 index 0000000000..715688a634 --- /dev/null +++ b/content/test/data/gpu/webgpu-stress-request-device-and-remove-loop.html @@ -0,0 +1,58 @@ + + + + + + diff --git a/content/test/gpu/gpu_tests/context_lost_integration_test.py b/content/test/gpu/gpu_tests/context_lost_integration_test.py index 6a3d4717c7..9096205323 100644 --- a/content/test/gpu/gpu_tests/context_lost_integration_test.py +++ b/content/test/gpu/gpu_tests/context_lost_integration_test.py @@ -148,6 +148,8 @@ class ContextLostIntegrationTest(gpu_integration_test.GpuIntegrationTest): 'gpu_process_crash.html'), ('ContextLost_WebGPUContextLostFromGPUProcessExit', 'webgpu-context-lost.html?query=kill_after_notification'), + ('ContextLost_WebGPUStressRequestDeviceAndRemoveLoop', + 'webgpu-stress-request-device-and-remove-loop.html'), ('ContextLost_WebGLContextLostFromGPUProcessExit', 'webgl.html?query=kill_after_notification'), ('ContextLost_WebGLContextLostFromLoseContextExtension', @@ -339,6 +341,15 @@ class ContextLostIntegrationTest(gpu_integration_test.GpuIntegrationTest): self._KillGPUProcess(1, False, timeout=180) self._RestartBrowser('must restart after tests that kill the GPU process') + def _ContextLost_WebGPUStressRequestDeviceAndRemoveLoop(self, test_path): + self.RestartBrowserIfNecessaryWithArgs([ + '--enable-unsafe-webgpu', + ]) + self._NavigateAndWaitForLoad(test_path) + + # Test runs for 90 seconds; wait for 120 seconds. + self._WaitForTabAndCheckCompletion(timeout=120000) + def _ContextLost_WebGLContextLostFromLoseContextExtension(self, test_path): self.RestartBrowserIfNecessaryWithArgs( [cba.DISABLE_DOMAIN_BLOCKING_FOR_3D_APIS]) diff --git a/content/web_test/browser/web_test_background_fetch_delegate.cc b/content/web_test/browser/web_test_background_fetch_delegate.cc index c26c3bd236..befa7f1b50 100644 --- a/content/web_test/browser/web_test_background_fetch_delegate.cc +++ b/content/web_test/browser/web_test_background_fetch_delegate.cc @@ -293,6 +293,7 @@ void WebTestBackgroundFetchDelegate::DownloadUrl( const std::string& download_guid, const std::string& method, const GURL& url, + ::network::mojom::CredentialsMode credentials_mode, const net::NetworkTrafficAnnotationTag& traffic_annotation, const net::HttpRequestHeaders& headers, bool has_request_body) { diff --git a/content/web_test/browser/web_test_background_fetch_delegate.h b/content/web_test/browser/web_test_background_fetch_delegate.h index e307e86e32..106df11659 100644 --- a/content/web_test/browser/web_test_background_fetch_delegate.h +++ b/content/web_test/browser/web_test_background_fetch_delegate.h @@ -39,6 +39,7 @@ class WebTestBackgroundFetchDelegate : public BackgroundFetchDelegate { const std::string& download_guid, const std::string& method, const GURL& url, + ::network::mojom::CredentialsMode credentials_mode, const net::NetworkTrafficAnnotationTag& traffic_annotation, const net::HttpRequestHeaders& headers, bool has_request_body) override; diff --git a/device/fido/public_key_credential_descriptor.cc b/device/fido/public_key_credential_descriptor.cc index 5c0328f855..bcda0c7659 100644 --- a/device/fido/public_key_credential_descriptor.cc +++ b/device/fido/public_key_credential_descriptor.cc @@ -4,6 +4,7 @@ #include +#include "device/fido/fido_transport_protocol.h" #include "device/fido/public_key_credential_descriptor.h" namespace device { @@ -13,6 +14,7 @@ namespace { // Keys for storing credential descriptor information in CBOR map. constexpr char kCredentialIdKey[] = "id"; constexpr char kCredentialTypeKey[] = "type"; +constexpr char kTransportsKey[] = "transports"; } // namespace @@ -33,8 +35,29 @@ PublicKeyCredentialDescriptor::CreateFromCBORValue(const cbor::Value& cbor) { if (id == map.end() || !id->second.is_bytestring()) return base::nullopt; + auto transports_it = map.find(cbor::Value(kTransportsKey)); + if (transports_it == map.end()) + return PublicKeyCredentialDescriptor(CredentialType::kPublicKey, + id->second.GetBytestring()); + + if (!transports_it->second.is_array()) + return base::nullopt; + + base::flat_set transports; + for (const cbor::Value& transport_name : transports_it->second.GetArray()) { + if (!transport_name.is_string()) { + return base::nullopt; + } + base::Optional transport = + ConvertToFidoTransportProtocol(transport_name.GetString()); + if (!transport) { + continue; + } + transports.insert(*transport); + } return PublicKeyCredentialDescriptor(CredentialType::kPublicKey, - id->second.GetBytestring()); + id->second.GetBytestring(), + std::move(transports)); } PublicKeyCredentialDescriptor::PublicKeyCredentialDescriptor() = default; @@ -42,14 +65,7 @@ PublicKeyCredentialDescriptor::PublicKeyCredentialDescriptor() = default; PublicKeyCredentialDescriptor::PublicKeyCredentialDescriptor( CredentialType credential_type, std::vector id) - : PublicKeyCredentialDescriptor( - credential_type, - std::move(id), - {FidoTransportProtocol::kUsbHumanInterfaceDevice, - FidoTransportProtocol::kBluetoothLowEnergy, - FidoTransportProtocol::kNearFieldCommunication, - FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy, - FidoTransportProtocol::kInternal}) {} + : PublicKeyCredentialDescriptor(credential_type, std::move(id), {}) {} PublicKeyCredentialDescriptor::PublicKeyCredentialDescriptor( CredentialType credential_type, @@ -84,6 +100,14 @@ cbor::Value AsCBOR(const PublicKeyCredentialDescriptor& desc) { cbor_descriptor_map[cbor::Value(kCredentialIdKey)] = cbor::Value(desc.id()); cbor_descriptor_map[cbor::Value(kCredentialTypeKey)] = cbor::Value(CredentialTypeToString(desc.credential_type())); + std::vector transports; + for (FidoTransportProtocol transport : desc.transports()) { + transports.emplace_back(cbor::Value(ToString(transport))); + } + if (!transports.empty()) { + cbor_descriptor_map[cbor::Value(kTransportsKey)] = + cbor::Value(std::move(transports)); + } return cbor::Value(std::move(cbor_descriptor_map)); } diff --git a/device/fido/virtual_ctap2_device.cc b/device/fido/virtual_ctap2_device.cc index e027b8fbc5..d4cd188452 100644 --- a/device/fido/virtual_ctap2_device.cc +++ b/device/fido/virtual_ctap2_device.cc @@ -965,6 +965,8 @@ base::Optional VirtualCtap2Device::OnMakeCredential( } CtapMakeCredentialRequest request = std::move(*opt_request); + mutable_state()->exclude_list_history.push_back(request.exclude_list); + bool user_verified = false; const base::Optional uv_error = CheckUserVerification( /*is_make_credential=*/true, *device_info_, request.rp.id, @@ -1222,7 +1224,7 @@ base::Optional VirtualCtap2Device::OnGetAssertion( } CtapGetAssertionRequest request = std::move(*opt_request); - mutable_state()->allow_list_sizes.push_back(request.allow_list.size()); + mutable_state()->allow_list_history.push_back(request.allow_list); bool user_verified; const base::Optional uv_error = CheckUserVerification( diff --git a/device/fido/virtual_fido_device.h b/device/fido/virtual_fido_device.h index 4526c4786a..7a9aef82d3 100644 --- a/device/fido/virtual_fido_device.h +++ b/device/fido/virtual_fido_device.h @@ -21,6 +21,7 @@ #include "device/fido/fido_constants.h" #include "device/fido/fido_device.h" #include "device/fido/fido_parsing_utils.h" +#include "device/fido/public_key_credential_descriptor.h" #include "device/fido/public_key_credential_rp_entity.h" #include "device/fido/public_key_credential_user_entity.h" #include "net/cert/x509_util.h" @@ -234,10 +235,16 @@ class COMPONENT_EXPORT(DEVICE_FIDO) VirtualFidoDevice : public FidoDevice { // to return from a previous authenticatorCredentialManagement command. std::list pending_registrations; - // allow_list_sizes contains the lengths of the allow_lists that have been - // seen in assertion requests. This is for tests to confirm that the - // expected sequence of requests was sent. - std::vector allow_list_sizes; + // allow_list_history contains the allow_list values that have been seen in + // assertion requests. This is for tests to confirm that the expected + // sequence of requests was sent. + std::vector> allow_list_history; + + // exclude_list_history contains the exclude_list values that have been seen + // in registration requests. This is for tests to confirm that the expected + // sequence of requests was sent. + std::vector> + exclude_list_history; // The large-blob array. std::vector large_blob; diff --git a/device/gamepad/gamepad_monitor.cc b/device/gamepad/gamepad_monitor.cc index 4a35a61d8b..9e1227f43d 100644 --- a/device/gamepad/gamepad_monitor.cc +++ b/device/gamepad/gamepad_monitor.cc @@ -54,6 +54,8 @@ void GamepadMonitor::GamepadStartPolling(GamepadStartPollingCallback callback) { GamepadService* service = GamepadService::GetInstance(); if (!service->ConsumerBecameActive(this)) { mojo::ReportBadMessage("GamepadMonitor::GamepadStartPolling failed"); + std::move(callback).Run(base::ReadOnlySharedMemoryRegion()); + return; } std::move(callback).Run(service->DuplicateSharedMemoryRegion()); } diff --git a/extensions/browser/api/file_system/file_system_api.cc b/extensions/browser/api/file_system/file_system_api.cc index 37d1f413ca..f047bc6c48 100644 --- a/extensions/browser/api/file_system/file_system_api.cc +++ b/extensions/browser/api/file_system/file_system_api.cc @@ -197,6 +197,9 @@ void PassFileInfoToUIThread(FileInfoOptCallback callback, content::WebContents* GetWebContentsForRenderFrameHost( content::BrowserContext* browser_context, content::RenderFrameHost* render_frame_host) { + if (!render_frame_host) + return nullptr; + content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(render_frame_host); // Check if there is an app window associated with the web contents; if not, @@ -508,15 +511,6 @@ void FileSystemChooseEntryFunction::FilesSelected( } if (is_directory_) { - // Get the WebContents for the app window to be the parent window of the - // confirmation dialog if necessary. - content::WebContents* const web_contents = GetWebContentsForRenderFrameHost( - browser_context(), render_frame_host()); - if (!web_contents) { - Respond(Error(kInvalidCallingPage)); - return; - } - DCHECK_EQ(paths.size(), 1u); bool non_native_path = false; #if BUILDFLAG(IS_CHROMEOS_ASH) @@ -530,7 +524,7 @@ void FileSystemChooseEntryFunction::FilesSelected( FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, base::BindOnce( &FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync, this, - non_native_path, paths, web_contents)); + non_native_path, paths)); return; } @@ -543,8 +537,7 @@ void FileSystemChooseEntryFunction::FileSelectionCanceled() { void FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync( bool non_native_path, - const std::vector& paths, - content::WebContents* web_contents) { + const std::vector& paths) { const base::FilePath check_path = non_native_path ? paths[0] : base::MakeAbsoluteFilePath(paths[0]); if (check_path.empty()) { @@ -576,7 +569,7 @@ void FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync( FROM_HERE, base::BindOnce( &FileSystemChooseEntryFunction::ConfirmSensitiveDirectoryAccess, - this, paths, web_contents)); + this, paths)); return; } @@ -587,8 +580,7 @@ void FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync( } void FileSystemChooseEntryFunction::ConfirmSensitiveDirectoryAccess( - const std::vector& paths, - content::WebContents* web_contents) { + const std::vector& paths) { if (ExtensionsBrowserClient::Get()->IsShuttingDown()) { FileSelectionCanceled(); return; @@ -601,6 +593,13 @@ void FileSystemChooseEntryFunction::ConfirmSensitiveDirectoryAccess( return; } + content::WebContents* const web_contents = + GetWebContentsForRenderFrameHost(browser_context(), render_frame_host()); + if (!web_contents) { + Respond(Error(kInvalidCallingPage)); + return; + } + delegate->ConfirmSensitiveDirectoryAccess( app_file_handler_util::HasFileSystemWritePermission(extension_.get()), base::UTF8ToUTF16(extension_->name()), web_contents, diff --git a/extensions/browser/api/file_system/file_system_api.h b/extensions/browser/api/file_system/file_system_api.h index ae1588ce85..0895a174a0 100644 --- a/extensions/browser/api/file_system/file_system_api.h +++ b/extensions/browser/api/file_system/file_system_api.h @@ -19,10 +19,6 @@ #include "extensions/common/api/file_system.h" #include "ui/shell_dialogs/select_file_dialog.h" -namespace content { -class WebContents; -} // namespace content - namespace extensions { class ExtensionPrefs; @@ -168,13 +164,12 @@ class FileSystemChooseEntryFunction : public FileSystemEntryFunction { // directory. If so, calls ConfirmSensitiveDirectoryAccess. Otherwise, calls // OnDirectoryAccessConfirmed. void ConfirmDirectoryAccessAsync(bool non_native_path, - const std::vector& paths, - content::WebContents* web_contents); + const std::vector& paths); // Shows a dialog to confirm whether the user wants to open the directory. // Calls OnDirectoryAccessConfirmed or FileSelectionCanceled. - void ConfirmSensitiveDirectoryAccess(const std::vector& paths, - content::WebContents* web_contents); + void ConfirmSensitiveDirectoryAccess( + const std::vector& paths); void OnDirectoryAccessConfirmed(const std::vector& paths); diff --git a/extensions/renderer/messaging_util.cc b/extensions/renderer/messaging_util.cc index f6bf874f98..7e9a0f124d 100644 --- a/extensions/renderer/messaging_util.cc +++ b/extensions/renderer/messaging_util.cc @@ -124,9 +124,13 @@ std::unique_ptr MessageFromJSONString(v8::Isolate* isolate, return nullptr; } - bool has_transient_user_activation = - web_frame ? web_frame->HasTransientUserActivation() : false; - return std::make_unique(message, has_transient_user_activation, + // The message should carry user activation information only if the last + // activation in |web_frame| was triggered by a real user interaction. See + // |UserActivationState::LastActivationWasRestricted()|. + bool has_unrestricted_user_activation = + web_frame && web_frame->HasTransientUserActivation() && + !web_frame->LastActivationWasRestricted(); + return std::make_unique(message, has_unrestricted_user_activation, privileged_context); } diff --git a/ipc/ipc_mojo_bootstrap.cc b/ipc/ipc_mojo_bootstrap.cc index 1fc3b955bf..9e22317c68 100644 --- a/ipc/ipc_mojo_bootstrap.cc +++ b/ipc/ipc_mojo_bootstrap.cc @@ -931,10 +931,14 @@ class ChannelAssociatedGroupController if (!client) return; + if (!endpoint->task_runner()->RunsTasksInCurrentSequence() && + !proxy_task_runner_->RunsTasksInCurrentSequence()) { + return; + } + // Using client->interface_name() is safe here because this is a static // string defined for each mojo interface. TRACE_EVENT0("mojom", client->interface_name()); - DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence()); // Sync messages should never make their way to this method. DCHECK(!message.has_flag(mojo::Message::kFlagIsSync)); @@ -965,10 +969,15 @@ class ChannelAssociatedGroupController if (!client) return; + if (!endpoint->task_runner()->RunsTasksInCurrentSequence() && + !proxy_task_runner_->RunsTasksInCurrentSequence()) { + return; + } + // Using client->interface_name() is safe here because this is a static // string defined for each mojo interface. TRACE_EVENT0("mojom", client->interface_name()); - DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence()); + MessageWrapper message_wrapper = endpoint->PopSyncMessage(message_id); // The message must have already been dequeued by the endpoint waking up diff --git a/media/base/ohos/ohos_media_player_bridge.cc b/media/base/ohos/ohos_media_player_bridge.cc index 882a855a4c..e2c6cab24b 100644 --- a/media/base/ohos/ohos_media_player_bridge.cc +++ b/media/base/ohos/ohos_media_player_bridge.cc @@ -139,9 +139,9 @@ void OHOSMediaPlayerBridge::FinishPaint(int fd) { return; } - if (cached_buffers_.front()->GetBufferHandle()->reserve[0] != fd) { + if (cached_buffers_.front()->GetBufferHandle()->fd != fd) { LOG(ERROR) << "match fd error render fd=" << fd << " browser fd=" - << cached_buffers_.front()->GetBufferHandle()->reserve[0]; + << cached_buffers_.front()->GetBufferHandle()->fd; } OHOS::SurfaceError ret = consumer_surface_->ReleaseBuffer(cached_buffers_.front(), -1); @@ -187,9 +187,31 @@ void OHOSMediaPlayerBridge::OnBufferAvailable( weak_factory_.GetWeakPtr(), std::move(buffer))); return; } - client_->OnFrameAvailable(buffer->GetBufferHandle()->reserve[0], - buffer->GetSize(), buffer->GetWidth(), - buffer->GetHeight()); + + // int32_t coded_height; + // int32_t coded_width; + + // // video frame height must be 32*N + // const int step_height = 32; + // // argb format video frame should divided by 4 + // const int argb_stride_step = 4; + // if (buffer->GetHeight() % step_height == 0) { + // coded_height = buffer->GetHeight(); + // } else { + // coded_height = (buffer->GetHeight() / step_height + 1) * step_height; + // } + // if (buffer->GetFormat() == PIXEL_FMT_RGBA_8888) { + // coded_width = buffer->GetStride() / argb_stride_step; + // } else { + // coded_width = buffer->GetStride(); + // } + if (buffer->GetBufferHandle()->fd <= 0) { + LOG(ERROR)<<"Unavailble fd frome meidaplayer"; + } + client_->OnFrameAvailable(buffer->GetBufferHandle()->fd, + buffer->GetSize(), buffer->GetWidth(), buffer->GetHeight(), + buffer->GetWidth(), buffer->GetHeight(), + buffer->GetFormat()); cached_buffers_.push_back(buffer); } diff --git a/media/base/ohos/ohos_media_player_bridge.h b/media/base/ohos/ohos_media_player_bridge.h index 2446a5dec1..631af9c93e 100644 --- a/media/base/ohos/ohos_media_player_bridge.h +++ b/media/base/ohos/ohos_media_player_bridge.h @@ -22,8 +22,11 @@ class MEDIA_EXPORT OHOSMediaPlayerBridge { public: virtual void OnFrameAvailable(int fd, uint32_t size, - int32_t width, - int32_t height) = 0; + int32_t coded_width, + int32_t coded_height, + int32_t visible_width, + int32_t visible_height, + int32_t format) = 0; // Called when media duration is first detected or changes. virtual void OnMediaDurationChanged(base::TimeDelta duration) = 0; @@ -73,7 +76,6 @@ class MEDIA_EXPORT OHOSMediaPlayerBridge { void OnPlayerStateUpdate(OHOS::Media::PlayerStates player_state); private: - int32_t SetFdSource(const std::string& path); const std::string surfaceFormat = "SURFACE_FORMAT"; diff --git a/media/base/ohos/ohos_media_player_listener.cc b/media/base/ohos/ohos_media_player_listener.cc index bb08070c17..5e2e5db877 100644 --- a/media/base/ohos/ohos_media_player_listener.cc +++ b/media/base/ohos/ohos_media_player_listener.cc @@ -4,6 +4,7 @@ #include "media/base/ohos/ohos_media_player_listener.h" +#include namespace media { OHOSMediaPlayerListener::OHOSMediaPlayerListener( @@ -32,9 +33,16 @@ void OHOSMediaPlayerListener::OnBufferAvailable() { LOG(ERROR) << "acquire buffer fail, ret=" << ret; return; } - task_runner_->PostTask( - FROM_HERE, base::BindOnce(&OHOSMediaPlayerBridge::OnBufferAvailable, - media_player_, buffer)); + + if (buffer->GetFormat() == PIXEL_FMT_RGBA_8888 || + buffer->GetFormat() == PIXEL_FMT_YCBCR_420_SP) { + task_runner_->PostTask( + FROM_HERE, base::BindOnce(&OHOSMediaPlayerBridge::OnBufferAvailable, + media_player_, buffer)); + } else { + LOG(ERROR) << "Unsupport format for:" << buffer->GetFormat(); + surface_temp->ReleaseBuffer(buffer, -1); + } } } // namespace media diff --git a/media/mojo/mojom/renderer_extensions.mojom b/media/mojo/mojom/renderer_extensions.mojom index 8d8e58cda5..07bd82171d 100644 --- a/media/mojo/mojom/renderer_extensions.mojom +++ b/media/mojo/mojom/renderer_extensions.mojom @@ -13,8 +13,11 @@ import "ui/gfx/geometry/mojom/geometry.mojom"; struct OhosSurfaceBufferHandle { uint32 buffer_size; int32 fd_browser; - int32 width; - int32 height; + int32 coded_width; + int32 coded_height; + int32 visible_width; + int32 visible_height; + int32 format; handle buffer_fd; }; diff --git a/mojo/core/handle_table.cc b/mojo/core/handle_table.cc index 9426281d73..a044f1c8e3 100644 --- a/mojo/core/handle_table.cc +++ b/mojo/core/handle_table.cc @@ -65,13 +65,19 @@ bool HandleTable::AddDispatchersFromTransit( const std::vector& dispatchers, MojoHandle* handles) { // Oops, we're out of handles. - if (next_available_handle_ == MOJO_HANDLE_INVALID) + if (next_available_handle_ == MOJO_HANDLE_INVALID) { return false; + } + + // MOJO_HANDLE_INVALID is zero. + DCHECK_GE(next_available_handle_, 1u); - DCHECK_LE(dispatchers.size(), std::numeric_limits::max()); // If this insertion would cause handle overflow, we're out of handles. - if (next_available_handle_ + dispatchers.size() < next_available_handle_) + const uint32_t num_handles_available = + std::numeric_limits::max() - next_available_handle_ + 1; + if (num_handles_available < dispatchers.size()) { return false; + } for (size_t i = 0; i < dispatchers.size(); ++i) { MojoHandle handle = MOJO_HANDLE_INVALID; diff --git a/mojo/public/cpp/bindings/README.md b/mojo/public/cpp/bindings/README.md index 05581aa626..d3ecb7e55a 100644 --- a/mojo/public/cpp/bindings/README.md +++ b/mojo/public/cpp/bindings/README.md @@ -1709,6 +1709,9 @@ C++ sources can depend on shared sources only, by referencing the `"${target_name}_shared"` target, e.g. `"//foo/mojom:mojom_shared"` in the example above. +For converting between Blink and non-Blink variants, please see +`//third_party/blink/public/platform/cross_variant_mojo_util.h`. + ## Versioning Considerations For general documentation of versioning in the Mojom IDL see diff --git a/mojo/public/cpp/bindings/lib/message_fragment.h b/mojo/public/cpp/bindings/lib/message_fragment.h index 226c364468..b380da4131 100644 --- a/mojo/public/cpp/bindings/lib/message_fragment.h +++ b/mojo/public/cpp/bindings/lib/message_fragment.h @@ -149,8 +149,7 @@ class MessageFragment> { static_assert( std::numeric_limits::max() > Traits::kMaxNumElements, "Max num elements castable to 32bit"); - if (num_elements > Traits::kMaxNumElements) - return; + CHECK_LE(num_elements, Traits::kMaxNumElements); const uint32_t num_bytes = Traits::GetStorageSize(static_cast(num_elements)); diff --git a/net/BUILD.gn b/net/BUILD.gn index edc7e8f38d..6232aeac47 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn @@ -1688,6 +1688,7 @@ source_set("net_deps") { public_deps = [ ":constants", + ":isolation_info_proto", ":net_export_header", ":net_resources", ":preload_decoder", @@ -1805,6 +1806,10 @@ proto_library("net_nqe_proto") { extra_configs = [ "//build/config/compiler:wexit_time_destructors" ] } +proto_library("isolation_info_proto") { + sources = [ "base/isolation_info.proto" ] +} + component("extras") { sources = [ "extras/sqlite/cookie_crypto_delegate.h", diff --git a/net/base/isolation_info.cc b/net/base/isolation_info.cc index e51644b222..3eb150b577 100644 --- a/net/base/isolation_info.cc +++ b/net/base/isolation_info.cc @@ -5,6 +5,7 @@ #include "net/base/isolation_info.h" #include "base/check_op.h" +#include "net/base/isolation_info.pb.h" namespace net { @@ -126,6 +127,35 @@ IsolationInfo IsolationInfo::CreateOpaqueAndNonTransient() { base::nullopt /* party_context */); } +base::Optional IsolationInfo::Deserialize( + const std::string& serialized) { + proto::IsolationInfo proto; + if (!proto.ParseFromString(serialized)) + return base::nullopt; + + base::Optional top_frame_origin; + if (proto.has_top_frame_origin()) + top_frame_origin = url::Origin::Create(GURL(proto.top_frame_origin())); + + base::Optional frame_origin; + if (proto.has_frame_origin()) + frame_origin = url::Origin::Create(GURL(proto.frame_origin())); + + base::Optional> party_context; + if (proto.has_party_context()) { + party_context = std::set(); + for (const auto& site : proto.party_context().site()) { + party_context->insert(SchemefulSite::Deserialize(site)); + } + } + + return IsolationInfo::CreateIfConsistent( + static_cast(proto.request_type()), + std::move(top_frame_origin), std::move(frame_origin), + SiteForCookies::FromUrl(GURL(proto.site_for_cookies())), + false /* opaque_and_non_transient */, std::move(party_context)); +} + IsolationInfo IsolationInfo::Create( RequestType request_type, const url::Origin& top_frame_origin, @@ -219,6 +249,35 @@ IsolationInfo IsolationInfo::ToDoUseTopFrameOriginAsWell( std::set() /* party_context */); } +std::string IsolationInfo::Serialize() const { + if (network_isolation_key().IsTransient()) + return ""; + + if (opaque_and_non_transient_) + return ""; + + proto::IsolationInfo info; + + info.set_request_type(static_cast(request_type_)); + + if (top_frame_origin_) + info.set_top_frame_origin(top_frame_origin_->Serialize()); + + if (frame_origin_) + info.set_frame_origin(frame_origin_->Serialize()); + + info.set_site_for_cookies(site_for_cookies_.RepresentativeUrl().spec()); + + if (party_context_) { + auto* pc = info.mutable_party_context(); + for (const auto& site : *party_context_) { + pc->add_site(site.Serialize()); + } + } + + return info.SerializeAsString(); +} + IsolationInfo::IsolationInfo( RequestType request_type, const base::Optional& top_frame_origin, diff --git a/net/base/isolation_info.h b/net/base/isolation_info.h index 28d6b1c7f7..f33bd4bb99 100644 --- a/net/base/isolation_info.h +++ b/net/base/isolation_info.h @@ -6,6 +6,7 @@ #define NET_BASE_ISOLATION_INFO_H_ #include +#include #include "base/optional.h" #include "net/base/net_export.h" @@ -96,6 +97,11 @@ class NET_EXPORT IsolationInfo { // allows use of the disk cache with a transient NIK. static IsolationInfo CreateOpaqueAndNonTransient(); + // Creates an IsolationInfo from the serialized contents. Returns a nullopt + // if deserialization fails or if data is inconsistent. + static base::Optional Deserialize( + const std::string& serialized); + // Creates an IsolationInfo with the provided parameters. If the parameters // are inconsistent, DCHECKs. In particular: // * If |request_type| is kMainFrame, |top_frame_origin| must equal @@ -198,6 +204,10 @@ class NET_EXPORT IsolationInfo { bool IsEqualForTesting(const IsolationInfo& other) const; + // Serialize the `IsolationInfo` into a string. Fails if transient, returning + // an empty string. + std::string Serialize() const; + private: IsolationInfo(RequestType request_type, const base::Optional& top_frame_origin, diff --git a/net/base/isolation_info.proto b/net/base/isolation_info.proto new file mode 100644 index 0000000000..252b738245 --- /dev/null +++ b/net/base/isolation_info.proto @@ -0,0 +1,19 @@ +// Copyright 2021 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. + +syntax = "proto2"; + +option optimize_for = LITE_RUNTIME; + +package net.proto; + +message IsolationInfo { + optional int32 request_type = 1; // net::IsolationInfo::RequestType + optional string top_frame_origin = 2; + optional string frame_origin = 3; + optional string site_for_cookies = 4; + + message PartyContext { repeated string site = 1; } + optional PartyContext party_context = 5; +} \ No newline at end of file diff --git a/net/base/isolation_info_unittest.cc b/net/base/isolation_info_unittest.cc index 5c6461ea6b..bf8cd296ca 100644 --- a/net/base/isolation_info_unittest.cc +++ b/net/base/isolation_info_unittest.cc @@ -48,6 +48,9 @@ class IsolationInfoTest : public testing::Test { std::set{net::SchemefulSite(kOrigin2)}; const base::Optional> kPartyContext3 = std::set{net::SchemefulSite(kOrigin3)}; + const base::Optional> kPartyContextMultiple = + std::set{net::SchemefulSite(kOrigin1), + net::SchemefulSite(kOrigin2)}; }; TEST_F(IsolationInfoTest, RequestTypeMainFrame) { @@ -502,6 +505,62 @@ TEST_F(IsolationInfoTest, CreateForRedirectPartyContext) { } } +TEST_F(IsolationInfoTest, Serialization) { + EXPECT_FALSE(IsolationInfo::Deserialize("")); + EXPECT_FALSE(IsolationInfo::Deserialize("garbage")); + + const IsolationInfo kPositiveTestCases[] = { + IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1, + kOrigin2, SiteForCookies::FromOrigin(kOrigin1), + kPartyContext1), + // Null party context + IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1, + kOrigin2, SiteForCookies::FromOrigin(kOrigin1), + kPartyContextNull), + // Empty party context + IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1, + kOrigin2, SiteForCookies::FromOrigin(kOrigin1), + kPartyContextEmpty), + // Multiple party context entries. + IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1, + kOrigin2, SiteForCookies::FromOrigin(kOrigin1), + kPartyContextMultiple), + // Without SiteForCookies + IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1, + kOrigin2, SiteForCookies(), base::nullopt), + // Request type kOther + IsolationInfo::Create(IsolationInfo::RequestType::kOther, kOrigin1, + kOrigin1, SiteForCookies::FromOrigin(kOrigin1), + base::nullopt), + // Request type kMainframe + IsolationInfo::Create(IsolationInfo::RequestType::kMainFrame, kOrigin1, + kOrigin1, SiteForCookies::FromOrigin(kOrigin1), + base::nullopt), + }; + for (const auto& info : kPositiveTestCases) { + auto rt = IsolationInfo::Deserialize(info.Serialize()); + ASSERT_TRUE(rt); + EXPECT_TRUE(rt->IsEqualForTesting(info)); + } + + const IsolationInfo kNegativeTestCases[] = { + IsolationInfo::CreateTransient(), + IsolationInfo::CreateOpaqueAndNonTransient(), + // With nonce (i.e transient). + IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1, + kOrigin2, SiteForCookies::FromOrigin(kOrigin1), + kPartyContext1, &kNonce1), + // With an opaque origin (i.e transient) + IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1, + url::Origin(), SiteForCookies::FromOrigin(kOrigin1), + base::nullopt), + + }; + for (const auto& info : kNegativeTestCases) { + EXPECT_TRUE(info.Serialize().empty()); + } +} + } // namespace } // namespace net diff --git a/net/cert/cert_verify_proc_ohos.cc b/net/cert/cert_verify_proc_ohos.cc index b36b8d9022..82d219d37d 100644 --- a/net/cert/cert_verify_proc_ohos.cc +++ b/net/cert/cert_verify_proc_ohos.cc @@ -3,9 +3,19 @@ // found in the LICENSE file. #include "net/cert/cert_verify_proc_ohos.h" - +#include +#include +#include "base/logging.h" #include "net/cert/cert_net_fetcher.h" +#include "net/cert/x509_certificate.h" +#include "net/cert/x509_util.h" +#include "openssl/err.h" +#include "openssl/ossl_typ.h" +#include "openssl/x509.h" +#include "openssl/x509_vfy.h" +#define ROOT_CERT "/etc/ssl/certs/cacert.pem" +#define MIN_CERT_NUM 1 namespace net { CertVerifyProcOHOS::CertVerifyProcOHOS( scoped_refptr cert_net_fetcher) @@ -17,6 +27,131 @@ bool CertVerifyProcOHOS::SupportsAdditionalTrustAnchors() const { return false; } +void GetChainDEREncodedBytes(X509Certificate* cert, + std::vector* chain_bytes) { + chain_bytes->reserve(1 + cert->intermediate_buffers().size()); + chain_bytes->emplace_back( + net::x509_util::CryptoBufferAsStringPiece(cert->cert_buffer())); + for (const auto& handle : cert->intermediate_buffers()) { + chain_bytes->emplace_back( + net::x509_util::CryptoBufferAsStringPiece(handle.get())); + } +} + +void X509_d2i_free(X509* server_cert[], uint32_t server_cert_sum) { + uint32_t i; + for (i = 0; i < server_cert_sum; i++) { + X509_free(server_cert[i]); + } +} + +bool CertChainVerify(X509* server_cert[], + uint32_t server_cert_sum, + X509_STORE* root_store) { + uint32_t i; + STACK_OF(X509)* ca_stack = nullptr; + X509_STORE_CTX* ctx = nullptr; + + // certificate chain verify + for (i = server_cert_sum - 1; i > 0; i--) { + // Create certificate store context function + ctx = X509_STORE_CTX_new(); + if (ctx == nullptr) { + LOG(ERROR) << "Create certificate store context function failed"; + X509_d2i_free(server_cert, server_cert_sum); + X509_STORE_free(root_store); + return false; + } + + // Initialize the certificate chain + X509_STORE_CTX_init(ctx, root_store, server_cert[i], ca_stack); + + // If verification fails, for detailed error information, see + // X509_verify_cert_error_string + if (!X509_verify_cert(ctx)) { + LOG(ERROR) << "Certificate verify error: " << ctx->error + << "\nCertificate verify info: " + << X509_verify_cert_error_string(ctx->error) + << "\nTotal number of server certificates: " << server_cert_sum + << "\nserver certificates count: " << i; + X509_d2i_free(server_cert, server_cert_sum); + X509_STORE_CTX_free(ctx); + X509_STORE_free(root_store); + return false; + } + + X509_STORE_CTX_free(ctx); + } + + X509_d2i_free(server_cert, server_cert_sum); + X509_STORE_free(root_store); + + return true; +} + +bool CertVerify(std::vector& cert_bytes) { + uint32_t server_cert_sum; + const unsigned char* der_encoded_tmp = nullptr; + uint32_t i; + int root_cert_sum = 0; + X509_STORE* root_store = nullptr; + X509_LOOKUP* look_up = nullptr; + + server_cert_sum = cert_bytes.size(); + if (server_cert_sum < MIN_CERT_NUM) { + LOG(ERROR) << "Total number of server certificates is error"; + return false; + } + + // Convert cert_bytes to internal X509 data structure(server_cert[]), If the + // conversion fails, see ERR_reason_error_string()/kLibraryNames + X509* server_cert[server_cert_sum]; + for (i = 0; i < server_cert_sum; i++) { + der_encoded_tmp = (unsigned char*)cert_bytes[i].c_str(); + server_cert[i] = d2i_X509(nullptr, &der_encoded_tmp, cert_bytes[i].size()); + if (server_cert[i] == nullptr) { + LOG(ERROR) + << "Server certificate DEREncoded converted to X509 error, Reason: " + << ERR_reason_error_string(ERR_get_error()) + << "\nTotal number of server certificates: " << server_cert_sum + << "\nError certificate count:" << i; + ERR_clear_error(); + X509_d2i_free(server_cert, i); + return false; + } + } + + // Create X509 certificate store + root_store = X509_STORE_new(); + if (root_store == nullptr) { + LOG(ERROR) << "Create X509 certificate store failed"; + X509_d2i_free(server_cert, server_cert_sum); + return false; + } + + // Create X509_LOOKUP, the store_ctx member of this data structure is + // associated with the newly created certificate store root_store + look_up = X509_STORE_add_lookup(root_store, X509_LOOKUP_file()); + if (look_up == nullptr) { + LOG(ERROR) << "Create X509 LOOKUP failed"; + X509_d2i_free(server_cert, server_cert_sum); + X509_STORE_free(root_store); + return false; + } + + // Parse the root certificate file + root_cert_sum = + X509_load_cert_crl_file(look_up, ROOT_CERT, X509_FILETYPE_PEM); + if (root_cert_sum == 0) { + LOG(ERROR) << "Root certificate number is 0"; + X509_d2i_free(server_cert, server_cert_sum); + X509_STORE_free(root_store); + return false; + } + + return CertChainVerify(server_cert, server_cert_sum, root_store); +} + int CertVerifyProcOHOS::VerifyInternal( X509Certificate* cert, const std::string& hostname, @@ -27,7 +162,14 @@ int CertVerifyProcOHOS::VerifyInternal( const CertificateList& additional_trust_anchors, CertVerifyResult* verify_result, const NetLogWithSource& net_log) { - //TODO: no implement + std::vector cert_bytes; + + GetChainDEREncodedBytes(cert, &cert_bytes); + + if (!CertVerify(cert_bytes)) { + return ERR_FAILED; + } + return OK; } diff --git a/ohos_nweb/BUILD.gn b/ohos_nweb/BUILD.gn index c87c2a462f..aa77be3230 100644 --- a/ohos_nweb/BUILD.gn +++ b/ohos_nweb/BUILD.gn @@ -181,10 +181,28 @@ executable("web_render") { sources = [ "src/ohos_nweb_main.cc", ] + deps = [ + ":nweb_hilog", + ] +} + +shared_library("libnweb_render") { + defines = [ + "OHOS_NWEB", + ] + + include_dirs = [ + "include", + ] + include_dirs += ohos_src_includes + + sources = [ + "src/nweb_render_main.cc", + ] deps = [ ":nweb_hilog", "//cef:libweb_engine", "//cef:libcef_dll_wrapper", ] -} \ No newline at end of file +} diff --git a/ohos_nweb/include/nweb.h b/ohos_nweb/include/nweb.h index 707d3a6fd8..10c2f66e40 100755 --- a/ohos_nweb/include/nweb.h +++ b/ohos_nweb/include/nweb.h @@ -150,7 +150,7 @@ class OHOS_NWEB_EXPORT NWeb : public std::enable_shared_from_this { * * @return the last HitTestResult */ - virtual const HitTestResult GetHitTestResult() const = 0; + virtual HitTestResult GetHitTestResult() const = 0; /** * Sets the background color for this view. diff --git a/ohos_nweb/include/nweb_access_request.h b/ohos_nweb/include/nweb_access_request.h index 853c91ec86..6592ba26ee 100644 --- a/ohos_nweb/include/nweb_access_request.h +++ b/ohos_nweb/include/nweb_access_request.h @@ -11,47 +11,47 @@ namespace OHOS::NWeb { class OHOS_NWEB_EXPORT NWebAccessRequest { - public: - NWebAccessRequest() = default; - - virtual ~NWebAccessRequest() = default; - - enum Resources { - GEOLOCATION = 1 << 0, - VIDEO_CAPTURE = 1 << 1, - AUDIO_CAPTURE = 1 << 2, - PROTECTED_MEDIA_ID = 1 << 3, - MIDI_SYSEX = 1 << 4, - }; - - /** - * Get the origin of the web page which is trying to access the resource. - * - * @return the origin of the web page which is trying to access the resource. - */ - virtual std::string Origin() = 0; - - /** - * Get the resource id the web page is trying to access. - * - * @return the resource id the web page is trying to access. - */ - virtual int ResourceAcessId() = 0; - - /** - * Agree the origin to access the given resources. - * The granted access is only valid for this WebView. - * - * @param resourceId id of the resource agreed to be accessed by origin. It - * must be equal to requested resource id returned by {@link - * #GetResourceAcessId()}. - */ - virtual void Agree(int resourceId) = 0; - - /** - * Refuse the request. - */ - virtual void Refuse() = 0; +public: + NWebAccessRequest() = default; + + virtual ~NWebAccessRequest() = default; + + enum Resources { + GEOLOCATION = 1 << 0, + VIDEO_CAPTURE = 1 << 1, + AUDIO_CAPTURE = 1 << 2, + PROTECTED_MEDIA_ID = 1 << 3, + MIDI_SYSEX = 1 << 4, + }; + + /** + * Get the origin of the web page which is trying to access the resource. + * + * @return the origin of the web page which is trying to access the resource. + */ + virtual std::string Origin() = 0; + + /** + * Get the resource id the web page is trying to access. + * + * @return the resource id the web page is trying to access. + */ + virtual int ResourceAcessId() = 0; + + /** + * Agree the origin to access the given resources. + * The granted access is only valid for this WebView. + * + * @param resourceId id of the resource agreed to be accessed by origin. It + * must be equal to requested resource id returned by {@link + * #GetResourceAcessId()}. + */ + virtual void Agree(int resourceId) = 0; + + /** + * Refuse the request. + */ + virtual void Refuse() = 0; }; } // namespace OHOS::NWeb diff --git a/ohos_nweb/include/nweb_console_log.h b/ohos_nweb/include/nweb_console_log.h index 2089061420..b0a8d6bbd9 100644 --- a/ohos_nweb/include/nweb_console_log.h +++ b/ohos_nweb/include/nweb_console_log.h @@ -76,4 +76,4 @@ private: }; } -#endif \ No newline at end of file +#endif // NWEB_CONSOLE_LOG_H \ No newline at end of file diff --git a/ohos_nweb/include/nweb_cookie_manager.h b/ohos_nweb/include/nweb_cookie_manager.h index 11800d8579..4e2c33aaf9 100644 --- a/ohos_nweb/include/nweb_cookie_manager.h +++ b/ohos_nweb/include/nweb_cookie_manager.h @@ -31,7 +31,6 @@ public: * @return true if the instance send and accept cookies. */ virtual bool IsAcceptCookieAllowed() const = 0; - /** * @brief Sets whether the instance should send and accept cookies. * By default this is set to true and the nweb accepts cookies. @@ -39,21 +38,18 @@ public: * @param accept whether the instance should send and accept cookies. */ virtual void PutAcceptCookieEnabled(bool accept) = 0; - /** * @brief Get whether instances can send and accept cookies for file scheme URLs. * * @return true if instances send and accept cookies for file scheme URLs. */ virtual bool IsFileURLSchemeCookiesAllowed() const = 0; - /** * @brief Sets whether the instance should send and accept cookies for file scheme URLs. * * @param allow whether the instance should send and accept cookies for file scheme URLs. */ virtual void PutAcceptFileURLSchemeCookiesEnabled(bool allow) = 0; - /** * @brief Gets all the cookies for the given URL. * @@ -62,7 +58,6 @@ public: */ virtual void ReturnCookie(const std::string &url, std::shared_ptr> callback) = 0; - /** * @brief GSets a single cookie (key-value pair) for the given URL. * @@ -73,14 +68,12 @@ public: virtual void SetCookie(const std::string &url, const std::string &value, std::shared_ptr> callback) = 0; - /** * @brief Gets whether there are stored cookies. * * @param callback a callback to be executed when the cookie has checked. */ virtual void ExistCookies(std::shared_ptr> callback) = 0; - /** * @brief Ensures all cookies currently accessible through the ReturnCookie API are written to * persistent storage. @@ -88,14 +81,12 @@ public: * @param callback a callback to be executed when cookies has Stored. */ virtual void Store(std::shared_ptr> callback) = 0; - /** * @brief Removes all session cookies, which are cookies without an expiration date. * * @param callback a callback to be executed when all session cookies has removed. */ virtual void DeleteSessionCookies(std::shared_ptr> callback) = 0; - /** * @brief Removes all cookies. * diff --git a/ohos_nweb/include/nweb_geolocation_callback_interface.h b/ohos_nweb/include/nweb_geolocation_callback_interface.h index 4a95f8e8db..5fe586d606 100644 --- a/ohos_nweb/include/nweb_geolocation_callback_interface.h +++ b/ohos_nweb/include/nweb_geolocation_callback_interface.h @@ -11,21 +11,21 @@ namespace OHOS::NWeb { class OHOS_NWEB_EXPORT NWebGeolocationCallbackInterface { - public: - NWebGeolocationCallbackInterface() = default; +public: + NWebGeolocationCallbackInterface() = default; - virtual ~NWebGeolocationCallbackInterface() = default; - /** - * @brief Report the geolocation permission status from usrs. - * - * @param origin The origin that ask for the geolocation permission. - * @param allow The geolocation permission status. - * @param retain Whether to allow the geolocation permission status to be - * saved to the system. - */ - virtual void GeolocationCallbackInvoke(const std::string& origin, - bool allow, - bool retain) = 0; + virtual ~NWebGeolocationCallbackInterface() = default; + /** + * @brief Report the geolocation permission status from usrs. + * + * @param origin The origin that ask for the geolocation permission. + * @param allow The geolocation permission status. + * @param retain Whether to allow the geolocation permission status to be + * saved to the system. + */ + virtual void GeolocationCallbackInvoke(const std::string& origin, + bool allow, + bool retain) = 0; }; } // namespace OHOS::NWeb diff --git a/ohos_nweb/include/nweb_handler.h b/ohos_nweb/include/nweb_handler.h index af68a9a3d1..ce72bc9580 100644 --- a/ohos_nweb/include/nweb_handler.h +++ b/ohos_nweb/include/nweb_handler.h @@ -24,287 +24,283 @@ namespace OHOS::NWeb { * @brief Describes how pixel bits encoder color data. */ enum class ImageColorType { - // Unknown color type. - COLOR_TYPE_UNKNOWN = -1, + // Unknown color type. + COLOR_TYPE_UNKNOWN = -1, - // RGBA with 8 bits per pixel (32bits total). - COLOR_TYPE_RGBA_8888 = 0, + // RGBA with 8 bits per pixel (32bits total). + COLOR_TYPE_RGBA_8888 = 0, - // BGRA with 8 bits per pixel (32bits total). - COLOR_TYPE_BGRA_8888 = 1, + // BGRA with 8 bits per pixel (32bits total). + COLOR_TYPE_BGRA_8888 = 1, }; /** * @brief Describes how to interpret the alpha value of a pixel. */ enum class ImageAlphaType { - // Unknown alpha type. - ALPHA_TYPE_UNKNOWN = -1, + // Unknown alpha type. + ALPHA_TYPE_UNKNOWN = -1, - // No transparency. The alpha component is ignored. - ALPHA_TYPE_OPAQUE = 0, + // No transparency. The alpha component is ignored. + ALPHA_TYPE_OPAQUE = 0, - // Transparency with pre-multiplied alpha component. - ALPHA_TYPE_PREMULTIPLIED = 1, + // Transparency with pre-multiplied alpha component. + ALPHA_TYPE_PREMULTIPLIED = 1, - // Transparency with post-multiplied alpha component. - ALPHA_TYPE_POSTMULTIPLIED = 2, + // Transparency with post-multiplied alpha component. + ALPHA_TYPE_POSTMULTIPLIED = 2, }; class OHOS_NWEB_EXPORT NWebHandler { - public: - NWebHandler() = default; - - virtual ~NWebHandler() = default; - - virtual void SetNWeb(std::shared_ptr nweb) {} - - virtual void OnProxyDied() {} - - virtual void OnRouterPush(const std::string& param) {} - - virtual void OnMessage(const std::string& param) {} - - /** - * @brief Notify the SDK that a web site has finished loading. This method is - * called only for main frame. - * - * @param httpStatusCode The status code for the http request. - * @param url The url of the web site. - */ - virtual void OnPageLoadEnd(int httpStatusCode, const std::string& url) {} - - /** - * @brief Notify the SDK that a web site has started loading. This method is - * called once for each main frame load. - * - * @param url The url to be loaded. - */ - virtual void OnPageLoadBegin(const std::string& url) {} - - /** - * @brief Report a load error to the SDK. - * - * @param errorCode The error code. - * @param description The error description. - * @param failingUrl The failed url. - */ - virtual void OnPageLoadError(int errorCode, - const std::string& description, - const std::string& failingUrl) {} - - /** - * @brief Give the SDK a chance to decide wheather to continue loading the - * url. - * - * @param url The url to be loaded. - * @return true to cancel the loading, false to continue the loading. - */ - virtual bool OnHandleInterceptUrlLoading(const std::string& url) { - return false; - } - - /** - * @brief Notify the SDK that the nweb will load the resource specified by - * the given url. - * - * @param url The url of the resource. - */ - virtual void OnResource(const std::string& url) {} - - /** - * @brief Notify the SDK of the changed document title. - * - * @param title The document title. - */ - virtual void OnPageTitle(const std::string& title) {} - - /** - * @brief Notify the SDK the current progress of loading a web site. - * - * @param newProgress Loading progress, an integer between 0 and 100. - */ - virtual void OnLoadingProgress(int newProgress) {} - - /** - * @brief Request display and focus for a new nweb. - * - */ - virtual void OnFocus() {} - - /** - * @brief Obtains a list of all visited history items, used for link coloring - * - * @retval visited history - */ - virtual const std::vector VisitedUrlHistory() { - return std::vector(); - } - - /** - * @brief Notify the host application of a resource request and allow the - * application to return the data. - * - * @param request the resource response's MIME type, for example { - * "text/html"}. - * - * @retval if NWebUrlResourceResponse is null ,No interception. - */ - virtual std::shared_ptr OnHandleInterceptRequest( - std::shared_ptr request) { - return nullptr; - } - - /** - * @brief Report web resource loading error to the SDK. These errors usually - * indicate inability to connect to the server. - * - * @param request The request information. - * @param error The error information. - */ - virtual void OnResourceLoadError( - std::shared_ptr request, - std::shared_ptr error) {} - - /** - * @brief Notify the SDK that an HTTP error has been received from the server - * while loading a resource. - * - * @param request The request information. - * @param errorResponse The error occurred. - */ - virtual void OnHttpError( - std::shared_ptr request, - std::shared_ptr errorResponse) {} - - /** - * @brief Notify the SDK of a new favicon for the current web site. - * - * @param data The raw image data for the icon. - * @param width The width of the icon in pixel. - * @param height The height of the icon in pixel. - * @param color_type The color data encoding type. - * @param alpha_type The alpha value of any pixel. - */ - virtual void OnPageIcon(const void* data, - size_t width, - size_t height, - ImageColorType color_type, - ImageAlphaType alpha_type) {} - - /** - * @brief Notify the SDK of the url for an touch icon. - * - * @param icon_url The icon url. - * @param precomposed The touch icon type. - */ - virtual void OnDesktopIconUrl(const std::string& icon_url, bool precomposed) { - } - - /** - * @brief Report a JavaScript console message to the host application. - * - * @param message Details of the console message. - * @return Return true to stop the message from being output to the console. - */ - virtual bool OnConsoleLog(const NWebConsoleLog& message) { return false; } - - /** - * @brief Show prompt to ask for the geolocation permission. - * - * @param origin String: the origin of the resource to get geolocation - * @param callback GeolocationCallbackInterface: callback to report - * geolocation - */ - virtual void OnGeolocationShow(const std::string& origin, - NWebGeolocationCallbackInterface* callback) {} - - /** - * @brief Notify the host application that the web page wants to display a - * JavaScript alert() dialog. - * - * @param url String: The url of the page requesting the dialog. - * @param message String: The message of the dialog. - * @param result std::shared_ptr: A NWebJSDialogResult to - * confirm that the user closed the window. - * @return To show a custom dialog, the app should return true. - */ - virtual bool OnAlertDialogByJS(const std::string& url, - const std::string& message, - std::shared_ptr result) { - return false; - } - - /** - * @brief Notify the host application that the web page wants to handle - * JavaScript onbeforeunload. - * - * @param url String: The url of the page requesting. - * @param message String: The message of the dialog. - * @param result std::shared_ptr: A NWebJSDialogResult to - * confirm that the user closed the window. - * @return To show a custom dialog, the app should return true. - */ - virtual bool OnBeforeUnloadByJS(const std::string& url, - const std::string& message, - std::shared_ptr result) { - return false; - } - - /** - * @brief Notify the host application that the web page wants to display a - * JavaScript prompt() dialog. - * - * @param url String: The url of the page requesting the dialog. - * @param message String: The message of the dialog. - * @param defaultValue String: The default value of the input message. - * @param result std::shared_ptr: A NWebJSDialogResult to - * confirm that the user closed the window. - * @return To show a custom dialog, the app should return true. - */ - virtual bool OnPromptDialogByJs(const std::string& url, - const std::string& message, - const std::string& defaultValue, - std::shared_ptr result) { - return false; - } - - /** - * @brief Notify the host application that the web page wants to display a - * JavaScript Confirm() dialog. - * - * @param url String: The url of the page requesting the dialog. - * @param message String: The message of the dialog. - * @param result std::shared_ptr: A NWebJSDialogResult to - * confirm that the user closed the window. - * @return To show a custom dialog, the app should return true. - */ - virtual bool OnConfirmDialogByJS(const std::string& url, +public: + NWebHandler() = default; + + virtual ~NWebHandler() = default; + + virtual void SetNWeb(std::shared_ptr nweb) {} + + virtual void OnProxyDied() {} + + virtual void OnRouterPush(const std::string& param) {} + + virtual void OnMessage(const std::string& param) {} + + /** + * @brief Notify the SDK that a web site has finished loading. This method is + * called only for main frame. + * + * @param httpStatusCode The status code for the http request. + * @param url The url of the web site. + */ + virtual void OnPageLoadEnd(int httpStatusCode, const std::string& url) {} + + /** + * @brief Notify the SDK that a web site has started loading. This method is + * called once for each main frame load. + * + * @param url The url to be loaded. + */ + virtual void OnPageLoadBegin(const std::string& url) {} + + /** + * @brief Report a load error to the SDK. + * + * @param errorCode The error code. + * @param description The error description. + * @param failingUrl The failed url. + */ + virtual void OnPageLoadError(int errorCode, + const std::string& description, + const std::string& failingUrl) {} + + /** + * @brief Give the SDK a chance to decide wheather to continue loading the + * url. + * + * @param url The url to be loaded. + * @return true to cancel the loading, false to continue the loading. + */ + virtual bool OnHandleInterceptUrlLoading(const std::string& url) { + return false; + } + + /** + * @brief Notify the SDK that the nweb will load the resource specified by + * the given url. + * + * @param url The url of the resource. + */ + virtual void OnResource(const std::string& url) {} + + /** + * @brief Notify the SDK of the changed document title. + * + * @param title The document title. + */ + virtual void OnPageTitle(const std::string& title) {} + + /** + * @brief Notify the SDK the current progress of loading a web site. + * + * @param newProgress Loading progress, an integer between 0 and 100. + */ + virtual void OnLoadingProgress(int newProgress) {} + + /** + * @brief Request display and focus for a new nweb. + * + */ + virtual void OnFocus() {} + + /** + * @brief Obtains a list of all visited history items, used for link coloring + * + * @retval visited history + */ + virtual const std::vector VisitedUrlHistory() { + return std::vector(); + } + + /** + * @brief Notify the host application of a resource request and allow the + * application to return the data. + * + * @param request the resource response's MIME type, for example { + * "text/html"}. + * + * @retval if NWebUrlResourceResponse is null ,No interception. + */ + virtual std::shared_ptr OnHandleInterceptRequest( + std::shared_ptr request) { + return nullptr; + } + + /** + * @brief Report web resource loading error to the SDK. These errors usually + * indicate inability to connect to the server. + * + * @param request The request information. + * @param error The error information. + */ + virtual void OnResourceLoadError(std::shared_ptr request, + std::shared_ptr error) {} + + /** + * @brief Notify the SDK that an HTTP error has been received from the server + * while loading a resource. + * + * @param request The request information. + * @param errorResponse The error occurred. + */ + virtual void OnHttpError(std::shared_ptr request, + std::shared_ptr errorResponse) {} + + /** + * @brief Notify the SDK of a new favicon for the current web site. + * + * @param data The raw image data for the icon. + * @param width The width of the icon in pixel. + * @param height The height of the icon in pixel. + * @param color_type The color data encoding type. + * @param alpha_type The alpha value of any pixel. + */ + virtual void OnPageIcon(const void* data, + size_t width, + size_t height, + ImageColorType color_type, + ImageAlphaType alpha_type) {} + + /** + * @brief Notify the SDK of the url for an touch icon. + * + * @param icon_url The icon url. + * @param precomposed The touch icon type. + */ + virtual void OnDesktopIconUrl(const std::string& icon_url, bool precomposed) { + } + + /** + * @brief Report a JavaScript console message to the host application. + * + * @param message Details of the console message. + * @return Return true to stop the message from being output to the console. + */ + virtual bool OnConsoleLog(const NWebConsoleLog& message) { return false; } + + /** + * @brief Show prompt to ask for the geolocation permission. + * + * @param origin String: the origin of the resource to get geolocation + * @param callback GeolocationCallbackInterface: callback to report + * geolocation + */ + virtual void OnGeolocationShow(const std::string& origin, + NWebGeolocationCallbackInterface* callback) {} + + /** + * @brief Notify the host application that the web page wants to display a + * JavaScript alert() dialog. + * + * @param url String: The url of the page requesting the dialog. + * @param message String: The message of the dialog. + * @param result std::shared_ptr: A NWebJSDialogResult to + * confirm that the user closed the window. + * @return To show a custom dialog, the app should return true. + */ + virtual bool OnAlertDialogByJS(const std::string& url, const std::string& message, std::shared_ptr result) { - return false; - } - - /** - * @brief Hide prompt to ask for the geolocation permission. - */ - virtual void OnGeolocationHide() {} - - /** - * @brief - * - * @param request String: - */ - virtual void OnPermissionRequest( - std::shared_ptr request) {} - - /** - * @brief - * - * @param request String: - */ - virtual void OnPermissionRequestCanceled( - std::shared_ptr request) {} + return false; + } + + /** + * @brief Notify the host application that the web page wants to handle + * JavaScript onbeforeunload. + * + * @param url String: The url of the page requesting. + * @param message String: The message of the dialog. + * @param result std::shared_ptr: A NWebJSDialogResult to + * confirm that the user closed the window. + * @return To show a custom dialog, the app should return true. + */ + virtual bool OnBeforeUnloadByJS(const std::string& url, + const std::string& message, + std::shared_ptr result) { + return false; + } + + /** + * @brief Notify the host application that the web page wants to display a + * JavaScript prompt() dialog. + * + * @param url String: The url of the page requesting the dialog. + * @param message String: The message of the dialog. + * @param defaultValue String: The default value of the input message. + * @param result std::shared_ptr: A NWebJSDialogResult to + * confirm that the user closed the window. + * @return To show a custom dialog, the app should return true. + */ + virtual bool OnPromptDialogByJs(const std::string& url, + const std::string& message, + const std::string& defaultValue, + std::shared_ptr result) { + return false; + } + + /** + * @brief Notify the host application that the web page wants to display a + * JavaScript Confirm() dialog. + * + * @param url String: The url of the page requesting the dialog. + * @param message String: The message of the dialog. + * @param result std::shared_ptr: A NWebJSDialogResult to + * confirm that the user closed the window. + * @return To show a custom dialog, the app should return true. + */ + virtual bool OnConfirmDialogByJS(const std::string& url, + const std::string& message, + std::shared_ptr result) { + return false; + } + + /** + * @brief Hide prompt to ask for the geolocation permission. + */ + virtual void OnGeolocationHide() {} + + /** + * @brief + * + * @param request String: + */ + virtual void OnPermissionRequest(std::shared_ptr request) {} + + /** + * @brief + * + * @param request String: + */ + virtual void OnPermissionRequestCanceled(std::shared_ptr request) {} }; } // namespace OHOS::NWeb diff --git a/ohos_nweb/include/nweb_hit_testresult.h b/ohos_nweb/include/nweb_hit_testresult.h index 4eb0d0915b..510e471280 100755 --- a/ohos_nweb/include/nweb_hit_testresult.h +++ b/ohos_nweb/include/nweb_hit_testresult.h @@ -75,7 +75,6 @@ public: private: int type_; std::string extra_; - }; } diff --git a/ohos_nweb/include/nweb_js_dialog_result.h b/ohos_nweb/include/nweb_js_dialog_result.h index 13b0fe51f0..693a050f4a 100644 --- a/ohos_nweb/include/nweb_js_dialog_result.h +++ b/ohos_nweb/include/nweb_js_dialog_result.h @@ -12,19 +12,16 @@ namespace OHOS::NWeb { class OHOS_NWEB_EXPORT NWebJSDialogResult { public: virtual ~NWebJSDialogResult() = default; - /** * @brief Handle a confirmation response from the user. */ virtual void Confirm() = 0; - /** * @brief Handle a confirmation response from the user with input message. * * @param message confirm message. */ virtual void Confirm(const std::string &message) = 0; - /** * @brief Handle the result if the user cancelled the dialog. */ diff --git a/ohos_nweb/include/nweb_preference.h b/ohos_nweb/include/nweb_preference.h index ca85253000..cd9f3b430a 100644 --- a/ohos_nweb/include/nweb_preference.h +++ b/ohos_nweb/include/nweb_preference.h @@ -10,13 +10,11 @@ namespace OHOS::NWeb { class OHOS_NWEB_EXPORT NWebPreference { - public: +public: NWebPreference() = default; virtual ~NWebPreference() = default; - enum AccessMode { ALWAYS_ALLOW = 0, NEVER_ALLOW = 1, COMPATIBILITY_MODE = 2 }; - - /* synchronous set web settings and web preferences */ + /* synchronous set NWebPreference and web preferences */ virtual void PutEnableContentAccess(bool flag) = 0; virtual void PutEnableRawFileAccess(bool flag) = 0; virtual void PutEnableRawFileAccessFromFileURLs(bool flag) = 0; @@ -46,7 +44,7 @@ class OHOS_NWEB_EXPORT NWebPreference { AccessMode mode) = 0; virtual void PutZoomingFunctionEnabled(bool flag) = 0; - /* get methods*/ + /* get methods */ virtual bool EnableContentAccess() = 0; virtual bool EnableRawFileAccess() = 0; virtual bool EnableRawFileAccessFromFileURLs() = 0; diff --git a/ohos_nweb/include/nweb_url_resource_error.h b/ohos_nweb/include/nweb_url_resource_error.h index b24b7fbd90..dafc312994 100644 --- a/ohos_nweb/include/nweb_url_resource_error.h +++ b/ohos_nweb/include/nweb_url_resource_error.h @@ -19,7 +19,7 @@ public: * @brief Gets the error description. * * @brief Gets the ErrorInfo. - * + * * @return The description of the error. */ virtual const std::string &ErrorInfo() const = 0; diff --git a/ohos_nweb/include/nweb_value.h b/ohos_nweb/include/nweb_value.h index ee4c745e3c..e08d162fe9 100644 --- a/ohos_nweb/include/nweb_value.h +++ b/ohos_nweb/include/nweb_value.h @@ -16,55 +16,55 @@ namespace OHOS::NWeb { bool b; }; - class OHOS_NWEB_EXPORT NWebValue { - public: - enum class Type : unsigned char { - NONE = 0, - BOOLEAN, - INTEGER, - DOUBLE, - STRING, - BINARY, - DICTIONARY, - LIST - }; +class OHOS_NWEB_EXPORT NWebValue { +public: + enum class Type : unsigned char { + NONE = 0, + BOOLEAN, + INTEGER, + DOUBLE, + STRING, + BINARY, + DICTIONARY, + LIST + }; - NWebValue(Type type) : type_(type) {} + NWebValue(Type type) : type_(type) {} - ~NWebValue() = default; + ~NWebValue() = default; - bool GetBoolean() { return data_.b; } + bool GetBoolean() { return data_.b; } - void SetBoolean(bool b) { data_.b = b; } + void SetBoolean(bool b) { data_.b = b; } - void SetString(std::string str) { str_ = str; } + void SetString(std::string str) { str_ = str; } - std::string GetString() { return str_; } + std::string GetString() { return str_; } - void SetDouble(double dou) { data_.f = dou; } + void SetDouble(double dou) { data_.f = dou; } - double GetDouble() { return data_.f; } + double GetDouble() { return data_.f; } - void SetInt(int num) { data_.n = num; } + void SetInt(int num) { data_.n = num; } - int GetInt() { return data_.n; } + int GetInt() { return data_.n; } - void SetJsonString(std::string json_string) { str_json_ = json_string; } + void SetJsonString(std::string json_string) { str_json_ = json_string; } - std::string GetJsonString() { return str_json_; } + std::string GetJsonString() { return str_json_; } - Type GetType() { return type_; } + Type GetType() { return type_; } - void SetType(Type type) { type_ = type; } + void SetType(Type type) { type_ = type; } - int error_ = 0; + int error_ = 0; - private: - Type type_ = Type::NONE; - data_union data_; - std::string str_; - std::string str_json_; - }; +private: + Type type_ = Type::NONE; + data_union data_; + std::string str_; + std::string str_json_; +}; } #endif // NWEB_VALUE_H_ diff --git a/ohos_nweb/include/nweb_value_callback.h b/ohos_nweb/include/nweb_value_callback.h index aeba1f792a..4f521b4232 100644 --- a/ohos_nweb/include/nweb_value_callback.h +++ b/ohos_nweb/include/nweb_value_callback.h @@ -8,7 +8,7 @@ #include "nweb_export.h" namespace OHOS::NWeb { -template +template class OHOS_NWEB_EXPORT NWebValueCallback { public: NWebValueCallback() = default; diff --git a/ohos_nweb/src/cef_delegate/nweb_delegate.cc b/ohos_nweb/src/cef_delegate/nweb_delegate.cc index 16a7c15f74..475195e136 100755 --- a/ohos_nweb/src/cef_delegate/nweb_delegate.cc +++ b/ohos_nweb/src/cef_delegate/nweb_delegate.cc @@ -107,6 +107,10 @@ void NWebDelegate::Resize(uint32_t width, uint32_t height) { if (render_handler_ != nullptr) { render_handler_->Resize(width, height); } + auto browser = GetBrowser(); + if (browser != nullptr && browser->GetHost() != nullptr) { + browser->GetHost()->WasResized(); + } } void NWebDelegate::OnTouchPress(int32_t id, double x, double y) { diff --git a/ohos_nweb/src/cef_delegate/nweb_geolocation_callback.cc b/ohos_nweb/src/cef_delegate/nweb_geolocation_callback.cc index 893b92a9bb..31046871ce 100644 --- a/ohos_nweb/src/cef_delegate/nweb_geolocation_callback.cc +++ b/ohos_nweb/src/cef_delegate/nweb_geolocation_callback.cc @@ -13,14 +13,16 @@ void NWebGeolocationCallback::GeolocationCallbackInvoke( const std::string& origin, bool allow, bool retain) { - if (retain) { - if (allow) { - browser_->GetGeolocationPermissions()->Enabled(origin); - } else { - browser_->GetGeolocationPermissions()->Disabled(origin); - } - } - browser_->GetPermissionRequestDelegate()->NotifyGeolocationPermission(allow, - origin); + LOG(ERROR) << "NWebGeolocationCallback::GeolocationCallbackInvoke"; + return; + // if (retain) { + // if (allow) { + // browser_->GetGeolocationPermissions()->Enabled(origin); + // } else { + // browser_->GetGeolocationPermissions()->Disabled(origin); + // } + // } + // browser_->GetPermissionRequestDelegate()->NotifyGeolocationPermission(false, + // origin); } } // namespace OHOS::NWeb \ No newline at end of file diff --git a/ohos_nweb/src/cef_delegate/nweb_handler_delegate.cc b/ohos_nweb/src/cef_delegate/nweb_handler_delegate.cc index 6c3bef39d1..6fc789fd1e 100755 --- a/ohos_nweb/src/cef_delegate/nweb_handler_delegate.cc +++ b/ohos_nweb/src/cef_delegate/nweb_handler_delegate.cc @@ -294,7 +294,9 @@ void NWebHandlerDelegate::OnLoadStart(CefRefPtr browser, CefRefPtr frame, TransitionType transition_type) { LOG(INFO) << "NWebHandlerDelegate::OnLoadStart"; - + if (browser != nullptr && browser->GetHost() != nullptr) { + browser->GetHost()->SetFocus(true); + } if (nweb_handler_ != nullptr) { nweb_handler_->OnPageLoadBegin(frame->GetURL().ToString()); } diff --git a/ohos_nweb/src/cef_delegate/nweb_render_handler.cc b/ohos_nweb/src/cef_delegate/nweb_render_handler.cc index 4b85ca9122..ae7be00613 100644 --- a/ohos_nweb/src/cef_delegate/nweb_render_handler.cc +++ b/ohos_nweb/src/cef_delegate/nweb_render_handler.cc @@ -53,7 +53,21 @@ void NWebRenderHandler::OnPaint(CefRefPtr browser, int height) { // run render callback to take buffer. // note: buffer must be consumed asap with no lock protected - if (render_update_cb_ != nullptr) { + if (render_update_cb_ == nullptr) { + return; + } + if (width != width_ || height != height_) { + LOG(INFO) << "frame size(" << width << "*" << height + << ") is not identical to request size (" << width_ << "*" + << height_ << "), drop this frame"; + constexpr uint8_t kBitsPerPixel = 4; + uint32_t white_frame_size = width_ * height_ * kBitsPerPixel; + char* white_frame = new char[white_frame_size]; + const char pixel_in_white = 0xFF; + (void)memset(white_frame, pixel_in_white, white_frame_size); + render_update_cb_(white_frame); + delete[] white_frame; + } else { render_update_cb_(reinterpret_cast(buffer)); } } diff --git a/ohos_nweb/src/nweb_execute_process.cc b/ohos_nweb/src/nweb_execute_process.cc new file mode 100644 index 0000000000..02e9ea1950 --- /dev/null +++ b/ohos_nweb/src/nweb_execute_process.cc @@ -0,0 +1,35 @@ +// Copyright (c) 2022 Huawei Device Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include + +#include "include/cef_app.h" +#include "nweb_export.h" +#include "nweb_hilog.h" + +extern "C" OHOS_NWEB_EXPORT void NWebRenderMain(const char* args) { + WVLOG_I("NWebRenderMain start, pid=%{public}d", getpid()); + + std::string args_str = args; + std::stringstream args_ss(args_str); + const char separator = '#'; + std::vector argv_str; + std::string arg_str; + while(std::getline(args_ss, arg_str, separator)) { + argv_str.push_back(arg_str); + } + + std::vector argv_cstr; + int argc = argv_str.size(); + argv_cstr.reserve(argc + 1); + for (const auto& arg : argv_str) + argv_cstr.push_back(const_cast(arg.c_str())); + argv_cstr.push_back(nullptr); + + CefMainArgs main_args(argc, const_cast(argv_cstr.data())); + (void)CefExecuteProcess(main_args, NULL, NULL); + + WVLOG_I("NWebRenderMain end, pid=%{public}d", getpid()); +} \ No newline at end of file diff --git a/ohos_nweb/src/nweb_impl.cc b/ohos_nweb/src/nweb_impl.cc index 925a5561ef..21eeab89f2 100755 --- a/ohos_nweb/src/nweb_impl.cc +++ b/ohos_nweb/src/nweb_impl.cc @@ -135,9 +135,11 @@ bool NWebImpl::InitWebEngine() { void NWebImpl::InitWebEngineArgs(const NWebInitArgs& init_args) { web_engine_args_.clear(); web_engine_args_.emplace_back("/system/bin/web_render"); + // web_engine_args_.emplace_back("--disable-gpu"); web_engine_args_.emplace_back("--in-process-gpu"); web_engine_args_.emplace_back("--disable-dev-shm-usage"); web_engine_args_.emplace_back("--no-unsandboxed-zygote"); + web_engine_args_.emplace_back("--no-zygote"); web_engine_args_.emplace_back("--off-screen-frame-rate=60"); web_engine_args_.emplace_back("--enable-features=UseOzonePlatform"); web_engine_args_.emplace_back("-ozone-platform=headless"); @@ -335,7 +337,7 @@ std::string NWebImpl::Title() { return nweb_delegate_->Title(); } -const HitTestResult NWebImpl::GetHitTestResult() const { +HitTestResult NWebImpl::GetHitTestResult() const { return nweb_delegate_->GetHitTestResult(); } diff --git a/ohos_nweb/src/nweb_impl.h b/ohos_nweb/src/nweb_impl.h index 559f8487f2..dd0c16f178 100755 --- a/ohos_nweb/src/nweb_impl.h +++ b/ohos_nweb/src/nweb_impl.h @@ -56,7 +56,7 @@ class NWebImpl : public NWeb { void SetNWebHandler(std::shared_ptr handler) override; const std::shared_ptr GetNWebHandler() const override; std::string Title() override; - const HitTestResult GetHitTestResult() const override; + HitTestResult GetHitTestResult() const override; int PageLoadProgress() override; int ContentHeight() override; float Scale() override; diff --git a/ohos_nweb/src/nweb_input_handler.cc b/ohos_nweb/src/nweb_input_handler.cc index 710cbc5df4..78ea32c2b0 100644 --- a/ohos_nweb/src/nweb_input_handler.cc +++ b/ohos_nweb/src/nweb_input_handler.cc @@ -60,16 +60,6 @@ void NWebInputHandler::OnTouchMove(int32_t id, double x, double y) { return; } - // For multi-finger touch-move event get from ArkUI, some fingers may start - // move without previous touch-press event, which may cause these fingers - // unrecognized by web_engine, and multi-finger gestures like pinch unsupport. - // For this reason, the first touch-move event would be treated as touch-press - // event. - if (touch_press_id_map_.find(id) == touch_press_id_map_.end() || - !touch_press_id_map_.at(id)) { - this->OnTouchPress(id, x, y); - } - nweb_delegate_->OnTouchMove(id, x, y); last_x_ = x; last_y_ = y; diff --git a/ohos_nweb/src/nweb_inputmethod_handler.cc b/ohos_nweb/src/nweb_inputmethod_handler.cc index 0456edc290..5bb55cf39c 100644 --- a/ohos_nweb/src/nweb_inputmethod_handler.cc +++ b/ohos_nweb/src/nweb_inputmethod_handler.cc @@ -41,7 +41,12 @@ class OnTextChangedListenerImpl } void SendKeyboardInfo(const OHOS::MiscServices::KeyboardInfo& info) override { - + auto status = info.GetKeyboardStatus(); + if (status == OHOS::MiscServices::KeyboardStatus::SHOW) { + handler_->SetIMEStatus(true); + } else if (status == OHOS::MiscServices::KeyboardStatus::HIDE) { + handler_->SetIMEStatus(false); + } } void SetKeyboardStatus(bool status) override { @@ -76,11 +81,14 @@ class InputMethodTask : public CefTask { }; NWebInputMethodHandler::NWebInputMethodHandler() - : selected_from_(0), selected_to_(0) {} + : selected_from_(0), selected_to_(0) { + g_listener = nullptr; +} NWebInputMethodHandler::~NWebInputMethodHandler() {} void NWebInputMethodHandler::Attach(CefRefPtr browser) { + composing_text_.clear(); browser_ = browser; if (ime_shown_) { return; @@ -105,6 +113,11 @@ void NWebInputMethodHandler::OnTextSelectionChanged( CefRefPtr browser, const CefString& selected_text, const CefRange& selected_range) { + if (ime_text_composing_ && !composing_text_.empty()) { + if (browser_ != nullptr && browser_->GetHost() != nullptr) { + browser_->GetHost()->ImeFinishComposingText(false); + } + } selected_text_ = selected_text.ToString16(); selected_from_ = selected_range.from; selected_to_ = selected_range.to; @@ -148,6 +161,7 @@ void NWebInputMethodHandler::SetIMEStatusOnUI(bool status) { if (!status && ime_text_composing_) { browser_->GetHost()->ImeFinishComposingText(false); ime_text_composing_ = false; + composing_text_.clear(); } ime_shown_ = status; } diff --git a/ohos_nweb/src/nweb_render_main.cc b/ohos_nweb/src/nweb_render_main.cc new file mode 100644 index 0000000000..b0b3122e56 --- /dev/null +++ b/ohos_nweb/src/nweb_render_main.cc @@ -0,0 +1,34 @@ +// Copyright (c) 2022 Huawei Device Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include + +#include "include/cef_app.h" +#include "nweb_export.h" +#include "nweb_hilog.h" + +extern "C" OHOS_NWEB_EXPORT void NWebRenderMain(const char* args) { + WVLOG_I("NWebRenderMain start, pid=%{public}d", getpid()); + + std::string args_str = args; + std::stringstream args_ss(args_str); + const char separator = '#'; + std::vector argv_str; + std::string arg_str; + while(std::getline(args_ss, arg_str, separator)) { + argv_str.push_back(arg_str); + } + std::vector argv_cstr; + int argc = argv_str.size(); + argv_cstr.reserve(argc + 1); + for (const auto& arg : argv_str) + argv_cstr.push_back(const_cast(arg.c_str())); + argv_cstr.push_back(nullptr); + + CefMainArgs main_args(argc, const_cast(argv_cstr.data())); + (void)CefExecuteProcess(main_args, NULL, NULL); + + WVLOG_I("NWebRenderMain end, pid=%{public}d", getpid()); +} \ No newline at end of file diff --git a/ohos_nweb/src/ohos_nweb_main.cc b/ohos_nweb/src/ohos_nweb_main.cc index defaae1499..bcce6266f6 100644 --- a/ohos_nweb/src/ohos_nweb_main.cc +++ b/ohos_nweb/src/ohos_nweb_main.cc @@ -3,15 +3,67 @@ // found in the LICENSE file. #include +#include #include "include/cef_app.h" #include "nweb_hilog.h" int main(int argc, const char* argv[]) { WVLOG_I("nweb subprocess %{public}s begin, pid=%{public}d", argv[0], getpid()); - - CefMainArgs main_args(argc, const_cast(argv)); - (void)CefExecuteProcess(main_args, NULL, NULL); +#ifdef __MUSL__ + Dl_namespace dlns; + dlns_init(&dlns, "nweb_test_ns"); + dlns_create(&dlns, "/data/app/el1/bundle/public/com.ohos.nweb/libs/arm"); + const std::string LIB_PATH_NWEB_RENDER = "libnweb_render.so"; + const std::string LIB_PATH_WEB_ENGINE = "libweb_engine.so"; + void *libHandleWebEngine = dlopen_ns(&dlns, LIB_PATH_WEB_ENGINE.c_str(), RTLD_NOW); + if (libHandleWebEngine == nullptr) { + WVLOG_E("fail to dlopen %{public}s, errmsg=%{public}s", LIB_PATH_WEB_ENGINE.c_str(), dlerror()); + return -1; + } + void *libHandleNWebRender = dlopen_ns(&dlns, LIB_PATH_NWEB_RENDER.c_str(), RTLD_NOW); + if (libHandleNWebRender == nullptr) { + WVLOG_E("fail to dlopen %{public}s, errmsg=%{public}s", LIB_PATH_NWEB_RENDER.c_str(), dlerror()); + return -1; + } +#else + const std::string LOAD_LIB_DIR_INSTALLATION = "/data/app/el1/bundle/public/com.ohos.nweb/libs/arm"; + const std::string LIB_PATH_WEB_ENGINE = LOAD_LIB_DIR_INSTALLATION + "/libweb_engine.so"; + const std::string LIB_PATH_NWEB_RENDER = LOAD_LIB_DIR_INSTALLATION + "/libnweb_render.so"; + void *libHandleWebEngine = ::dlopen(LIB_PATH_WEB_ENGINE.c_str(), RTLD_NOW); + if (libHandleWebEngine == nullptr) { + WVLOG_E("fail to dlopen %{public}s, errmsg=%{public}s", LIB_PATH_WEB_ENGINE.c_str(), dlerror()); + return -1; + } + void *libHandleNWebRender = ::dlopen(LIB_PATH_NWEB_RENDER.c_str(), RTLD_NOW); + if (libHandleNWebRender == nullptr) { + WVLOG_E("fail to dlopen %{public}s, errmsg=%{public}s", LIB_PATH_NWEB_RENDER.c_str(), dlerror()); + return -1; + } +#endif + using NWebRenderMainFunc = void (*)(const char* args); + const std::string NWEB_RENDER_MAIN = "NWebRenderMain"; + NWebRenderMainFunc func = + reinterpret_cast(dlsym(libHandleNWebRender, NWEB_RENDER_MAIN.c_str())); + if (func == nullptr) { + WVLOG_E("fail to dlsym %{public}s from libnweb_render.so", NWEB_RENDER_MAIN.c_str()); + return -1; + } + std::stringstream argv_ss; + const char separator = '#'; + for (int i=0; i LocationArbitrator::NewSystemLocationProvider() { -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_FUCHSIA) +#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_FUCHSIA) || defined(OS_OHOS) return nullptr; #else return device::NewSystemLocationProvider(); diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc index 374ea34a12..c2a4e52a90 100644 --- a/services/network/cors/cors_url_loader.cc +++ b/services/network/cors/cors_url_loader.cc @@ -296,13 +296,6 @@ void CorsURLLoader::OnReceiveRedirect(const net::RedirectInfo& redirect_info, DCHECK(forwarding_client_); DCHECK(!deferred_redirect_url_); - if (request_.redirect_mode == mojom::RedirectMode::kManual) { - deferred_redirect_url_ = std::make_unique(redirect_info.new_url); - forwarding_client_->OnReceiveRedirect(redirect_info, - std::move(response_head)); - return; - } - // If |CORS flag| is set and a CORS check for |request| and |response| returns // failure, then return a network error. if (fetch_cors_flag_ && IsCorsEnabledRequestMode(request_.mode)) { @@ -320,6 +313,13 @@ void CorsURLLoader::OnReceiveRedirect(const net::RedirectInfo& redirect_info, } } + if (request_.redirect_mode == mojom::RedirectMode::kManual) { + deferred_redirect_url_ = std::make_unique(redirect_info.new_url); + forwarding_client_->OnReceiveRedirect(redirect_info, + std::move(response_head)); + return; + } + timing_allow_failed_flag_ = !PassesTimingAllowOriginCheck(*response_head); // Because we initiate a new request on redirect in some cases, we cannot diff --git a/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc b/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc index 77cd931b5f..c16affe394 100644 --- a/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc +++ b/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc @@ -105,7 +105,8 @@ void CoordinatorImpl::RegisterClientProcess( const base::Optional& service_name) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); mojo::Remote process(std::move(client_process)); - coordinator_receivers_.Add(this, std::move(receiver), process_id); + if (receiver.is_valid()) + coordinator_receivers_.Add(this, std::move(receiver), process_id); process.set_disconnect_handler( base::BindOnce(&CoordinatorImpl::UnregisterClientProcess, base::Unretained(this), process_id)); diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc index ca0e8d8441..ae9ef93eaf 100644 --- a/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc +++ b/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc @@ -24,6 +24,11 @@ void ClientProcessImpl::CreateInstance( mojo::PendingReceiver receiver, mojo::PendingRemote coordinator, bool is_browser_process) { + // Intentionally disallow non-browser processes from ever holding a + // Coordinator. + if (!is_browser_process) + coordinator.reset(); + static ClientProcessImpl* instance = nullptr; if (!instance) { instance = new ClientProcessImpl( @@ -39,10 +44,12 @@ ClientProcessImpl::ClientProcessImpl( mojo::PendingRemote coordinator, bool is_browser_process, bool initialize_memory_instrumentation) - : receiver_(this, std::move(receiver)) { + : receiver_(this, std::move(receiver)), + is_browser_process_(is_browser_process) { if (initialize_memory_instrumentation) { // Initialize the public-facing MemoryInstrumentation helper. - MemoryInstrumentation::CreateInstance(std::move(coordinator)); + MemoryInstrumentation::CreateInstance(std::move(coordinator), + is_browser_process); } else { coordinator_.Bind(std::move(coordinator)); } @@ -109,6 +116,8 @@ void ClientProcessImpl::OnChromeMemoryDumpDone( void ClientProcessImpl::RequestGlobalMemoryDump_NoCallback( base::trace_event::MemoryDumpType dump_type, base::trace_event::MemoryDumpLevelOfDetail level_of_detail) { + CHECK(is_browser_process_); + if (!task_runner_->RunsTasksInCurrentSequence()) { task_runner_->PostTask( FROM_HERE, diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h b/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h index 6dd8c55823..8c2c20c449 100644 --- a/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h +++ b/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h @@ -96,6 +96,9 @@ class COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MEMORY_INSTRUMENTATION) mojo::Remote coordinator_; scoped_refptr task_runner_; + // Only browser process is allowed to request memory dumps. + const bool is_browser_process_; + // TODO(crbug.com/728199): The observer is only used to setup and tear down // MemoryDumpManager in each process. Setting up MemoryDumpManager should // be moved away from TracingObserver. diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.cc index c81d5f83bf..ec90ab9211 100644 --- a/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.cc +++ b/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.cc @@ -21,10 +21,11 @@ void WrapGlobalMemoryDump( // static void MemoryInstrumentation::CreateInstance( - mojo::PendingRemote - coordinator) { + mojo::PendingRemote coordinator, + bool is_browser_process) { DCHECK(!g_instance); - g_instance = new MemoryInstrumentation(std::move(coordinator)); + g_instance = + new MemoryInstrumentation(std::move(coordinator), is_browser_process); } // static @@ -33,8 +34,10 @@ MemoryInstrumentation* MemoryInstrumentation::GetInstance() { } MemoryInstrumentation::MemoryInstrumentation( - mojo::PendingRemote coordinator) - : coordinator_(std::move(coordinator)) {} + mojo::PendingRemote coordinator, + bool is_browser_process) + : coordinator_(std::move(coordinator)), + is_browser_process_(is_browser_process) {} MemoryInstrumentation::~MemoryInstrumentation() { g_instance = nullptr; @@ -43,6 +46,7 @@ MemoryInstrumentation::~MemoryInstrumentation() { void MemoryInstrumentation::RequestGlobalDump( const std::vector& allocator_dump_names, RequestGlobalDumpCallback callback) { + CHECK(is_browser_process_); coordinator_->RequestGlobalMemoryDump( MemoryDumpType::SUMMARY_ONLY, MemoryDumpLevelOfDetail::BACKGROUND, MemoryDumpDeterminism::NONE, allocator_dump_names, @@ -52,6 +56,7 @@ void MemoryInstrumentation::RequestGlobalDump( void MemoryInstrumentation::RequestPrivateMemoryFootprint( base::ProcessId pid, RequestGlobalDumpCallback callback) { + CHECK(is_browser_process_); coordinator_->RequestPrivateMemoryFootprint( pid, base::BindOnce(&WrapGlobalMemoryDump, std::move(callback))); } @@ -60,6 +65,7 @@ void MemoryInstrumentation::RequestGlobalDumpForPid( base::ProcessId pid, const std::vector& allocator_dump_names, RequestGlobalDumpCallback callback) { + CHECK(is_browser_process_); coordinator_->RequestGlobalMemoryDumpForPid( pid, allocator_dump_names, base::BindOnce(&WrapGlobalMemoryDump, std::move(callback))); @@ -70,6 +76,7 @@ void MemoryInstrumentation::RequestGlobalDumpAndAppendToTrace( MemoryDumpLevelOfDetail level_of_detail, MemoryDumpDeterminism determinism, RequestGlobalMemoryDumpAndAppendToTraceCallback callback) { + CHECK(is_browser_process_); coordinator_->RequestGlobalMemoryDumpAndAppendToTrace( dump_type, level_of_detail, determinism, std::move(callback)); } diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h b/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h index 3264917890..72157b5345 100644 --- a/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h +++ b/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h @@ -34,7 +34,8 @@ class COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MEMORY_INSTRUMENTATION) static void CreateInstance( mojo::PendingRemote - coordinator); + coordinator, + bool is_browser_process); static MemoryInstrumentation* GetInstance(); // Retrieves a Coordinator interface to communicate with the service. This is @@ -100,12 +101,16 @@ class COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MEMORY_INSTRUMENTATION) private: explicit MemoryInstrumentation( mojo::PendingRemote - coordinator); + coordinator, + bool is_browser_process); ~MemoryInstrumentation(); const mojo::SharedRemote coordinator_; + // Only browser process is allowed to request memory dumps. + const bool is_browser_process_; + DISALLOW_COPY_AND_ASSIGN(MemoryInstrumentation); }; diff --git a/services/viz/public/cpp/gpu/context_provider_command_buffer.cc b/services/viz/public/cpp/gpu/context_provider_command_buffer.cc index 2a37d497b4..7b4ee07dbb 100644 --- a/services/viz/public/cpp/gpu/context_provider_command_buffer.cc +++ b/services/viz/public/cpp/gpu/context_provider_command_buffer.cc @@ -477,9 +477,13 @@ const gpu::GpuFeatureInfo& ContextProviderCommandBuffer::GetGpuFeatureInfo() void ContextProviderCommandBuffer::OnLostContext() { CheckValidThreadOrLockAcquired(); - // Ensure |this| isn't destroyed in the middle of OnLostContext() if observers - // drop all references to it. - scoped_refptr ref(this); + // Observers may drop the last persistent references to `this`, but there may + // be weak references in use further up the stack. This task is posted to + // ensure that destruction is deferred until it's safe. + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce([](scoped_refptr) {}, + base::WrapRefCounted(this))); for (auto& observer : observers_) observer.OnContextLost(); diff --git a/storage/browser/blob/blob_registry_impl.cc b/storage/browser/blob/blob_registry_impl.cc index 34e736e80d..2479803044 100644 --- a/storage/browser/blob/blob_registry_impl.cc +++ b/storage/browser/blob/blob_registry_impl.cc @@ -629,13 +629,14 @@ void BlobRegistryImpl::GetBlobFromUUID( void BlobRegistryImpl::URLStoreForOrigin( const url::Origin& origin, mojo::PendingAssociatedReceiver receiver) { - // TODO(mek): Pass origin on to BlobURLStoreImpl so it can use it to generate - // Blob URLs, and verify at this point that the renderer can create URLs for - // that origin. Delegate* delegate = receivers_.current_context().get(); DCHECK(delegate); + if (!origin.opaque() && !delegate->CanCommitURL(origin.GetURL())) { + mojo::ReportBadMessage( + "Non committable origin passed to BlobRegistryImpl::URLStoreForOrigin"); + } auto self_owned_associated_receiver = mojo::MakeSelfOwnedAssociatedReceiver( - std::make_unique(url_registry_, delegate), + std::make_unique(origin, url_registry_), std::move(receiver)); if (g_url_store_creation_hook) g_url_store_creation_hook->Run(self_owned_associated_receiver); diff --git a/storage/browser/blob/blob_url_store_impl.cc b/storage/browser/blob/blob_url_store_impl.cc index b46ee60849..02281e3e5f 100644 --- a/storage/browser/blob/blob_url_store_impl.cc +++ b/storage/browser/blob/blob_url_store_impl.cc @@ -5,6 +5,7 @@ #include "storage/browser/blob/blob_url_store_impl.h" #include "base/bind.h" +#include "base/strings/strcat.h" #include "mojo/public/cpp/bindings/receiver_set.h" #include "storage/browser/blob/blob_impl.h" #include "storage/browser/blob/blob_url_loader_factory.h" @@ -58,9 +59,9 @@ class BlobURLTokenImpl : public blink::mojom::BlobURLToken { const base::UnguessableToken token_; }; -BlobURLStoreImpl::BlobURLStoreImpl(base::WeakPtr registry, - BlobRegistryImpl::Delegate* delegate) - : registry_(std::move(registry)), delegate_(delegate) {} +BlobURLStoreImpl::BlobURLStoreImpl(const url::Origin& origin, + base::WeakPtr registry) + : origin_(origin), registry_(std::move(registry)) {} BlobURLStoreImpl::~BlobURLStoreImpl() { if (registry_) { @@ -72,20 +73,9 @@ BlobURLStoreImpl::~BlobURLStoreImpl() { void BlobURLStoreImpl::Register(mojo::PendingRemote blob, const GURL& url, RegisterCallback callback) { - if (!url.SchemeIsBlob()) { - mojo::ReportBadMessage("Invalid scheme passed to BlobURLStore::Register"); - std::move(callback).Run(); - return; - } - if (!delegate_->CanCommitURL(url)) { - mojo::ReportBadMessage( - "Non committable URL passed to BlobURLStore::Register"); - std::move(callback).Run(); - return; - } - if (BlobUrlUtils::UrlHasFragment(url)) { - mojo::ReportBadMessage( - "URL with fragment passed to BlobURLStore::Register"); + // TODO(mek): Generate blob URLs here, rather than validating the URLs the + // renderer process generated. + if (!BlobUrlIsValid(url, "Register")) { std::move(callback).Run(); return; } @@ -97,19 +87,8 @@ void BlobURLStoreImpl::Register(mojo::PendingRemote blob, } void BlobURLStoreImpl::Revoke(const GURL& url) { - if (!url.SchemeIsBlob()) { - mojo::ReportBadMessage("Invalid scheme passed to BlobURLStore::Revoke"); - return; - } - if (!delegate_->CanCommitURL(url)) { - mojo::ReportBadMessage( - "Non committable URL passed to BlobURLStore::Revoke"); + if (!BlobUrlIsValid(url, "Revoke")) return; - } - if (BlobUrlUtils::UrlHasFragment(url)) { - mojo::ReportBadMessage("URL with fragment passed to BlobURLStore::Revoke"); - return; - } if (registry_) registry_->RemoveUrlMapping(url); @@ -125,6 +104,40 @@ void BlobURLStoreImpl::Resolve(const GURL& url, ResolveCallback callback) { std::move(callback).Run(std::move(blob)); } +bool BlobURLStoreImpl::BlobUrlIsValid(const GURL& url, + const char* method) const { + if (!url.SchemeIsBlob()) { + mojo::ReportBadMessage( + base::StrCat({"Invalid scheme passed to BlobURLStore::", method})); + return false; + } + url::Origin url_origin = url::Origin::Create(url); + // For file:// origins blink sometimes creates blob URLs with "null" as origin + // and other times "file://" (based on a runtime setting). On the other hand, + // `origin_` will always be a non-opaque file: origin for pages loaded from + // file:// URLs. To deal with this, we treat file:// origins and + // opaque origins separately from non-opaque origins. + bool valid_origin = true; + if (url_origin.scheme() == url::kFileScheme) { + valid_origin = origin_.scheme() == url::kFileScheme; + } else if (url_origin.opaque()) { + valid_origin = origin_.opaque() || origin_.scheme() == url::kFileScheme; + } else { + valid_origin = origin_ == url_origin; + } + if (!valid_origin) { + mojo::ReportBadMessage(base::StrCat( + {"URL with invalid origin passed to BlobURLStore::", method})); + return false; + } + if (BlobUrlUtils::UrlHasFragment(url)) { + mojo::ReportBadMessage( + base::StrCat({"URL with fragment passed to BlobURLStore::", method})); + return false; + } + return true; +} + void BlobURLStoreImpl::ResolveAsURLLoaderFactory( const GURL& url, mojo::PendingReceiver receiver) { diff --git a/storage/browser/blob/blob_url_store_impl.h b/storage/browser/blob/blob_url_store_impl.h index 6b4a738a46..3cada75583 100644 --- a/storage/browser/blob/blob_url_store_impl.h +++ b/storage/browser/blob/blob_url_store_impl.h @@ -11,8 +11,9 @@ #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/remote.h" -#include "storage/browser/blob/blob_registry_impl.h" +#include "storage/browser/blob/blob_url_registry.h" #include "third_party/blink/public/mojom/blob/blob_url_store.mojom.h" +#include "url/origin.h" namespace storage { @@ -21,8 +22,8 @@ class BlobUrlRegistry; class COMPONENT_EXPORT(STORAGE_BROWSER) BlobURLStoreImpl : public blink::mojom::BlobURLStore { public: - BlobURLStoreImpl(base::WeakPtr registry, - BlobRegistryImpl::Delegate* delegate); + BlobURLStoreImpl(const url::Origin& origin, + base::WeakPtr registry); ~BlobURLStoreImpl() override; void Register(mojo::PendingRemote blob, @@ -39,8 +40,12 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) BlobURLStoreImpl mojo::PendingReceiver token) override; private: + // Checks if the passed in url is a valid blob url for this blob url store. + // Returns false and reports a bad mojo message if not. + bool BlobUrlIsValid(const GURL& url, const char* method) const; + + const url::Origin origin_; base::WeakPtr registry_; - BlobRegistryImpl::Delegate* delegate_; std::set urls_; diff --git a/storage/browser/blob/blob_url_store_impl_unittest.cc b/storage/browser/blob/blob_url_store_impl_unittest.cc index 69428d0ade..52d17152b3 100644 --- a/storage/browser/blob/blob_url_store_impl_unittest.cc +++ b/storage/browser/blob/blob_url_store_impl_unittest.cc @@ -17,7 +17,6 @@ #include "storage/browser/blob/blob_impl.h" #include "storage/browser/blob/blob_storage_context.h" #include "storage/browser/blob/blob_url_registry.h" -#include "storage/browser/test/mock_blob_registry_delegate.h" #include "testing/gtest/include/gtest/gtest.h" using blink::mojom::BlobURLStore; @@ -69,9 +68,9 @@ class BlobURLStoreImplTest : public testing::Test { mojo::PendingRemote CreateURLStore() { mojo::PendingRemote result; - mojo::MakeSelfOwnedReceiver(std::make_unique( - url_registry_.AsWeakPtr(), &delegate_), - result.InitWithNewPipeAndPassReceiver()); + mojo::MakeSelfOwnedReceiver( + std::make_unique(kOrigin, url_registry_.AsWeakPtr()), + result.InitWithNewPipeAndPassReceiver()); return result; } @@ -101,15 +100,19 @@ class BlobURLStoreImplTest : public testing::Test { } const std::string kId = "id"; - const GURL kValidUrl = GURL("blob:id"); + const url::Origin kOrigin = url::Origin::Create(GURL("https://example.com")); + const GURL kValidUrl = GURL("blob:" + kOrigin.Serialize() + "/id1"); + const GURL kValidUrl2 = GURL("blob:" + kOrigin.Serialize() + "/id2"); const GURL kInvalidUrl = GURL("bolb:id"); - const GURL kFragmentUrl = GURL("blob:id#fragment"); + const GURL kFragmentUrl = GURL(kValidUrl.spec() + "#fragment"); + const url::Origin kWrongOrigin = + url::Origin::Create(GURL("https://test.com")); + const GURL kWrongOriginUrl = GURL("blob:" + kWrongOrigin.Serialize() + "/id"); protected: base::test::TaskEnvironment task_environment_; std::unique_ptr context_; BlobUrlRegistry url_registry_; - MockBlobRegistryDelegate delegate_; std::vector bad_messages_; }; @@ -118,7 +121,7 @@ TEST_F(BlobURLStoreImplTest, BasicRegisterRevoke) { CreateBlobFromString(kId, "hello world"); // Register a URL and make sure the URL keeps the blob alive. - BlobURLStoreImpl url_store(url_registry_.AsWeakPtr(), &delegate_); + BlobURLStoreImpl url_store(kOrigin, url_registry_.AsWeakPtr()); RegisterURL(&url_store, std::move(blob), kValidUrl); blob = url_registry_.GetBlobFromUrl(kValidUrl); @@ -146,15 +149,13 @@ TEST_F(BlobURLStoreImplTest, RegisterInvalidScheme) { EXPECT_EQ(1u, bad_messages_.size()); } -TEST_F(BlobURLStoreImplTest, RegisterCantCommit) { +TEST_F(BlobURLStoreImplTest, RegisterWrongOrigin) { mojo::PendingRemote blob = CreateBlobFromString(kId, "hello world"); - delegate_.can_commit_url_result = false; - mojo::Remote url_store(CreateURLStore()); - RegisterURL(url_store.get(), std::move(blob), kValidUrl); - EXPECT_FALSE(url_registry_.GetBlobFromUrl(kValidUrl)); + RegisterURL(url_store.get(), std::move(blob), kWrongOriginUrl); + EXPECT_FALSE(url_registry_.GetBlobFromUrl(kWrongOriginUrl)); EXPECT_EQ(1u, bad_messages_.size()); } @@ -169,14 +170,13 @@ TEST_F(BlobURLStoreImplTest, RegisterUrlFragment) { } TEST_F(BlobURLStoreImplTest, ImplicitRevoke) { - const GURL kValidUrl2("blob:id2"); mojo::Remote blob( CreateBlobFromString(kId, "hello world")); mojo::PendingRemote blob2; blob->Clone(blob2.InitWithNewPipeAndPassReceiver()); auto url_store = - std::make_unique(url_registry_.AsWeakPtr(), &delegate_); + std::make_unique(kOrigin, url_registry_.AsWeakPtr()); RegisterURL(url_store.get(), blob.Unbind(), kValidUrl); EXPECT_TRUE(url_registry_.GetBlobFromUrl(kValidUrl)); RegisterURL(url_store.get(), std::move(blob2), kValidUrl2); @@ -192,8 +192,8 @@ TEST_F(BlobURLStoreImplTest, RevokeThroughDifferentURLStore) { mojo::PendingRemote blob = CreateBlobFromString(kId, "hello world"); - BlobURLStoreImpl url_store1(url_registry_.AsWeakPtr(), &delegate_); - BlobURLStoreImpl url_store2(url_registry_.AsWeakPtr(), &delegate_); + BlobURLStoreImpl url_store1(kOrigin, url_registry_.AsWeakPtr()); + BlobURLStoreImpl url_store2(kOrigin, url_registry_.AsWeakPtr()); RegisterURL(&url_store1, std::move(blob), kValidUrl); EXPECT_TRUE(url_registry_.GetBlobFromUrl(kValidUrl)); @@ -209,11 +209,9 @@ TEST_F(BlobURLStoreImplTest, RevokeInvalidScheme) { EXPECT_EQ(1u, bad_messages_.size()); } -TEST_F(BlobURLStoreImplTest, RevokeCantCommit) { - delegate_.can_commit_url_result = false; - +TEST_F(BlobURLStoreImplTest, RevokeWrongOrigin) { mojo::Remote url_store(CreateURLStore()); - url_store->Revoke(kValidUrl); + url_store->Revoke(kWrongOriginUrl); url_store.FlushForTesting(); EXPECT_EQ(1u, bad_messages_.size()); } @@ -229,7 +227,7 @@ TEST_F(BlobURLStoreImplTest, Resolve) { mojo::PendingRemote blob = CreateBlobFromString(kId, "hello world"); - BlobURLStoreImpl url_store(url_registry_.AsWeakPtr(), &delegate_); + BlobURLStoreImpl url_store(kOrigin, url_registry_.AsWeakPtr()); RegisterURL(&url_store, std::move(blob), kValidUrl); blob = ResolveURL(&url_store, kValidUrl); @@ -244,7 +242,7 @@ TEST_F(BlobURLStoreImplTest, Resolve) { } TEST_F(BlobURLStoreImplTest, ResolveNonExistentURL) { - BlobURLStoreImpl url_store(url_registry_.AsWeakPtr(), &delegate_); + BlobURLStoreImpl url_store(kOrigin, url_registry_.AsWeakPtr()); mojo::PendingRemote blob = ResolveURL(&url_store, kValidUrl); @@ -254,7 +252,7 @@ TEST_F(BlobURLStoreImplTest, ResolveNonExistentURL) { } TEST_F(BlobURLStoreImplTest, ResolveInvalidURL) { - BlobURLStoreImpl url_store(url_registry_.AsWeakPtr(), &delegate_); + BlobURLStoreImpl url_store(kOrigin, url_registry_.AsWeakPtr()); mojo::PendingRemote blob = ResolveURL(&url_store, kInvalidUrl); @@ -265,7 +263,7 @@ TEST_F(BlobURLStoreImplTest, ResolveAsURLLoaderFactory) { mojo::PendingRemote blob = CreateBlobFromString(kId, "hello world"); - BlobURLStoreImpl url_store(url_registry_.AsWeakPtr(), &delegate_); + BlobURLStoreImpl url_store(kOrigin, url_registry_.AsWeakPtr()); RegisterURL(&url_store, std::move(blob), kValidUrl); mojo::Remote factory; @@ -291,7 +289,7 @@ TEST_F(BlobURLStoreImplTest, ResolveForNavigation) { mojo::PendingRemote blob = CreateBlobFromString(kId, "hello world"); - BlobURLStoreImpl url_store(url_registry_.AsWeakPtr(), &delegate_); + BlobURLStoreImpl url_store(kOrigin, url_registry_.AsWeakPtr()); RegisterURL(&url_store, std::move(blob), kValidUrl); mojo::Remote token_remote; diff --git a/third_party/angle/src/libANGLE/Framebuffer.cpp b/third_party/angle/src/libANGLE/Framebuffer.cpp index 7d9856d15c..48cf822901 100644 --- a/third_party/angle/src/libANGLE/Framebuffer.cpp +++ b/third_party/angle/src/libANGLE/Framebuffer.cpp @@ -1925,6 +1925,14 @@ void Framebuffer::onSubjectStateChange(angle::SubjectIndex index, angle::Subject return; } + // This can be triggered by freeing TextureStorage in D3D back-end. + if (message == angle::SubjectMessage::StorageReleased) + { + mDirtyBits.set(index); + invalidateCompletenessCache(); + return; + } + // This can be triggered by the GL back-end TextureGL class. ASSERT(message == angle::SubjectMessage::DirtyBitsFlagged); return; diff --git a/third_party/angle/src/libANGLE/Observer.h b/third_party/angle/src/libANGLE/Observer.h index ae83677c77..bb2acd0210 100644 --- a/third_party/angle/src/libANGLE/Observer.h +++ b/third_party/angle/src/libANGLE/Observer.h @@ -54,6 +54,9 @@ enum class SubjectMessage // Indicates an external change to the default framebuffer. SurfaceChanged, + + // Indicates a Storage of back-end in gl::Texture has been released. + StorageReleased, }; // The observing class inherits from this interface class. diff --git a/third_party/angle/src/libANGLE/Texture.cpp b/third_party/angle/src/libANGLE/Texture.cpp index e90bfd7c7d..09aa3a5fb5 100644 --- a/third_party/angle/src/libANGLE/Texture.cpp +++ b/third_party/angle/src/libANGLE/Texture.cpp @@ -2236,6 +2236,15 @@ void Texture::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMess mState.setImageDesc(TextureTarget::Buffer, 0, desc); } break; + case angle::SubjectMessage::StorageReleased: + // When the TextureStorage is released, it needs to update the + // RenderTargetCache of the Framebuffer attaching this Texture. + // This is currently only for D3D back-end. See http://crbug.com/1234829 + if (index == rx::kTextureImageImplObserverMessageIndex) + { + onStateChange(angle::SubjectMessage::StorageReleased); + } + break; case angle::SubjectMessage::SubjectMapped: case angle::SubjectMessage::SubjectUnmapped: case angle::SubjectMessage::BindingChanged: diff --git a/third_party/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp b/third_party/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp index 3a1b58b282..fc5ace1c05 100644 --- a/third_party/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp +++ b/third_party/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp @@ -710,6 +710,8 @@ angle::Result TextureD3D::releaseTexStorage(const gl::Context *context) return angle::Result::Continue; } + onStateChange(angle::SubjectMessage::StorageReleased); + auto err = mTexStorage->onDestroy(context); SafeDelete(mTexStorage); return err; diff --git a/third_party/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp b/third_party/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp index 8321bb60cd..7588a161eb 100644 --- a/third_party/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp +++ b/third_party/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp @@ -2179,28 +2179,35 @@ angle::Result GenerateInitialTextureData( const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(d3dFormatInfo.texFormat); - unsigned int rowPitch = dxgiFormatInfo.pixelBytes * width; - unsigned int depthPitch = rowPitch * height; - unsigned int maxImageSize = depthPitch * depth; + using CheckedSize = angle::CheckedNumeric; + CheckedSize rowPitch = CheckedSize(dxgiFormatInfo.pixelBytes) * CheckedSize(width); + CheckedSize depthPitch = rowPitch * CheckedSize(height); + CheckedSize maxImageSize = depthPitch * CheckedSize(depth); + + Context11 *context11 = GetImplAs(context); + ANGLE_CHECK_GL_ALLOC(context11, maxImageSize.IsValid()); angle::MemoryBuffer *scratchBuffer = nullptr; - ANGLE_CHECK_GL_ALLOC(GetImplAs(context), - context->getScratchBuffer(maxImageSize, &scratchBuffer)); + ANGLE_CHECK_GL_ALLOC(context11, + context->getScratchBuffer(maxImageSize.ValueOrDie(), &scratchBuffer)); - d3dFormatInfo.dataInitializerFunction(width, height, depth, scratchBuffer->data(), rowPitch, - depthPitch); + d3dFormatInfo.dataInitializerFunction(width, height, depth, scratchBuffer->data(), + rowPitch.ValueOrDie(), depthPitch.ValueOrDie()); for (unsigned int i = 0; i < mipLevels; i++) { unsigned int mipWidth = std::max(width >> i, 1U); unsigned int mipHeight = std::max(height >> i, 1U); - unsigned int mipRowPitch = dxgiFormatInfo.pixelBytes * mipWidth; - unsigned int mipDepthPitch = mipRowPitch * mipHeight; + using CheckedUINT = angle::CheckedNumeric; + CheckedUINT mipRowPitch = CheckedUINT(dxgiFormatInfo.pixelBytes) * CheckedUINT(mipWidth); + CheckedUINT mipDepthPitch = mipRowPitch * CheckedUINT(mipHeight); + + ANGLE_CHECK_GL_ALLOC(context11, mipRowPitch.IsValid() && mipDepthPitch.IsValid()); outSubresourceData->at(i).pSysMem = scratchBuffer->data(); - outSubresourceData->at(i).SysMemPitch = mipRowPitch; - outSubresourceData->at(i).SysMemSlicePitch = mipDepthPitch; + outSubresourceData->at(i).SysMemPitch = mipRowPitch.ValueOrDie(); + outSubresourceData->at(i).SysMemSlicePitch = mipDepthPitch.ValueOrDie(); } return angle::Result::Continue; diff --git a/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.cpp b/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.cpp index f995fbd0c2..f2d2cf76bb 100644 --- a/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.cpp +++ b/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.cpp @@ -1283,6 +1283,10 @@ angle::Result TextureVk::setStorageMultisample(const gl::Context *context, { releaseAndDeleteImageAndViews(contextVk); } + else if (mImage) + { + mImage->releaseStagingBuffer(contextVk->getRenderer()); + } const vk::Format &format = renderer->getFormat(internalformat); ANGLE_TRY(ensureImageAllocated(contextVk, format)); diff --git a/third_party/angle/src/libANGLE/validationES.cpp b/third_party/angle/src/libANGLE/validationES.cpp index e49c3927d0..b2a2406a23 100644 --- a/third_party/angle/src/libANGLE/validationES.cpp +++ b/third_party/angle/src/libANGLE/validationES.cpp @@ -3923,6 +3923,12 @@ const char *ValidateDrawStates(const Context *context) { return kVertexBufferBoundForTransformFeedback; } + + // Validate that we are rendering with a linked program. + if (!program->isLinked()) + { + return kProgramNotLinked; + } } } diff --git a/third_party/angle/src/tests/gl_tests/GLSLTest.cpp b/third_party/angle/src/tests/gl_tests/GLSLTest.cpp index 851ccb4768..51b880df15 100644 --- a/third_party/angle/src/tests/gl_tests/GLSLTest.cpp +++ b/third_party/angle/src/tests/gl_tests/GLSLTest.cpp @@ -10493,6 +10493,54 @@ void main() GLuint program = CompileProgram(kVS, kFS); EXPECT_EQ(0u, program); } + +// Tests an unsuccessful re-link using glBindAttribLocation. +TEST_P(GLSLTest_ES3, UnsuccessfulRelinkWithBindAttribLocation) +{ + // Make a simple program. + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); + + // Install the executable. + glUseProgram(testProgram); + + // Re-link with a bad XFB varying and a bound attrib location. + const char *tfVaryings = "gl_FragColor"; + glTransformFeedbackVaryings(testProgram, 1, &tfVaryings, GL_SEPARATE_ATTRIBS); + glBindAttribLocation(testProgram, 8, essl1_shaders::PositionAttrib()); + glLinkProgram(testProgram); + GLint linkStatus = 999; + glGetProgramiv(testProgram, GL_LINK_STATUS, &linkStatus); + ASSERT_GL_NO_ERROR(); + ASSERT_EQ(linkStatus, GL_FALSE); + + // Under normal GL this is not an error. + glDrawArrays(GL_TRIANGLES, 79, 16); + EXPECT_GL_NO_ERROR(); +} + +// Tests an unsuccessful re-link using glBindAttribLocation under WebGL. +TEST_P(WebGL2GLSLTest, UnsuccessfulRelinkWithBindAttribLocation) +{ + // Make a simple program. + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); + + // Install the executable. + glUseProgram(testProgram); + + // Re-link with a bad XFB varying and a bound attrib location. + const char *tfVaryings = "gl_FragColor"; + glTransformFeedbackVaryings(testProgram, 1, &tfVaryings, GL_SEPARATE_ATTRIBS); + glBindAttribLocation(testProgram, 8, essl1_shaders::PositionAttrib()); + glLinkProgram(testProgram); + GLint linkStatus = 999; + glGetProgramiv(testProgram, GL_LINK_STATUS, &linkStatus); + ASSERT_GL_NO_ERROR(); + ASSERT_EQ(linkStatus, GL_FALSE); + + // Under WebGL this is an error. + glDrawArrays(GL_TRIANGLES, 79, 16); + EXPECT_GL_ERROR(GL_INVALID_OPERATION); +} } // anonymous namespace ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(GLSLTest); diff --git a/third_party/angle/src/tests/gl_tests/TextureTest.cpp b/third_party/angle/src/tests/gl_tests/TextureTest.cpp index 23ea81694a..2dfcc0d00f 100644 --- a/third_party/angle/src/tests/gl_tests/TextureTest.cpp +++ b/third_party/angle/src/tests/gl_tests/TextureTest.cpp @@ -8151,6 +8151,26 @@ TEST_P(Texture2DTestES3, NonZeroBaseEmulatedClear) EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); } +// Test if the RenderTargetCache is updated when the TextureStorage object is freed +TEST_P(Texture2DTestES3, UpdateRenderTargetCacheOnDestroyTexStorage) +{ + ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); + const GLenum attachments[] = {GL_COLOR_ATTACHMENT0}; + + GLTexture tex; + GLFramebuffer fb; + glBindTexture(GL_TEXTURE_2D, tex); + glTexStorage2D(GL_TEXTURE_2D, 2, GL_RGBA8, 100, 1); + glBindFramebuffer(GL_FRAMEBUFFER, fb); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); + glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, attachments); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1); + drawQuad(drawRed, essl3_shaders::PositionAttrib(), 1.0f); + EXPECT_GL_NO_ERROR(); + + EXPECT_PIXEL_RECT_EQ(0, 0, 100, 1, GLColor::red); +} + // Draw a quad with an integer texture with a non-zero base level, and test that the color of the // texture is output. TEST_P(Texture2DIntegerTestES3, IntegerTextureNonZeroBaseLevel) @@ -8750,6 +8770,73 @@ void main() glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); } +class TextureChangeStorageUploadTest : public ANGLETest +{ + protected: + TextureChangeStorageUploadTest() + { + setWindowWidth(256); + setWindowHeight(256); + setConfigRedBits(8); + setConfigGreenBits(8); + setConfigBlueBits(8); + setConfigAlphaBits(8); + } + + void testSetUp() override + { + mProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); + if (mProgram == 0) + { + FAIL() << "shader compilation failed."; + } + + mColorLocation = glGetUniformLocation(mProgram, essl1_shaders::ColorUniform()); + + glUseProgram(mProgram); + + glClearColor(0, 0, 0, 0); + glClearDepthf(0.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glEnable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + + glGenTextures(1, &mTexture); + ASSERT_GL_NO_ERROR(); + } + + void testTearDown() override + { + glDeleteTextures(1, &mTexture); + glDeleteProgram(mProgram); + } + + GLuint mProgram; + GLint mColorLocation; + GLuint mTexture; +}; + +// Verify that respecifying storage and re-uploading doesn't crash. +TEST_P(TextureChangeStorageUploadTest, Basic) +{ + constexpr int kImageSize = 8; // 4 doesn't trip ASAN + constexpr int kSmallerImageSize = kImageSize / 2; + EXPECT_GT(kImageSize, kSmallerImageSize); + EXPECT_GT(kSmallerImageSize / 2, 0); + + std::array kColor; + + glBindTexture(GL_TEXTURE_2D, mTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kImageSize, kImageSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, + kColor.data()); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSmallerImageSize, kSmallerImageSize); + // need partial update to sidestep optimizations that remove the full upload + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSmallerImageSize / 2, kSmallerImageSize / 2, GL_RGBA, + GL_UNSIGNED_BYTE, kColor.data()); + EXPECT_GL_NO_ERROR(); +} + // Use this to select which configurations (e.g. which renderer, which GLES major version) these // tests should be run against. #define ES2_EMULATE_COPY_TEX_IMAGE() \ @@ -8858,4 +8945,6 @@ ANGLE_INSTANTIATE_TEST_ES31(TextureBufferTestES31); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CopyImageTestES31); ANGLE_INSTANTIATE_TEST_ES31(CopyImageTestES31); +ANGLE_INSTANTIATE_TEST_ES3(TextureChangeStorageUploadTest); + } // anonymous namespace diff --git a/third_party/blink/common/frame/user_activation_state.cc b/third_party/blink/common/frame/user_activation_state.cc index 5ec774f5ce..5804a6b026 100644 --- a/third_party/blink/common/frame/user_activation_state.cc +++ b/third_party/blink/common/frame/user_activation_state.cc @@ -11,6 +11,23 @@ using blink::mojom::UserActivationNotificationType; namespace blink { +namespace { + +// Indicates if |notification_type| should be considered restricted. See +// |LastActivationWasRestricted| for details. +bool IsRestricted(UserActivationNotificationType notification_type) { + return notification_type == UserActivationNotificationType:: + kExtensionMessagingBothPrivileged || + notification_type == UserActivationNotificationType:: + kExtensionMessagingSenderPrivileged || + notification_type == UserActivationNotificationType:: + kExtensionMessagingReceiverPrivileged || + notification_type == UserActivationNotificationType:: + kExtensionMessagingNeitherPrivileged; +} + +} // namespace + // The expiry time should be long enough to allow network round trips even in a // very slow connection (to support xhr-like calls with user activation), yet // not too long to make an "unattended" page feel activated. @@ -23,6 +40,7 @@ UserActivationState::UserActivationState() void UserActivationState::Activate( UserActivationNotificationType notification_type) { has_been_active_ = true; + last_activation_was_restricted_ = IsRestricted(notification_type); ActivateTransientState(); // Update states for UMA. @@ -36,6 +54,7 @@ void UserActivationState::Activate( void UserActivationState::Clear() { has_been_active_ = false; + last_activation_was_restricted_ = false; first_notification_type_ = UserActivationNotificationType::kNone; last_notification_type_ = UserActivationNotificationType::kNone; DeactivateTransientState(); @@ -70,6 +89,10 @@ bool UserActivationState::ConsumeIfActive() { return true; } +bool UserActivationState::LastActivationWasRestricted() const { + return last_activation_was_restricted_; +} + void UserActivationState::RecordPreconsumptionUma() const { if (!IsActiveInternal()) return; diff --git a/third_party/blink/public/common/frame/user_activation_state.h b/third_party/blink/public/common/frame/user_activation_state.h index aa1a421c1c..380165d265 100644 --- a/third_party/blink/public/common/frame/user_activation_state.h +++ b/third_party/blink/public/common/frame/user_activation_state.h @@ -94,6 +94,9 @@ class BLINK_COMMON_EXPORT UserActivationState { // true and updates the transient state timestamp to "now". // // The |notification_type| parameter is used for histograms only. + // + // TODO(mustaq): When removing |notification_type|, explicitly pass + // |is_restricted| as a parameter here. void Activate(mojom::UserActivationNotificationType notification_type); void Clear(); @@ -110,6 +113,21 @@ class BLINK_COMMON_EXPORT UserActivationState { // successfully consumed. bool ConsumeIfActive(); + // Indicates if the last user activation notification was restricted in + // nature. This is a non-spec-compliant state, added only for compat reasons. + // + // Please don't add any new dependency to it! + // + // More details: A user activation on a frame is marked as restricted when the + // frame is neither an ancestor nor of the same-origin w.r.t. the frame where + // user interaction happened. In other words, the restricted activation does + // not follow the tracking mechanism mentioned in the HTML spec and above. + // This non-standard activation in Chrome prevents breaking old extensions + // that (historically) expect a synthetic user activation to be available in + // an "unexposed" script-context (say in an extension's background script) + // after receiving an extension message under certain conditions. + bool LastActivationWasRestricted() const; + // Records UMA stats related to consumption. Must be called: // - before |ConsumeIfActive()| to record correct stats, and // - only once during consumption propagation to suppress over-counting. @@ -126,6 +144,8 @@ class BLINK_COMMON_EXPORT UserActivationState { bool has_been_active_ = false; base::TimeTicks transient_state_expiry_time_; + bool last_activation_was_restricted_ = false; + // Tracks the expiry of |kInteraction| notification for UMA data. base::TimeTicks transient_state_expiry_time_for_interaction_; diff --git a/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom b/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom index 382be0b3dd..c95a2e2551 100644 --- a/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom +++ b/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom @@ -9,13 +9,6 @@ import "third_party/blink/public/mojom/blob/blob.mojom"; import "third_party/blink/public/mojom/fetch/fetch_api_request.mojom"; import "third_party/blink/public/mojom/timing/worker_timing_container.mojom"; -// Used for service worker navigation preload, to create -// FetchEvent#preloadResponse. -struct FetchEventPreloadHandle { - pending_remote url_loader; - pending_receiver url_loader_client_receiver; -}; - // Parameters used for dispatching a FetchEvent. struct DispatchFetchEventParams { // FetchEvent#request. @@ -23,8 +16,9 @@ struct DispatchFetchEventParams { // FetchEvent#clientId. string client_id; + // FetchEvent#preloadResponse. - FetchEventPreloadHandle? preload_handle; + pending_receiver? preload_url_loader_client_receiver; // This is currently null for navigation because it's still being implemented. // TODO(https://crbug.com/900700): Make this non-nullable when implementation diff --git a/third_party/blink/public/mojom/webauthn/authenticator.mojom b/third_party/blink/public/mojom/webauthn/authenticator.mojom index fd2d994705..25d66267c3 100644 --- a/third_party/blink/public/mojom/webauthn/authenticator.mojom +++ b/third_party/blink/public/mojom/webauthn/authenticator.mojom @@ -12,6 +12,12 @@ import "url/mojom/url.mojom"; // credentials and use already-created credentials to get assertions. // See https://w3c.github.io/webauthn/. +// The maximum allowable list size for vectors of +// `PublicKeyCredentialDescriptor` (i.e. +// `PublicKeyCredentialCreationOptions.exclude_credentials` and +// `PublicKeyCredentialRequestOptions.allow_credentials`). +const uint32 kPublicKeyCredentialDescriptorListMaxSize = 64; + enum AuthenticatorStatus { SUCCESS, PENDING_REQUEST, diff --git a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h index 48e3e7ecec..ad64e9ba7f 100644 --- a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h +++ b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h @@ -31,8 +31,6 @@ #ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_CONTEXT_CLIENT_H_ #define THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_CONTEXT_CLIENT_H_ -#include - #include "base/memory/scoped_refptr.h" #include "base/time/time.h" #include "services/network/public/mojom/url_loader.mojom-shared.h" @@ -54,14 +52,6 @@ namespace blink { class WebServiceWorkerContextProxy; class WebString; -// Used to pass the mojom struct blink.mojom.FetchEventPreloadHandle across the -// boundary between //content and Blink. -struct WebFetchEventPreloadHandle { - CrossVariantMojoRemote url_loader; - CrossVariantMojoReceiver - url_loader_client_receiver; -}; - // WebServiceWorkerContextClient is a "client" of a service worker execution // context. This interface is implemented by the embedder and allows the // embedder to communicate with the service worker execution context. It is @@ -167,7 +157,8 @@ class WebServiceWorkerContextClient { virtual void SetupNavigationPreload( int fetch_event_id, const WebURL& url, - std::unique_ptr preload_handle) {} + CrossVariantMojoReceiver + preload_url_loader_client_receiver) {} // Called when we need to request to terminate this worker due to idle // timeout. diff --git a/third_party/blink/public/web/web_local_frame.h b/third_party/blink/public/web/web_local_frame.h index 151d9e3de3..2355b99e90 100644 --- a/third_party/blink/public/web/web_local_frame.h +++ b/third_party/blink/public/web/web_local_frame.h @@ -777,20 +777,23 @@ class WebLocalFrame : public WebFrame { // User activation ----------------------------------------------------------- - // See blink::LocalFrame::NotifyUserActivation(). + // See |blink::LocalFrame::NotifyUserActivation()|. virtual void NotifyUserActivation( mojom::UserActivationNotificationType notification_type) = 0; - // See blink::LocalFrame::HasStickyUserActivation(). + // See |blink::Frame::HasStickyUserActivation()|. virtual bool HasStickyUserActivation() = 0; - // See blink::LocalFrame::HasTransientUserActivation(). + // See |blink::Frame::HasTransientUserActivation()|. virtual bool HasTransientUserActivation() = 0; - // See blink::LocalFrame::ConsumeTransientUserActivation(). + // See |blink::LocalFrame::ConsumeTransientUserActivation()|. virtual bool ConsumeTransientUserActivation( UserActivationUpdateSource update_source = UserActivationUpdateSource::kRenderer) = 0; + + // See |blink::Frame::LastActivationWasRestricted()|. + virtual bool LastActivationWasRestricted() const = 0; // Optimization Guide -------------------------------------------------------- diff --git a/third_party/blink/renderer/core/animation/animation.cc b/third_party/blink/renderer/core/animation/animation.cc index ea45c19829..02e5bc4ef1 100644 --- a/third_party/blink/renderer/core/animation/animation.cc +++ b/third_party/blink/renderer/core/animation/animation.cc @@ -2096,10 +2096,6 @@ bool Animation::Update(TimingUpdateReason reason) { if (reason == kTimingUpdateForAnimationFrame) { if (idle || CalculateAnimationPlayState() == kFinished) { - // TODO(crbug.com/1029348): Per spec, we should have a microtask - // checkpoint right after the update cycle. Once this is fixed we should - // no longer need to force a synchronous resolution here. - AsyncFinishMicrotask(); finished_ = true; } } diff --git a/third_party/blink/renderer/core/animation/document_animations.cc b/third_party/blink/renderer/core/animation/document_animations.cc index c7ed01c694..04ec203f21 100644 --- a/third_party/blink/renderer/core/animation/document_animations.cc +++ b/third_party/blink/renderer/core/animation/document_animations.cc @@ -44,6 +44,7 @@ #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/page/page_animator.h" #include "third_party/blink/renderer/platform/bindings/microtask.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" namespace blink { @@ -254,10 +255,13 @@ void DocumentAnimations::RemoveReplacedAnimations( // The list of animations for removal is constructed in reverse composite // ordering for efficiency. Flip the ordering to ensure that events are - // dispatched in composite order. + // dispatched in composite order. Queue as a microtask so that the finished + // event is dispatched ahead of the remove event. for (auto it = animations_to_remove.rbegin(); it != animations_to_remove.rend(); it++) { - (*it)->RemoveReplacedAnimation(); + Animation* animation = *it; + Microtask::EnqueueMicrotask(WTF::Bind(&Animation::RemoveReplacedAnimation, + WrapWeakPersistent(animation))); } } diff --git a/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc b/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc index b751822d19..715a830c65 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc +++ b/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc @@ -173,6 +173,9 @@ DisplayLockUtilities::ScopedForcedUpdate::Impl::Impl(const Node* node, if (!RuntimeEnabledFeatures::CSSContentVisibilityEnabled()) return; + if (!node_) + return; + auto* owner_node = GetFrameOwnerNode(node); if (owner_node) parent_frame_impl_ = MakeGarbageCollected(owner_node, true); @@ -215,6 +218,8 @@ DisplayLockUtilities::ScopedForcedUpdate::Impl::Impl(const Node* node, } void DisplayLockUtilities::ScopedForcedUpdate::Impl::Destroy() { + if (!node_) + return; if (RuntimeEnabledFeatures::CSSContentVisibilityEnabled()) node_->GetDocument().GetDisplayLockDocumentState().EndNodeForcedScope(this); if (parent_frame_impl_) diff --git a/third_party/blink/renderer/core/display_lock/display_lock_utilities.h b/third_party/blink/renderer/core/display_lock/display_lock_utilities.h index 6e6839e2c1..022ac073ca 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_utilities.h +++ b/third_party/blink/renderer/core/display_lock/display_lock_utilities.h @@ -8,6 +8,7 @@ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/display_lock/display_lock_context.h" #include "third_party/blink/renderer/core/editing/ephemeral_range.h" +#include "third_party/blink/renderer/core/editing/frame_selection.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" namespace blink { @@ -51,6 +52,8 @@ class CORE_EXPORT DisplayLockUtilities { friend void Document::EnsurePaintLocationDataValidForNode( const Node* node, DocumentUpdateReason reason); + friend VisibleSelection + FrameSelection::ComputeVisibleSelectionInDOMTreeDeprecated() const; friend class DisplayLockContext; diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index 40c41eae6f..ef07a29ca8 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc @@ -323,7 +323,6 @@ #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h" #include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h" #include "third_party/blink/renderer/platform/network/http_parsers.h" -#include "third_party/blink/renderer/platform/network/network_state_notifier.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/scheduler/public/event_loop.h" #include "third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h" @@ -577,43 +576,6 @@ uint64_t Document::global_tree_version_ = 0; static bool g_threaded_parsing_enabled_for_testing = true; -class Document::NetworkStateObserver final - : public GarbageCollected, - public NetworkStateNotifier::NetworkStateObserver, - public ExecutionContextLifecycleObserver { - public: - explicit NetworkStateObserver(ExecutionContext* context) - : ExecutionContextLifecycleObserver(context) { - online_observer_handle_ = GetNetworkStateNotifier().AddOnLineObserver( - this, GetExecutionContext()->GetTaskRunner(TaskType::kNetworking)); - } - - void OnLineStateChange(bool on_line) override { - AtomicString event_name = - on_line ? event_type_names::kOnline : event_type_names::kOffline; - auto* window = To(GetExecutionContext()); - window->DispatchEvent(*Event::Create(event_name)); - probe::NetworkStateChanged(window->GetFrame(), on_line); - } - - void ContextDestroyed() override { - UnregisterAsObserver(GetExecutionContext()); - } - - void UnregisterAsObserver(ExecutionContext* context) { - DCHECK(context); - online_observer_handle_ = nullptr; - } - - void Trace(Visitor* visitor) const override { - ExecutionContextLifecycleObserver::Trace(visitor); - } - - private: - std::unique_ptr - online_observer_handle_; -}; - ExplicitlySetAttrElementsMap* Document::GetExplicitlySetAttrElementsMap( Element* element) { DCHECK(element); @@ -2945,12 +2907,6 @@ void Document::Initialize() { if (View()) View()->DidAttachDocument(); - - // Observer(s) should not be initialized until the document is initialized / - // attached to a frame. Otherwise - // ExecutionContextLifecycleObserver::contextDestroyed wouldn't be fired. - network_state_observer_ = - MakeGarbageCollected(GetExecutionContext()); } void Document::Shutdown() { @@ -8162,7 +8118,6 @@ void Document::Trace(Visitor* visitor) const { visitor->Trace(intersection_observer_controller_); visitor->Trace(snap_coordinator_); visitor->Trace(property_registry_); - visitor->Trace(network_state_observer_); visitor->Trace(policy_); visitor->Trace(slot_assignment_engine_); visitor->Trace(viewport_data_); diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h index b134657c84..dde3cfc634 100644 --- a/third_party/blink/renderer/core/dom/document.h +++ b/third_party/blink/renderer/core/dom/document.h @@ -1720,7 +1720,6 @@ class CORE_EXPORT Document : public ContainerNode, BeforeMatchExpandedHiddenMatchableUkm); FRIEND_TEST_ALL_PREFIXES(TextFinderSimTest, BeforeMatchExpandedHiddenMatchableUkmNoHandler); - class NetworkStateObserver; friend class AXContext; void AddAXContext(AXContext*); @@ -2112,8 +2111,6 @@ class CORE_EXPORT Document : public ContainerNode, TaskHandle sensitive_input_edited_task_; - Member network_state_observer_; - // |ukm_recorder_| and |source_id_| will allow objects that are part of // the document to record UKM. std::unique_ptr ukm_recorder_; diff --git a/third_party/blink/renderer/core/editing/frame_selection.cc b/third_party/blink/renderer/core/editing/frame_selection.cc index d0133cc8da..f59557caeb 100644 --- a/third_party/blink/renderer/core/editing/frame_selection.cc +++ b/third_party/blink/renderer/core/editing/frame_selection.cc @@ -158,6 +158,10 @@ VisibleSelection FrameSelection::ComputeVisibleSelectionInDOMTreeDeprecated() const { // TODO(editing-dev): Hoist UpdateStyleAndLayout // to caller. See http://crbug.com/590369 for more details. + DisplayLockUtilities::ScopedForcedUpdate base_scope( + GetSelectionInDOMTree().Base().AnchorNode()); + DisplayLockUtilities::ScopedForcedUpdate extent_scope( + GetSelectionInDOMTree().Extent().AnchorNode()); GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kSelection); return ComputeVisibleSelectionInDOMTree(); } diff --git a/third_party/blink/renderer/core/frame/frame.h b/third_party/blink/renderer/core/frame/frame.h index 485c1b1dd3..fa767917b2 100644 --- a/third_party/blink/renderer/core/frame/frame.h +++ b/third_party/blink/renderer/core/frame/frame.h @@ -212,6 +212,12 @@ class CORE_EXPORT Frame : public GarbageCollected { return user_activation_state_.HasBeenActive(); } + // Returns if the last user activation for this frame was restricted in + // nature. + bool LastActivationWasRestricted() const { + return user_activation_state_.LastActivationWasRestricted(); + } + // Resets the user activation state of this frame. void ClearUserActivation() { user_activation_state_.Clear(); } diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc index 62dac665c1..b93ae92cb6 100644 --- a/third_party/blink/renderer/core/frame/local_dom_window.cc +++ b/third_party/blink/renderer/core/frame/local_dom_window.cc @@ -128,6 +128,7 @@ #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h" +#include "third_party/blink/renderer/platform/network/network_state_notifier.h" #include "third_party/blink/renderer/platform/scheduler/public/dummy_schedulers.h" #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h" #include "third_party/blink/renderer/platform/timer.h" @@ -163,6 +164,38 @@ bool ShouldRecordPostMessageIncomingFrameUkmEvent( } // namespace +class LocalDOMWindow::NetworkStateObserver final + : public GarbageCollected, + public NetworkStateNotifier::NetworkStateObserver, + public ExecutionContextLifecycleObserver { + public: + explicit NetworkStateObserver(ExecutionContext* context) + : ExecutionContextLifecycleObserver(context) {} + + void Initialize() { + online_observer_handle_ = GetNetworkStateNotifier().AddOnLineObserver( + this, GetExecutionContext()->GetTaskRunner(TaskType::kNetworking)); + } + + void OnLineStateChange(bool on_line) override { + AtomicString event_name = + on_line ? event_type_names::kOnline : event_type_names::kOffline; + auto* window = To(GetExecutionContext()); + window->DispatchEvent(*Event::Create(event_name)); + probe::NetworkStateChanged(window->GetFrame(), on_line); + } + + void ContextDestroyed() override { online_observer_handle_ = nullptr; } + + void Trace(Visitor* visitor) const override { + ExecutionContextLifecycleObserver::Trace(visitor); + } + + private: + std::unique_ptr + online_observer_handle_; +}; + LocalDOMWindow::LocalDOMWindow(LocalFrame& frame, WindowAgent* agent) : DOMWindow(frame), ExecutionContext(V8PerIsolateData::MainThreadIsolate(), agent), @@ -180,7 +213,9 @@ LocalDOMWindow::LocalDOMWindow(LocalFrame& frame, WindowAgent* agent) isolated_world_csp_map_( MakeGarbageCollected< HeapHashMap>>()), - token_(frame.GetLocalFrameToken()) {} + token_(frame.GetLocalFrameToken()), + network_state_observer_( + MakeGarbageCollected(this)) {} void LocalDOMWindow::BindContentSecurityPolicy() { DCHECK(!GetContentSecurityPolicy()->IsBound()); @@ -190,6 +225,7 @@ void LocalDOMWindow::BindContentSecurityPolicy() { void LocalDOMWindow::Initialize() { GetAgent()->AttachContext(this); + network_state_observer_->Initialize(); } void LocalDOMWindow::ResetWindowAgent(WindowAgent* agent) { @@ -2094,6 +2130,7 @@ void LocalDOMWindow::Trace(Visitor* visitor) const { visitor->Trace(spell_checker_); visitor->Trace(text_suggestion_controller_); visitor->Trace(isolated_world_csp_map_); + visitor->Trace(network_state_observer_); DOMWindow::Trace(visitor); ExecutionContext::Trace(visitor); Supplementable::Trace(visitor); diff --git a/third_party/blink/renderer/core/frame/local_dom_window.h b/third_party/blink/renderer/core/frame/local_dom_window.h index 54799ba940..0ad3914d6b 100644 --- a/third_party/blink/renderer/core/frame/local_dom_window.h +++ b/third_party/blink/renderer/core/frame/local_dom_window.h @@ -445,6 +445,8 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow, LocalDOMWindow* source) override; private: + class NetworkStateObserver; + // Intentionally private to prevent redundant checks when the type is // already LocalDOMWindow. bool IsLocalDOMWindow() const override { return true; } @@ -543,6 +545,9 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow, // this UKM is logged. // TODO(crbug.com/1112491): Remove when no longer needed. Deque post_message_ukm_recorded_source_ids_; + + // Fire "online" and "offline" events. + Member network_state_observer_; }; template <> diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc index ce2ed9317c..3991250d8a 100644 --- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc +++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc @@ -651,6 +651,10 @@ bool WebLocalFrameImpl::ConsumeTransientUserActivation( return LocalFrame::ConsumeTransientUserActivation(GetFrame(), update_source); } +bool WebLocalFrameImpl::LastActivationWasRestricted() const { + return GetFrame()->LastActivationWasRestricted(); +} + void WebLocalFrameImpl::SetOptimizationGuideHints( const WebOptimizationGuideHints& web_hints) { if (!GetFrame()) @@ -2071,6 +2075,16 @@ LocalFrame* WebLocalFrameImpl::CreateChildFrame( policy_container_receiver = policy_container_remote.InitWithNewEndpointAndPassReceiver(); + FramePolicy frame_policy = owner_element->GetFramePolicy(); + // Documents create iframes, iframes host new documents. Both are associated + // with sandbox flags. They are required to be stricter or equal as we go + // down. The iframe owner element only returns the additional restrictions + // defined in the HTMLIFrameElement's sanbox attribute. It needs to be + // combined with the document's sandbox flags to get the frame's sandbox + // policy right. + frame_policy.sandbox_flags |= + GetFrame()->GetDocument()->GetExecutionContext()->GetSandboxFlags(); + // FIXME: Using subResourceAttributeName as fallback is not a perfect // solution. subResourceAttributeName returns just one attribute name. The // element might not have the attribute, and there might be other attributes @@ -2080,8 +2094,7 @@ LocalFrame* WebLocalFrameImpl::CreateChildFrame( scope, name, owner_element->getAttribute( owner_element->SubResourceAttributeName()), - owner_element->GetFramePolicy(), owner_properties, - owner_element->OwnerType(), + std::move(frame_policy), owner_properties, owner_element->OwnerType(), WebPolicyContainerBindParams{std::move(policy_container_receiver)})); if (!webframe_child) return nullptr; diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.h b/third_party/blink/renderer/core/frame/web_local_frame_impl.h index 7bd9fc4698..3c905f1dfd 100644 --- a/third_party/blink/renderer/core/frame/web_local_frame_impl.h +++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.h @@ -324,6 +324,7 @@ class CORE_EXPORT WebLocalFrameImpl final bool HasStickyUserActivation() override; bool HasTransientUserActivation() override; bool ConsumeTransientUserActivation(UserActivationUpdateSource) override; + bool LastActivationWasRestricted() const override; void SetOptimizationGuideHints(const WebOptimizationGuideHints&) override; void SetTargetToCurrentHistoryItem(const WebString& target) override; void UpdateCurrentHistoryItem() override; diff --git a/third_party/blink/renderer/core/html/html_iframe_element.cc b/third_party/blink/renderer/core/html/html_iframe_element.cc index cfa0b2e78b..ab26e9398f 100644 --- a/third_party/blink/renderer/core/html/html_iframe_element.cc +++ b/third_party/blink/renderer/core/html/html_iframe_element.cc @@ -207,16 +207,27 @@ void HTMLIFrameElement::ParseAttribute( UpdateContainerPolicy(); } } else if (name == html_names::kCspAttr) { + static const size_t kMaxLengthCSPAttribute = 4096; if (value && (value.Contains('\n') || value.Contains('\r') || !MatchesTheSerializedCSPGrammar(value.GetString()))) { + // TODO(antoniosartori): It would be safer to block loading iframes with + // invalid 'csp' attribute. required_csp_ = g_null_atom; GetDocument().AddConsoleMessage(MakeGarbageCollected( mojom::blink::ConsoleMessageSource::kOther, mojom::blink::ConsoleMessageLevel::kError, "'csp' attribute is invalid: " + value)); - return; - } - if (required_csp_ != value) { + } else if (value && value.length() > kMaxLengthCSPAttribute) { + // TODO(antoniosartori): It would be safer to block loading iframes with + // invalid 'csp' attribute. + required_csp_ = g_null_atom; + GetDocument().AddConsoleMessage(MakeGarbageCollected( + mojom::blink::ConsoleMessageSource::kOther, + mojom::blink::ConsoleMessageLevel::kError, + String::Format("'csp' attribute too long. The max length for the " + "'csp' attribute is %zu bytes.", + kMaxLengthCSPAttribute))); + } else if (required_csp_ != value) { required_csp_ = value; CSPAttributeChanged(); UseCounter::Count(GetDocument(), WebFeature::kIFrameCSPAttribute); diff --git a/third_party/blink/renderer/core/html/parser/css_preload_scanner.cc b/third_party/blink/renderer/core/html/parser/css_preload_scanner.cc index 99f25715af..4f3ee7e9cf 100644 --- a/third_party/blink/renderer/core/html/parser/css_preload_scanner.cc +++ b/third_party/blink/renderer/core/html/parser/css_preload_scanner.cc @@ -259,8 +259,7 @@ void CSSPreloadScanner::EmitRule(const SegmentedString& source) { auto request = PreloadRequest::CreateIfNeeded( fetch_initiator_type_names::kCSS, position, url, *predicted_base_element_url_, ResourceType::kCSSStyleSheet, - referrer_policy_, PreloadRequest::kBaseUrlIsReferrer, - ResourceFetcher::kImageNotImageSet, exclusion_info_); + referrer_policy_, ResourceFetcher::kImageNotImageSet, exclusion_info_); if (request) { // FIXME: Should this be including the charset in the preload request? requests_->push_back(std::move(request)); diff --git a/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc b/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc index ea4b201b0a..99ab6cd142 100644 --- a/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc +++ b/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc @@ -321,9 +321,8 @@ class TokenPreloadScanner::StartTagScanner { : document_parameters.referrer_policy; auto request = PreloadRequest::CreateIfNeeded( InitiatorFor(tag_impl_), position, url_to_load_, predicted_base_url, - type.value(), referrer_policy, PreloadRequest::kDocumentIsReferrer, - is_image_set, exclusion_info, resource_width, client_hints_preferences, - request_type); + type.value(), referrer_policy, is_image_set, exclusion_info, + resource_width, client_hints_preferences, request_type); if (!request) return nullptr; diff --git a/third_party/blink/renderer/core/html/parser/html_resource_preloader_test.cc b/third_party/blink/renderer/core/html/parser/html_resource_preloader_test.cc index 9dbe2ef393..ddd9f3de6a 100644 --- a/third_party/blink/renderer/core/html/parser/html_resource_preloader_test.cc +++ b/third_party/blink/renderer/core/html/parser/html_resource_preloader_test.cc @@ -58,10 +58,9 @@ class HTMLResourcePreloaderTest : public PageTestBase { auto preload_request = PreloadRequest::CreateIfNeeded( String(), TextPosition::MinimumPosition(), test_case.url, KURL(test_case.base_url), ResourceType::kImage, - network::mojom::ReferrerPolicy(), PreloadRequest::kDocumentIsReferrer, - ResourceFetcher::kImageNotImageSet, nullptr /* exclusion_info */, - FetchParameters::ResourceWidth(), ClientHintsPreferences(), - PreloadRequest::kRequestTypePreconnect); + network::mojom::ReferrerPolicy(), ResourceFetcher::kImageNotImageSet, + nullptr /* exclusion_info */, FetchParameters::ResourceWidth(), + ClientHintsPreferences(), PreloadRequest::kRequestTypePreconnect); DCHECK(preload_request); if (test_case.is_cors) preload_request->SetCrossOrigin(kCrossOriginAttributeAnonymous); diff --git a/third_party/blink/renderer/core/html/parser/preload_request.cc b/third_party/blink/renderer/core/html/parser/preload_request.cc index 73c57ab7c8..ec351968e7 100644 --- a/third_party/blink/renderer/core/html/parser/preload_request.cc +++ b/third_party/blink/renderer/core/html/parser/preload_request.cc @@ -61,7 +61,6 @@ std::unique_ptr PreloadRequest::CreateIfNeeded( const KURL& base_url, ResourceType resource_type, const network::mojom::ReferrerPolicy referrer_policy, - ReferrerSource referrer_source, ResourceFetcher::IsImageSet is_image_set, const ExclusionInfo* exclusion_info, const FetchParameters::ResourceWidth& resource_width, @@ -82,7 +81,7 @@ std::unique_ptr PreloadRequest::CreateIfNeeded( return base::WrapUnique(new PreloadRequest( initiator_name, initiator_position, resource_url, base_url, resource_type, resource_width, client_hints_preferences, request_type, referrer_policy, - referrer_source, is_image_set)); + is_image_set)); } Resource* PreloadRequest::Start(Document* document) { @@ -98,9 +97,6 @@ Resource* PreloadRequest::Start(Document* document) { ResourceRequest resource_request(url); resource_request.SetReferrerPolicy(referrer_policy_); - if (referrer_source_ == kBaseUrlIsReferrer) { - resource_request.SetReferrerString(base_url_.StrippedForUseAsReferrer()); - } resource_request.SetRequestContext( ResourceFetcher::DetermineRequestContext(resource_type_, is_image_set_)); diff --git a/third_party/blink/renderer/core/html/parser/preload_request.h b/third_party/blink/renderer/core/html/parser/preload_request.h index 8f0d11c50f..9f64caa47e 100644 --- a/third_party/blink/renderer/core/html/parser/preload_request.h +++ b/third_party/blink/renderer/core/html/parser/preload_request.h @@ -62,8 +62,6 @@ class CORE_EXPORT PreloadRequest { kRequestTypeLinkRelPreload }; - enum ReferrerSource { kDocumentIsReferrer, kBaseUrlIsReferrer }; - static std::unique_ptr CreateIfNeeded( const String& initiator_name, const TextPosition& initiator_position, @@ -71,7 +69,6 @@ class CORE_EXPORT PreloadRequest { const KURL& base_url, ResourceType resource_type, const network::mojom::ReferrerPolicy referrer_policy, - ReferrerSource referrer_source, ResourceFetcher::IsImageSet is_image_set, const ExclusionInfo* exclusion_info, const FetchParameters::ResourceWidth& resource_width = @@ -154,7 +151,6 @@ class CORE_EXPORT PreloadRequest { const ClientHintsPreferences& client_hints_preferences, RequestType request_type, const network::mojom::ReferrerPolicy referrer_policy, - ReferrerSource referrer_source, ResourceFetcher::IsImageSet is_image_set) : initiator_name_(initiator_name), initiator_position_(initiator_position), @@ -169,7 +165,6 @@ class CORE_EXPORT PreloadRequest { client_hints_preferences_(client_hints_preferences), request_type_(request_type), referrer_policy_(referrer_policy), - referrer_source_(referrer_source), from_insertion_scanner_(false), is_image_set_(is_image_set), is_lazy_load_image_enabled_(false) {} @@ -191,7 +186,6 @@ class CORE_EXPORT PreloadRequest { const ClientHintsPreferences client_hints_preferences_; const RequestType request_type_; const network::mojom::ReferrerPolicy referrer_policy_; - const ReferrerSource referrer_source_; IntegrityMetadataSet integrity_metadata_; RenderBlockingBehavior render_blocking_behavior_ = RenderBlockingBehavior::kUnset; diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc index e59adae120..d3fa773216 100644 --- a/third_party/blink/renderer/core/layout/layout_inline.cc +++ b/third_party/blink/renderer/core/layout/layout_inline.cc @@ -574,15 +574,13 @@ void LayoutInline::SplitInlines(LayoutBlockFlow* from_block, // nest to a much greater depth (see bugzilla bug 13430) but for now we have a // limit. This *will* result in incorrect rendering, but the alternative is to // hang forever. - const unsigned kCMaxSplitDepth = 200; Vector inlines_to_clone; LayoutInline* top_most_inline = this; for (LayoutObject* o = this; o != from_block; o = o->Parent()) { if (o->IsLayoutNGInsideListMarker()) continue; top_most_inline = To(o); - if (inlines_to_clone.size() < kCMaxSplitDepth) - inlines_to_clone.push_back(top_most_inline); + inlines_to_clone.push_back(top_most_inline); // Keep walking up the chain to ensure |topMostInline| is a child of // |fromBlock|, to avoid assertion failure when |fromBlock|'s children are // moved to |toBlock| below. diff --git a/third_party/blink/renderer/core/loader/threaded_icon_loader.cc b/third_party/blink/renderer/core/loader/threaded_icon_loader.cc index c995ac8660..40d0b51332 100644 --- a/third_party/blink/renderer/core/loader/threaded_icon_loader.cc +++ b/third_party/blink/renderer/core/loader/threaded_icon_loader.cc @@ -11,6 +11,7 @@ #include "skia/ext/image_operations.h" #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" +#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h" #include "third_party/blink/renderer/platform/image-decoders/image_decoder.h" #include "third_party/blink/renderer/platform/image-decoders/image_frame.h" #include "third_party/blink/renderer/platform/image-decoders/segment_reader.h" @@ -24,6 +25,80 @@ namespace blink { +namespace { + +void DecodeAndResizeImage( + scoped_refptr task_runner, + scoped_refptr data, + gfx::Size resize_dimensions, + CrossThreadOnceFunction done_callback) { + auto notify_complete = [&](SkBitmap icon, double resize_scale) { + // This is needed so it can be moved cross-thread. + icon.setImmutable(); + PostCrossThreadTask(*task_runner, FROM_HERE, + CrossThreadBindOnce(std::move(done_callback), + std::move(icon), resize_scale)); + }; + + std::unique_ptr decoder = ImageDecoder::Create( + std::move(data), /* data_complete= */ true, + ImageDecoder::kAlphaPremultiplied, ImageDecoder::kDefaultBitDepth, + ColorBehavior::TransformToSRGB()); + + if (!decoder) { + notify_complete(SkBitmap(), -1.0); + return; + } + + ImageFrame* image_frame = decoder->DecodeFrameBufferAtIndex(0); + + if (!image_frame) { + notify_complete(SkBitmap(), -1.0); + return; + } + + SkBitmap decoded_icon = image_frame->Bitmap(); + if (resize_dimensions.IsEmpty()) { + notify_complete(std::move(decoded_icon), 1.0); + return; + } + + // If the icon is larger than |resize_dimensions| permits, we need to + // resize it as well. This can be done synchronously given that we're on a + // background thread already. + double scale = std::min( + static_cast(resize_dimensions.width()) / decoded_icon.width(), + static_cast(resize_dimensions.height()) / decoded_icon.height()); + + if (scale >= 1.0) { + notify_complete(std::move(decoded_icon), 1.0); + return; + } + + int resized_width = + base::ranges::clamp(static_cast(scale * decoded_icon.width()), 1, + resize_dimensions.width()); + int resized_height = + base::ranges::clamp(static_cast(scale * decoded_icon.height()), 1, + resize_dimensions.height()); + + // Use the RESIZE_GOOD quality allowing the implementation to pick an + // appropriate method for the resize. Can be increased to RESIZE_BETTER + // or RESIZE_BEST if the quality looks poor. + SkBitmap resized_icon = skia::ImageOperations::Resize( + decoded_icon, skia::ImageOperations::RESIZE_GOOD, resized_width, + resized_height); + + if (resized_icon.isNull()) { + notify_complete(std::move(decoded_icon), 1.0); + return; + } + + notify_complete(std::move(resized_icon), scale); +} + +} // namespace + void ThreadedIconLoader::Start( ExecutionContext* execution_context, const ResourceRequestHead& resource_request, @@ -83,87 +158,18 @@ void ThreadedIconLoader::DidFinishLoading(uint64_t resource_identifier) { worker_pool::PostTask( FROM_HERE, CrossThreadBindOnce( - &ThreadedIconLoader::DecodeAndResizeImageOnBackgroundThread, - WrapCrossThreadPersistent(this), std::move(task_runner), - SegmentReader::CreateFromSharedBuffer(std::move(data_)))); -} - -void ThreadedIconLoader::DecodeAndResizeImageOnBackgroundThread( - scoped_refptr task_runner, - scoped_refptr data) { - DCHECK(task_runner); - DCHECK(data); - - auto notify_complete = [&](double refactor_scale) { - PostCrossThreadTask( - *task_runner, FROM_HERE, - CrossThreadBindOnce(&ThreadedIconLoader::OnBackgroundTaskComplete, - WrapCrossThreadPersistent(this), refactor_scale)); - }; - - std::unique_ptr decoder = ImageDecoder::Create( - std::move(data), /* data_complete= */ true, - ImageDecoder::kAlphaPremultiplied, ImageDecoder::kDefaultBitDepth, - ColorBehavior::TransformToSRGB()); - - if (!decoder) { - notify_complete(-1.0); - return; - } - - ImageFrame* image_frame = decoder->DecodeFrameBufferAtIndex(0); - - if (!image_frame) { - notify_complete(-1.0); - return; - } - - decoded_icon_ = image_frame->Bitmap(); - if (!resize_dimensions_) { - notify_complete(1.0); - return; - } - - // If the icon is larger than |resize_dimensions_| permits, we need to resize - // it as well. This can be done synchronously given that we're on a - // background thread already. - double scale = std::min( - static_cast(resize_dimensions_->width()) / decoded_icon_.width(), - static_cast(resize_dimensions_->height()) / - decoded_icon_.height()); - - if (scale >= 1.0) { - notify_complete(1.0); - return; - } - - int resized_width = - base::ClampToRange(static_cast(scale * decoded_icon_.width()), 1, - resize_dimensions_->width()); - int resized_height = - base::ClampToRange(static_cast(scale * decoded_icon_.height()), 1, - resize_dimensions_->height()); - - // Use the RESIZE_GOOD quality allowing the implementation to pick an - // appropriate method for the resize. Can be increased to RESIZE_BETTER - // or RESIZE_BEST if the quality looks poor. - SkBitmap resized_icon = skia::ImageOperations::Resize( - decoded_icon_, skia::ImageOperations::RESIZE_GOOD, resized_width, - resized_height); - - if (resized_icon.isNull()) { - notify_complete(1.0); - return; - } - - decoded_icon_ = std::move(resized_icon); - notify_complete(scale); + &DecodeAndResizeImage, std::move(task_runner), + SegmentReader::CreateFromSharedBuffer(std::move(data_)), + resize_dimensions_ ? *resize_dimensions_ : gfx::Size(), + CrossThreadBindOnce(&ThreadedIconLoader::OnBackgroundTaskComplete, + WrapCrossThreadWeakPersistent(this)))); } -void ThreadedIconLoader::OnBackgroundTaskComplete(double resize_scale) { +void ThreadedIconLoader::OnBackgroundTaskComplete(SkBitmap icon, + double resize_scale) { if (stopped_) return; - std::move(icon_callback_).Run(std::move(decoded_icon_), resize_scale); + std::move(icon_callback_).Run(std::move(icon), resize_scale); } void ThreadedIconLoader::DidFail(const ResourceError& error) { diff --git a/third_party/blink/renderer/core/loader/threaded_icon_loader.h b/third_party/blink/renderer/core/loader/threaded_icon_loader.h index 4497f329a0..41fba43ad7 100644 --- a/third_party/blink/renderer/core/loader/threaded_icon_loader.h +++ b/third_party/blink/renderer/core/loader/threaded_icon_loader.h @@ -18,7 +18,6 @@ namespace blink { class ResourceRequestHead; -class SegmentReader; // Utility class for loading, decoding, and potentially rescaling an icon on a // background thread. Note that icons are only downscaled and never upscaled. @@ -52,11 +51,7 @@ class CORE_EXPORT ThreadedIconLoader final void Trace(Visitor* visitor) const override; private: - void DecodeAndResizeImageOnBackgroundThread( - scoped_refptr task_runner, - scoped_refptr data); - - void OnBackgroundTaskComplete(double resize_scale); + void OnBackgroundTaskComplete(SkBitmap icon, double resize_scale); Member threadable_loader_; @@ -64,9 +59,7 @@ class CORE_EXPORT ThreadedIconLoader final // of the image data starts. scoped_refptr data_; - // Accessed from main thread and background thread. base::Optional resize_dimensions_; - SkBitmap decoded_icon_; IconCallback icon_callback_; diff --git a/third_party/blink/renderer/core/streams/build.gni b/third_party/blink/renderer/core/streams/build.gni index 57a106353b..744d47f1a1 100644 --- a/third_party/blink/renderer/core/streams/build.gni +++ b/third_party/blink/renderer/core/streams/build.gni @@ -43,6 +43,7 @@ blink_core_sources_streams = [ "transform_stream_default_controller.cc", "transform_stream_default_controller.h", "transform_stream_transformer.h", + "underlying_sink_base.cc", "underlying_sink_base.h", "underlying_source_base.cc", "underlying_source_base.h", diff --git a/third_party/blink/renderer/core/streams/underlying_sink_base.cc b/third_party/blink/renderer/core/streams/underlying_sink_base.cc new file mode 100644 index 0000000000..a10d4f1865 --- /dev/null +++ b/third_party/blink/renderer/core/streams/underlying_sink_base.cc @@ -0,0 +1,29 @@ +// Copyright 2021 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 "third_party/blink/renderer/core/streams/underlying_sink_base.h" + +#include "third_party/blink/renderer/core/streams/writable_stream_default_controller.h" +#include "v8/include/v8.h" + +namespace blink { + +ScriptPromise UnderlyingSinkBase::start(ScriptState* script_state, + ScriptValue controller, + ExceptionState& exception_state) { + controller_ = WritableStreamDefaultController::From(script_state, controller); + return start(script_state, controller_, exception_state); +} + +ScriptValue UnderlyingSinkBase::type(ScriptState* script_state) const { + auto* isolate = script_state->GetIsolate(); + return ScriptValue(isolate, v8::Undefined(isolate)); +} + +void UnderlyingSinkBase::Trace(Visitor* visitor) const { + visitor->Trace(controller_); + ScriptWrappable::Trace(visitor); +} + +} // namespace blink diff --git a/third_party/blink/renderer/core/streams/underlying_sink_base.h b/third_party/blink/renderer/core/streams/underlying_sink_base.h index 3b07d87f06..07ba729fc3 100644 --- a/third_party/blink/renderer/core/streams/underlying_sink_base.h +++ b/third_party/blink/renderer/core/streams/underlying_sink_base.h @@ -6,16 +6,20 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_UNDERLYING_SINK_BASE_H_ #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" +#include "third_party/blink/renderer/bindings/core/v8/script_value.h" #include "third_party/blink/renderer/core/core_export.h" -#include "third_party/blink/renderer/core/streams/writable_stream_default_controller.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/heap/visitor.h" +// Various files depend on us exporting this header. +// TODO(ricea): Clean up the dependencies and remove this include. +#include "third_party/blink/renderer/core/streams/writable_stream_default_controller.h" + namespace blink { class ExceptionState; -class ScriptValue; class ScriptState; +class WritableStreamDefaultController; class CORE_EXPORT UnderlyingSinkBase : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); @@ -38,12 +42,8 @@ class CORE_EXPORT UnderlyingSinkBase : public ScriptWrappable { ScriptValue reason, ExceptionState&) = 0; - ScriptPromise start(ScriptState* script_state, - ScriptValue controller, - ExceptionState& exception_state) { - controller_ = WritableStreamDefaultController::From(controller); - return start(script_state, controller_, exception_state); - } + ScriptPromise start(ScriptState*, ScriptValue controller, ExceptionState&); + ScriptPromise write(ScriptState* script_state, ScriptValue chunk, ScriptValue controller, @@ -52,10 +52,11 @@ class CORE_EXPORT UnderlyingSinkBase : public ScriptWrappable { return write(script_state, chunk, controller_, exception_state); } - void Trace(Visitor* visitor) const override { - visitor->Trace(controller_); - ScriptWrappable::Trace(visitor); - } + // Returns a JavaScript "undefined" value. This is required by the + // WritableStream Create() method. + ScriptValue type(ScriptState*) const; + + void Trace(Visitor*) const override; protected: WritableStreamDefaultController* Controller() const { return controller_; } diff --git a/third_party/blink/renderer/core/streams/underlying_sink_base.idl b/third_party/blink/renderer/core/streams/underlying_sink_base.idl index 8351141cbc..470eb527b1 100644 --- a/third_party/blink/renderer/core/streams/underlying_sink_base.idl +++ b/third_party/blink/renderer/core/streams/underlying_sink_base.idl @@ -14,4 +14,7 @@ interface UnderlyingSinkBase { [CallWith=ScriptState, RaisesException] Promise write(any chunk, any controller); [CallWith=ScriptState, RaisesException] Promise close(); [CallWith=ScriptState, RaisesException] Promise abort(any reason); + + // This only exists to prevent Object.prototype.type being accessed. + [CallWith=ScriptState] readonly attribute any type; }; diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc b/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc index cc76647826..9f60d988f7 100644 --- a/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc +++ b/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc @@ -21,10 +21,14 @@ namespace blink { WritableStreamDefaultController* WritableStreamDefaultController::From( + ScriptState* script_state, ScriptValue controller) { - DCHECK(controller.IsObject()); - return V8WritableStreamDefaultController::ToImpl( - controller.V8Value().As()); + CHECK(controller.IsObject()); + auto* controller_impl = + V8WritableStreamDefaultController::ToImplWithTypeCheck( + script_state->GetIsolate(), controller.V8Value().As()); + CHECK(controller_impl); + return controller_impl; } // Only used internally. Not reachable from JavaScript. diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_controller.h b/third_party/blink/renderer/core/streams/writable_stream_default_controller.h index 3351dcd694..8be6764217 100644 --- a/third_party/blink/renderer/core/streams/writable_stream_default_controller.h +++ b/third_party/blink/renderer/core/streams/writable_stream_default_controller.h @@ -27,7 +27,7 @@ class CORE_EXPORT WritableStreamDefaultController final DEFINE_WRAPPERTYPEINFO(); public: - static WritableStreamDefaultController* From(ScriptValue); + static WritableStreamDefaultController* From(ScriptState*, ScriptValue); // The JavaScript-exposed constructor throws automatically as no constructor // is specified in the IDL. This constructor is used internally during diff --git a/third_party/blink/renderer/modules/cache_storage/cache.cc b/third_party/blink/renderer/modules/cache_storage/cache.cc index 5482ce90e5..0ec3a20cff 100644 --- a/third_party/blink/renderer/modules/cache_storage/cache.cc +++ b/third_party/blink/renderer/modules/cache_storage/cache.cc @@ -101,7 +101,7 @@ void ValidateResponseForPut(const Response* response, exception_state.ThrowTypeError("Vary header contains *"); return; } - if (response->GetResponse()->InternalStatus() == 206) { + if (response->GetResponse()->Status() == 206) { exception_state.ThrowTypeError( "Partial response (status code 206) is unsupported"); return; diff --git a/third_party/blink/renderer/modules/content_index/content_index_icon_loader.cc b/third_party/blink/renderer/modules/content_index/content_index_icon_loader.cc index 79f4224fd9..3b5f52a9be 100644 --- a/third_party/blink/renderer/modules/content_index/content_index_icon_loader.cc +++ b/third_party/blink/renderer/modules/content_index/content_index_icon_loader.cc @@ -26,6 +26,7 @@ constexpr base::TimeDelta kIconFetchTimeout = base::TimeDelta::FromSeconds(30); void FetchIcon(ExecutionContext* execution_context, const KURL& icon_url, const gfx::Size& icon_size, + ThreadedIconLoader* threaded_icon_loader, ThreadedIconLoader::IconCallback callback) { ResourceRequest resource_request(icon_url); resource_request.SetRequestContext(mojom::blink::RequestContextType::IMAGE); @@ -34,7 +35,6 @@ void FetchIcon(ExecutionContext* execution_context, resource_request.SetPriority(ResourceLoadPriority::kMedium); resource_request.SetTimeoutInterval(kIconFetchTimeout); - auto* threaded_icon_loader = MakeGarbageCollected(); threaded_icon_loader->Start(execution_context, resource_request, icon_size, std::move(callback)); } @@ -100,16 +100,21 @@ void ContentIndexIconLoader::Start( if (icon_url.IsEmpty()) icon_url = KURL(image_resources[0].src); + auto* threaded_icon_loader = MakeGarbageCollected(); // |icons_ptr| is safe to use since it is owned by |barrier_closure|. FetchIcon( - execution_context, icon_url, icon_size, + execution_context, icon_url, icon_size, threaded_icon_loader, WTF::Bind( [](base::OnceClosure done_closure, Vector* icons_ptr, - SkBitmap icon, double resize_scale) { + ThreadedIconLoader* icon_loader, SkBitmap icon, + double resize_scale) { icons_ptr->push_back(std::move(icon)); std::move(done_closure).Run(); }, - barrier_closure, WTF::Unretained(icons_ptr))); + barrier_closure, WTF::Unretained(icons_ptr), + // Pass |threaded_icon_loader| to the callback to make sure it + // doesn't get destroyed. + WrapPersistent(threaded_icon_loader))); } } diff --git a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc index 1061445c91..8aaf8511d0 100644 --- a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc +++ b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc @@ -311,6 +311,11 @@ bool IsArrayBufferOrViewBelowSizeLimit( .IsValid(); } +bool IsCredentialDescriptorListBelowSizeLimit( + const HeapVector>& list) { + return list.size() <= mojom::blink::kPublicKeyCredentialDescriptorListMaxSize; +} + DOMException* CredentialManagerErrorToDOMException( CredentialManagerError reason) { switch (reason) { @@ -984,6 +989,16 @@ ScriptPromise CredentialsContainer::get( "RangeError")); return promise; } + + if (!IsCredentialDescriptorListBelowSizeLimit( + options->publicKey()->allowCredentials())) { + resolver->Reject( + DOMException::Create("The `allowCredentials` attribute exceeds the " + "maximum allowed size (64).", + "RangeError")); + return promise; + } + if (public_key_options->hasExtensions()) { if (public_key_options->extensions()->hasAppid()) { const auto& appid = public_key_options->extensions()->appid(); @@ -1259,10 +1274,19 @@ ScriptPromise CredentialsContainer::create( return promise; } + if (!IsCredentialDescriptorListBelowSizeLimit( + options->publicKey()->excludeCredentials())) { + resolver->Reject( + DOMException::Create("The `excludeCredentials` attribute exceeds the " + "maximum allowed size (64).", + "RangeError")); + return promise; + } + for (const auto& credential : options->publicKey()->excludeCredentials()) { if (!IsArrayBufferOrViewBelowSizeLimit(credential->id())) { resolver->Reject(DOMException::Create( - "The `excludedCredentials.id` attribute exceeds the maximum " + "The `excludeCredentials.id` attribute exceeds the maximum " "allowed size.", "RangeError")); return promise; diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc index 9265e14be8..84a8825ec8 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc @@ -1629,7 +1629,8 @@ void RTCPeerConnectionHandler::AddICECandidate( handler_weak_ptr = weak_factory_.GetWeakPtr(), tracker_weak_ptr = WrapCrossThreadWeakPersistent(peer_connection_tracker_.Get()), - candidate, persistent_request = WrapCrossThreadPersistent(request), + persistent_candidate = WrapCrossThreadPersistent(candidate), + persistent_request = WrapCrossThreadPersistent(request), callback_on_task_runner = std::move(callback_on_task_runner)](webrtc::RTCError result) { // Grab a snapshot of all the session descriptions. AddIceCandidate may @@ -1657,7 +1658,7 @@ void RTCPeerConnectionHandler::AddICECandidate( std::move(current_local_description), std::move(pending_remote_description), std::move(current_remote_description), - WrapCrossThreadPersistent(candidate), std::move(result), + std::move(persistent_candidate), std::move(result), std::move(persistent_request))); }); } diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc index 862a8a747c..bed557e4f4 100644 --- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc +++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc @@ -1508,11 +1508,12 @@ void ServiceWorkerGlobalScope::StartFetchEvent( params->request->url.ElidedString().Utf8()); // Set up for navigation preload (FetchEvent#preloadResponse) if needed. - const bool navigation_preload_sent = !!params->preload_handle; + bool navigation_preload_sent = !!params->preload_url_loader_client_receiver; if (navigation_preload_sent) { To(ReportingProxy()) - .SetupNavigationPreload(event_id, params->request->url, - std::move(params->preload_handle)); + .SetupNavigationPreload( + event_id, params->request->url, + std::move(params->preload_url_loader_client_receiver)); } ScriptState::Scope scope(ScriptController()->GetScriptState()); diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc index 397d579ed7..bae1f3ac2a 100644 --- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc +++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc @@ -258,14 +258,11 @@ bool ServiceWorkerGlobalScopeProxy::IsServiceWorkerGlobalScopeProxy() const { void ServiceWorkerGlobalScopeProxy::SetupNavigationPreload( int fetch_event_id, const KURL& url, - mojom::blink::FetchEventPreloadHandlePtr preload_handle) { + mojo::PendingReceiver + preload_url_loader_client_receiver) { DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_); - auto web_preload_handle = std::make_unique(); - web_preload_handle->url_loader = std::move(preload_handle->url_loader); - web_preload_handle->url_loader_client_receiver = - std::move(preload_handle->url_loader_client_receiver); - Client().SetupNavigationPreload(fetch_event_id, url, - std::move(web_preload_handle)); + Client().SetupNavigationPreload( + fetch_event_id, url, std::move(preload_url_loader_client_receiver)); } void ServiceWorkerGlobalScopeProxy::RequestTermination( diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h index 783dbe1919..d54a2449da 100644 --- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h +++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h @@ -129,7 +129,8 @@ class ServiceWorkerGlobalScopeProxy final : public WebServiceWorkerContextProxy, void SetupNavigationPreload( int fetch_event_id, const KURL& url, - mojom::blink::FetchEventPreloadHandlePtr preload_handle); + mojo::PendingReceiver + preload_url_loader_client_receiver); void RequestTermination(WTF::CrossThreadOnceFunction callback); // Detaches this proxy object entirely from the outside world, clearing out diff --git a/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc b/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc index cf863b343b..f6a0dc5e5c 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc +++ b/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc @@ -37,6 +37,7 @@ #include "third_party/blink/renderer/platform/bindings/exception_messages.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/wtf/math_extras.h" +#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" #include "third_party/fdlibm/ieee754.h" #if defined(ARCH_CPU_X86_FAMILY) @@ -133,7 +134,12 @@ float AudioParamTimeline::ExponentialRampAtTime(double t, double time1, float value2, double time2) { - return value1 * fdlibm::pow(value2 / value1, (t - time1) / (time2 - time1)); + DCHECK(!std::isnan(value1) && std::isfinite(value1)); + DCHECK(!std::isnan(value2) && std::isfinite(value2)); + + return (value1 == 0.0f || std::signbit(value1) != std::signbit(value2)) + ? value1 + : value1 * fdlibm::pow(value2 / value1, (t - time1) / (time2 - time1)); } // Compute the value of a set target event at time t with the given event @@ -998,6 +1004,8 @@ float AudioParamTimeline::ValuesForFrameRangeImpl( std::tie(value2, time2, next_event_type) = HandleCancelValues(event, next_event, value2, time2); + DCHECK(!std::isnan(value1)); + DCHECK(!std::isnan(value2)); DCHECK_GE(time2, time1); // |fillToEndFrame| is the exclusive upper bound of the last frame to be @@ -1057,7 +1065,6 @@ float AudioParamTimeline::ValuesForFrameRangeImpl( value = event->Value(); write_index = FillWithDefault(values, value, fill_to_frame, write_index); - break; } @@ -1400,6 +1407,7 @@ AudioParamTimeline::HandleCancelValues(const ParamEvent* current_event, value2 = ExponentialRampAtTime(next_event->Time(), value1, time1, saved_event->Value(), saved_event->Time()); + DCHECK(!std::isnan(value1)); break; case ParamEvent::kSetValueCurve: case ParamEvent::kSetValueCurveEnd: diff --git a/third_party/blink/renderer/modules/webgpu/dawn_callback.h b/third_party/blink/renderer/modules/webgpu/dawn_callback.h index 812ac5b490..33f4aedcf6 100644 --- a/third_party/blink/renderer/modules/webgpu/dawn_callback.h +++ b/third_party/blink/renderer/modules/webgpu/dawn_callback.h @@ -17,8 +17,8 @@ namespace blink { // void* and passed to Dawn C callbacks. // // Example: -// DawnCallback* callback = -// CreateDawnCallback(WTF::Bind(func, arg1)); +// DawnOnceCallback* callback = +// BindDawnOnceCallback(func, arg1); // // // |someDawnFunction| expects callback function with arguments: // // Args... args, void* userdata. @@ -26,81 +26,119 @@ namespace blink { // GetProcs().someDawnFunction( // callback->UnboundCallback(), callback->AsUserdata()); template -class DawnCallback; +class DawnCallbackBase; + +template +class DawnOnceCallback; + +template +class DawnRepeatingCallback; template