diff --git a/DEPS b/DEPS index 40a49997..8c4f64f 100644 --- a/DEPS +++ b/DEPS
@@ -43,7 +43,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '62edb0c29bcea560a375c89bd775c3ae572ad256', + 'v8_revision': 'c233dc130e87cb9b36c568dff576d22895a47891', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -87,7 +87,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling NaCl # and whatever else without interference from each other. - 'nacl_revision': '296d9ac73190fbd37f699461600e83b16ec0d2b3', + 'nacl_revision': '0c539908088374d1c4074e331456644b21628a65', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling dEQP # and whatever else without interference from each other.
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc index 0b88116..573e241 100644 --- a/android_webview/browser/aw_content_browser_client.cc +++ b/android_webview/browser/aw_content_browser_client.cc
@@ -311,7 +311,7 @@ content::ResourceContext* context, int render_process_id, int render_frame_id, - net::CookieOptions* options) { + const net::CookieOptions& options) { return AwCookieAccessPolicy::GetInstance()->AllowSetCookie(url, first_party, cookie_line,
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h index 960c3e88..adc27458 100644 --- a/android_webview/browser/aw_content_browser_client.h +++ b/android_webview/browser/aw_content_browser_client.h
@@ -71,7 +71,7 @@ content::ResourceContext* context, int render_process_id, int render_frame_id, - net::CookieOptions* options) override; + const net::CookieOptions& options) override; bool AllowWorkerDatabase( const GURL& url, const base::string16& name,
diff --git a/android_webview/browser/aw_cookie_access_policy.cc b/android_webview/browser/aw_cookie_access_policy.cc index 242abca..5b5274a 100644 --- a/android_webview/browser/aw_cookie_access_policy.cc +++ b/android_webview/browser/aw_cookie_access_policy.cc
@@ -100,7 +100,7 @@ content::ResourceContext* context, int render_process_id, int render_frame_id, - net::CookieOptions* options) { + const net::CookieOptions& options) { bool global = GetShouldAcceptCookies(); bool thirdParty = GetShouldAcceptThirdPartyCookies(render_process_id, render_frame_id);
diff --git a/android_webview/browser/aw_cookie_access_policy.h b/android_webview/browser/aw_cookie_access_policy.h index a2de037..867df7c 100644 --- a/android_webview/browser/aw_cookie_access_policy.h +++ b/android_webview/browser/aw_cookie_access_policy.h
@@ -62,7 +62,7 @@ content::ResourceContext* context, int render_process_id, int render_frame_id, - net::CookieOptions* options); + const net::CookieOptions& options); private: friend struct base::DefaultLazyInstanceTraits<AwCookieAccessPolicy>;
diff --git a/chrome/browser/banners/app_banner_data_fetcher.cc b/chrome/browser/banners/app_banner_data_fetcher.cc index 321e8d3e..0090d10 100644 --- a/chrome/browser/banners/app_banner_data_fetcher.cc +++ b/chrome/browser/banners/app_banner_data_fetcher.cc
@@ -188,9 +188,6 @@ return; } - AppBannerSettingsHelper::RecordMinutesFromFirstVisitToShow( - web_contents, validated_url_, GetAppIdentifier(), GetCurrentTime()); - // Definitely going to show the banner now. FOR_EACH_OBSERVER(Observer, observer_list_, OnDecidedWhetherToShow(this, true));
diff --git a/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc b/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc index c868268..b37df5f 100644 --- a/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc +++ b/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc
@@ -9,10 +9,8 @@ #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/task_runner.h" -#include "base/test/histogram_tester.h" #include "base/thread_task_runner_handle.h" #include "chrome/browser/banners/app_banner_data_fetcher_desktop.h" -#include "chrome/browser/banners/app_banner_metrics.h" #include "chrome/browser/banners/app_banner_settings_helper.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -99,7 +97,6 @@ weak_factory_.GetWeakPtr(), 128, 128)); - base::HistogramTester histograms; base::RunLoop run_loop; quit_closure_ = run_loop.QuitClosure(); scoped_ptr<TestObserver> observer(new TestObserver(fetcher.get(), @@ -110,10 +107,6 @@ EXPECT_EQ(expected_non_web_platform, non_web_platform_); EXPECT_EQ(expected_to_show, observer->will_show()); ASSERT_FALSE(fetcher->is_active()); - - // If showing the banner, ensure that the minutes histogram is recorded. - histograms.ExpectTotalCount(banners::kMinutesHistogram, - (observer->will_show() ? 1 : 0)); } void RunBannerTest(const std::string& manifest_page,
diff --git a/chrome/browser/banners/app_banner_metrics.cc b/chrome/browser/banners/app_banner_metrics.cc index f9bbd34..5ab6f59a 100644 --- a/chrome/browser/banners/app_banner_metrics.cc +++ b/chrome/browser/banners/app_banner_metrics.cc
@@ -4,48 +4,32 @@ #include "chrome/browser/banners/app_banner_metrics.h" -#include "base/metrics/histogram_macros.h" #include "base/metrics/sparse_histogram.h" namespace banners { -const char kDismissEventHistogram[] = "AppBanners.DismissEvent"; -const char kDisplayEventHistogram[] = "AppBanners.DisplayEvent"; -const char kInstallEventHistogram[] = "AppBanners.InstallEvent"; -const char kMinutesHistogram[] = - "AppBanners.MinutesFromFirstVisitToBannerShown"; -const char kUserResponseHistogram[] = "AppBanners.UserResponse"; - void TrackDismissEvent(int event) { DCHECK_LT(DISMISS_EVENT_MIN, event); DCHECK_LT(event, DISMISS_EVENT_MAX); - UMA_HISTOGRAM_SPARSE_SLOWLY(kDismissEventHistogram, event); + UMA_HISTOGRAM_SPARSE_SLOWLY("AppBanners.DismissEvent", event); } void TrackDisplayEvent(int event) { DCHECK_LT(DISPLAY_EVENT_MIN, event); DCHECK_LT(event, DISPLAY_EVENT_MAX); - UMA_HISTOGRAM_SPARSE_SLOWLY(kDisplayEventHistogram, event); + UMA_HISTOGRAM_SPARSE_SLOWLY("AppBanners.DisplayEvent", event); } void TrackInstallEvent(int event) { DCHECK_LT(INSTALL_EVENT_MIN, event); DCHECK_LT(event, INSTALL_EVENT_MAX); - UMA_HISTOGRAM_SPARSE_SLOWLY(kInstallEventHistogram, event); -} - -void TrackMinutesFromFirstVisitToBannerShown(int minutes) { - // Histogram ranges from 1 minute to the number of minutes in 21 days. - // This is one more day than the decay length of time for site engagement, - // and seven more days than the expiry of visits for the app banner - // navigation heuristic. - UMA_HISTOGRAM_CUSTOM_COUNTS(kMinutesHistogram, minutes, 1, 30240, 100); + UMA_HISTOGRAM_SPARSE_SLOWLY("AppBanners.InstallEvent", event); } void TrackUserResponse(int event) { DCHECK_LT(USER_RESPONSE_MIN, event); DCHECK_LT(event, USER_RESPONSE_MAX); - UMA_HISTOGRAM_SPARSE_SLOWLY(kUserResponseHistogram, event); + UMA_HISTOGRAM_SPARSE_SLOWLY("AppBanners.UserResponse", event); } } // namespace banners
diff --git a/chrome/browser/banners/app_banner_metrics.h b/chrome/browser/banners/app_banner_metrics.h index 0b0939ee..7c781792 100644 --- a/chrome/browser/banners/app_banner_metrics.h +++ b/chrome/browser/banners/app_banner_metrics.h
@@ -57,16 +57,9 @@ USER_RESPONSE_MAX = 7, }; -extern const char kDismissEventHistogram[]; -extern const char kDisplayEventHistogram[]; -extern const char kInstallEventHistogram[]; -extern const char kMinutesHistogram[]; -extern const char kUserResponseHistogram[]; - void TrackDismissEvent(int event); void TrackDisplayEvent(int event); void TrackInstallEvent(int event); -void TrackMinutesFromFirstVisitToBannerShown(int minutes); void TrackUserResponse(int event); }; // namespace banners
diff --git a/chrome/browser/banners/app_banner_settings_helper.cc b/chrome/browser/banners/app_banner_settings_helper.cc index aca24f6..2f0bb43 100644 --- a/chrome/browser/banners/app_banner_settings_helper.cc +++ b/chrome/browser/banners/app_banner_settings_helper.cc
@@ -8,14 +8,11 @@ #include <string> #include "base/command_line.h" -#include "base/metrics/field_trial.h" #include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" #include "chrome/browser/banners/app_banner_data_fetcher.h" #include "chrome/browser/banners/app_banner_metrics.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" -#include "chrome/browser/engagement/site_engagement_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_switches.h" #include "components/content_settings/core/browser/host_content_settings_map.h" @@ -66,11 +63,9 @@ const char kBannerParamsIndirectKey[] = "indirect"; const char kBannerParamsTotalKey[] = "total"; const char kBannerParamsMinutesKey[] = "minutes"; -const char kBannerSiteEngagementParamsKey[] = "app_banner_triggering"; -const char kBannerSiteEngagementParamsTotalKey[] = - "app_banner_triggering_total"; -// Total engagement score required before a banner will actually be triggered. +// Total site engagements where a banner could have been shown before +// a banner will actually be triggered. double gTotalEngagementToTrigger = 2; // Engagement weight assigned to direct and indirect navigations. @@ -120,26 +115,10 @@ } } -// Queries variations for the maximum site engagement score required to trigger -// the banner showing. -void UpdateSiteEngagementToTrigger() { - std::string total_param = variations::GetVariationParamValue( - SiteEngagementService::kEngagementParams, - kBannerSiteEngagementParamsTotalKey); - - if (!total_param.empty()) { - double total_engagement = -1; - - if (base::StringToDouble(total_param, &total_engagement) && - total_engagement > 0) { - AppBannerSettingsHelper::SetTotalEngagementToTrigger(total_engagement); - } - } -} - // Queries variations for updates to the default engagement values assigned // to direct and indirect navigations. void UpdateEngagementWeights() { + std::map<std::string, std::string> params; std::string direct_param = variations::GetVariationParamValue( kBannerParamsKey, kBannerParamsDirectKey); std::string indirect_param = variations::GetVariationParamValue( @@ -181,16 +160,6 @@ } } -// Returns the site engagement karma score for the given origin URL under the -// current profile. -double GetSiteEngagementScoreForOrigin( - content::WebContents* web_contents, - const GURL& origin_url) { - SiteEngagementService* service = SiteEngagementService::Get( - Profile::FromBrowserContext(web_contents->GetBrowserContext())); - return service ? service->GetScore(origin_url) : 0; -} - } // namespace void AppBannerSettingsHelper::ClearHistoryForURLs( @@ -383,10 +352,6 @@ return true; } - // Never show a banner when the package name or URL is empty. - if (package_name_or_start_url.empty()) - return false; - // Don't show if it has been added to the homescreen. base::Time added_time = GetSingleBannerEvent(web_contents, origin_url, package_name_or_start_url, @@ -417,17 +382,14 @@ return false; } - double total_engagement = 0; - if (ShouldUseSiteEngagementScore()) { - total_engagement = - GetSiteEngagementScoreForOrigin(web_contents, origin_url); - } else { - std::vector<BannerEvent> could_show_events = GetCouldShowBannerEvents( - web_contents, origin_url, package_name_or_start_url); + std::vector<BannerEvent> could_show_events = GetCouldShowBannerEvents( + web_contents, origin_url, package_name_or_start_url); - for (const auto& event : could_show_events) - total_engagement += event.engagement; - } + // Return true if the total engagement of each applicable could show event + // meets the trigger threshold. + double total_engagement = 0; + for (const auto& event : could_show_events) + total_engagement += event.engagement; if (total_engagement < gTotalEngagementToTrigger) { banners::TrackDisplayEvent(banners::DISPLAY_EVENT_NOT_VISITED_ENOUGH); @@ -443,6 +405,8 @@ const GURL& origin_url, const std::string& package_name_or_start_url) { std::vector<BannerEvent> result; + if (package_name_or_start_url.empty()) + return result; Profile* profile = Profile::FromBrowserContext(web_contents->GetBrowserContext()); @@ -490,6 +454,9 @@ DCHECK(event != APP_BANNER_EVENT_COULD_SHOW); DCHECK(event < APP_BANNER_EVENT_NUM_EVENTS); + if (package_name_or_start_url.empty()) + return base::Time(); + Profile* profile = Profile::FromBrowserContext(web_contents->GetBrowserContext()); HostContentSettingsMap* settings = @@ -513,21 +480,6 @@ return base::Time::FromInternalValue(internal_time); } -void AppBannerSettingsHelper::RecordMinutesFromFirstVisitToShow( - content::WebContents* web_contents, - const GURL& origin_url, - const std::string& package_name_or_start_url, - base::Time time) { - std::vector<BannerEvent> could_show_events = GetCouldShowBannerEvents( - web_contents, origin_url, package_name_or_start_url); - - int minutes = 0; - if (could_show_events.size()) - minutes = (time - could_show_events[0].time).InMinutes(); - - banners::TrackMinutesFromFirstVisitToBannerShown(minutes); -} - void AppBannerSettingsHelper::SetEngagementWeights(double direct_engagement, double indirect_engagement) { gDirectNavigationEngagement = direct_engagement; @@ -571,32 +523,6 @@ } void AppBannerSettingsHelper::UpdateFromFieldTrial() { - // If we are using the site engagement score, only extract the total - // engagement to trigger from the params variations. - if (ShouldUseSiteEngagementScore()) { - UpdateSiteEngagementToTrigger(); - } else { - UpdateEngagementWeights(); - UpdateMinutesBetweenVisits(); - } -} - -bool AppBannerSettingsHelper::ShouldUseSiteEngagementScore() { - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableSiteEngagementAppBanner)) { - return true; - } - - // This experiment is controlled under the same key as the broader site - // engagement experiment rather than the banner experiment. This avoids cross - // pollution with other site engagement experiments. However, this experiment - // must only be active when there is one singular group under the banner - // experiment, otherwise the banner and site engagement banner experiments - // will conflict. - // - // Making the experiment active when a variations key is present allows us - // to have experiments which enable multiple features under site engagement. - std::string param = variations::GetVariationParamValue( - SiteEngagementService::kEngagementParams, kBannerSiteEngagementParamsKey); - return !param.empty(); + UpdateEngagementWeights(); + UpdateMinutesBetweenVisits(); }
diff --git a/chrome/browser/banners/app_banner_settings_helper.h b/chrome/browser/banners/app_banner_settings_helper.h index b46bc168..3ff877c0 100644 --- a/chrome/browser/banners/app_banner_settings_helper.h +++ b/chrome/browser/banners/app_banner_settings_helper.h
@@ -117,14 +117,6 @@ const std::string& package_name_or_start_url, AppBannerEvent event); - // Record a UMA statistic measuring the minutes between the first visit to the - // site and the first showing of the banner. - static void RecordMinutesFromFirstVisitToShow( - content::WebContents* web_contents, - const GURL& origin_url, - const std::string& package_name_or_start_url, - base::Time time); - // Set the engagement weights assigned to direct and indirect navigations. static void SetEngagementWeights(double direct_engagement, double indirect_engagement); @@ -145,10 +137,6 @@ // Updates all values from field trial. static void UpdateFromFieldTrial(); - // Returns true if the app banner trigger condition should use the site - // engagement score instead of the navigation-based heuristic. - static bool ShouldUseSiteEngagementScore(); - private: DISALLOW_IMPLICIT_CONSTRUCTORS(AppBannerSettingsHelper); };
diff --git a/chrome/browser/banners/app_banner_settings_helper_unittest.cc b/chrome/browser/banners/app_banner_settings_helper_unittest.cc index 254758a..82550f1 100644 --- a/chrome/browser/banners/app_banner_settings_helper_unittest.cc +++ b/chrome/browser/banners/app_banner_settings_helper_unittest.cc
@@ -4,14 +4,8 @@ #include <vector> -#include "base/command_line.h" -#include "chrome/browser/banners/app_banner_metrics.h" #include "chrome/browser/banners/app_banner_settings_helper.h" -#include "chrome/browser/engagement/site_engagement_service.h" -#include "chrome/browser/engagement/site_engagement_service_factory.h" -#include "chrome/common/chrome_switches.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" -#include "chrome/test/base/testing_profile.h" #include "ui/base/page_transition_types.h" namespace { @@ -737,93 +731,3 @@ EXPECT_TRUE(AppBannerSettingsHelper::ShouldShowBanner( web_contents(), url, kTestPackageName, reference_time)); } - -TEST_F(AppBannerSettingsHelperTest, ShouldShowWithHigherTotal) { - AppBannerSettingsHelper::SetEngagementWeights(1, 1); - AppBannerSettingsHelper::SetTotalEngagementToTrigger(5); - GURL url(kTestURL); - NavigateAndCommit(url); - - base::Time reference_time = GetReferenceTime(); - base::Time second_day = reference_time + base::TimeDelta::FromDays(1); - base::Time third_day = reference_time + base::TimeDelta::FromDays(2); - base::Time fourth_day = reference_time + base::TimeDelta::FromDays(3); - base::Time fifth_day = reference_time + base::TimeDelta::FromDays(4); - - EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( - web_contents(), url, kTestPackageName, reference_time)); - - // It should take five visits to trigger the banner. - AppBannerSettingsHelper::RecordBannerCouldShowEvent( - web_contents(), url, kTestPackageName, reference_time, - ui::PAGE_TRANSITION_LINK); - EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( - web_contents(), url, kTestPackageName, reference_time)); - - AppBannerSettingsHelper::RecordBannerCouldShowEvent( - web_contents(), url, kTestPackageName, second_day, - ui::PAGE_TRANSITION_TYPED); - EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( - web_contents(), url, kTestPackageName, second_day)); - - AppBannerSettingsHelper::RecordBannerCouldShowEvent( - web_contents(), url, kTestPackageName, third_day, - ui::PAGE_TRANSITION_GENERATED); - EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( - web_contents(), url, kTestPackageName, third_day)); - - AppBannerSettingsHelper::RecordBannerCouldShowEvent( - web_contents(), url, kTestPackageName, fourth_day, - ui::PAGE_TRANSITION_LINK); - EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( - web_contents(), url, kTestPackageName, fourth_day)); - - // Visit the site again; now it should be shown. - AppBannerSettingsHelper::RecordBannerCouldShowEvent( - web_contents(), url, kTestPackageName, fifth_day, - ui::PAGE_TRANSITION_TYPED); - EXPECT_TRUE(AppBannerSettingsHelper::ShouldShowBanner( - web_contents(), url, kTestPackageName, fifth_day)); -} - -// Test that the banner triggers correctly using site engagement. -TEST_F(AppBannerSettingsHelperTest, SiteEngagementTrigger) { - AppBannerSettingsHelper::SetTotalEngagementToTrigger(2); - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - command_line->AppendSwitch(switches::kEnableSiteEngagementAppBanner); - - SiteEngagementService* service = - SiteEngagementServiceFactory::GetForProfile(profile()); - DCHECK(service); - - // Not used, but needed for method call. - base::Time reference_time = GetReferenceTime(); - GURL url(kTestURL); - - EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( - web_contents(), url, kTestPackageName, reference_time)); - - service->AddPoints(url, 1); - EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( - web_contents(), url, kTestPackageName, reference_time)); - - service->AddPoints(url, 1); - EXPECT_TRUE(AppBannerSettingsHelper::ShouldShowBanner( - web_contents(), url, kTestPackageName, reference_time)); - - AppBannerSettingsHelper::SetTotalEngagementToTrigger(5); - EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( - web_contents(), url, kTestPackageName, reference_time)); - - service->AddPoints(url, 1.5); - EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( - web_contents(), url, kTestPackageName, reference_time)); - - service->AddPoints(url, 0.5); - EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( - web_contents(), url, kTestPackageName, reference_time)); - - service->AddPoints(url, 1.5); - EXPECT_TRUE(AppBannerSettingsHelper::ShouldShowBanner( - web_contents(), url, kTestPackageName, reference_time)); -}
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 14ee957..f9f87bc 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -1745,7 +1745,7 @@ content::ResourceContext* context, int render_process_id, int render_frame_id, - net::CookieOptions* options) { + const net::CookieOptions& options) { DCHECK_CURRENTLY_ON(BrowserThread::IO); ProfileIOData* io_data = ProfileIOData::FromResourceContext(context); content_settings::CookieSettings* cookie_settings = @@ -1755,7 +1755,7 @@ BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, base::Bind(&TabSpecificContentSettings::CookieChanged, render_process_id, - render_frame_id, url, first_party, cookie_line, *options, + render_frame_id, url, first_party, cookie_line, options, !allow)); return allow; }
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index ce1a1ad0..13af6ee 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h
@@ -143,7 +143,7 @@ content::ResourceContext* context, int render_process_id, int render_frame_id, - net::CookieOptions* options) override; + const net::CookieOptions& options) override; bool AllowSaveLocalState(content::ResourceContext* context) override; bool AllowWorkerDatabase( const GURL& url,
diff --git a/chrome/browser/content_settings/content_settings_browsertest.cc b/chrome/browser/content_settings/content_settings_browsertest.cc index c08f653d..32e52bc02 100644 --- a/chrome/browser/content_settings/content_settings_browsertest.cc +++ b/chrome/browser/content_settings/content_settings_browsertest.cc
@@ -33,6 +33,7 @@ #include "content/public/common/content_switches.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/test_utils.h" +#include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/url_request/url_request_mock_http_job.h" @@ -45,6 +46,19 @@ using content::BrowserThread; using net::URLRequestMockHTTPJob; +namespace { + +const LocalSharedObjectsContainer* GetSiteSettingsCookieContainer( + Browser* browser) { + TabSpecificContentSettings* settings = + TabSpecificContentSettings::FromWebContents( + browser->tab_strip_model()->GetWebContentsAt(0)); + return static_cast<const LocalSharedObjectsContainer*>( + &settings->allowed_local_shared_objects()); +} + +} // namespace + class ContentSettingsTest : public InProcessBrowserTest { public: ContentSettingsTest() : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) { @@ -232,6 +246,38 @@ IsContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES)); } +// TODO(jww): This should be removed after strict secure cookies is enabled for +// all and this test should be moved into ContentSettingsTest above. +class ContentSettingsStrictSecureCookiesBrowserTest + : public ContentSettingsTest { + protected: + void SetUpCommandLine(base::CommandLine* cmd) override { + cmd->AppendSwitch(switches::kEnableExperimentalWebPlatformFeatures); + } +}; + +// This test verifies that if strict secure cookies is enabled, the site +// settings accurately reflect that an attempt to create a secure cookie by an +// insecure origin fails. +IN_PROC_BROWSER_TEST_F(ContentSettingsStrictSecureCookiesBrowserTest, Cookies) { + host_resolver()->AddRule("*", "127.0.0.1"); + ASSERT_TRUE(embedded_test_server()->Start()); + + net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); + https_server.ServeFilesFromSourceDirectory("chrome/test/data"); + ASSERT_TRUE(https_server.Start()); + + GURL http_url = embedded_test_server()->GetURL("/setsecurecookie.html"); + GURL https_url = https_server.GetURL("/setsecurecookie.html"); + + ui_test_utils::NavigateToURL(browser(), http_url); + EXPECT_TRUE(GetSiteSettingsCookieContainer(browser())->cookies()->empty()); + + ui_test_utils::NavigateToURL(browser(), + https_server.GetURL("/setsecurecookie.html")); + EXPECT_FALSE(GetSiteSettingsCookieContainer(browser())->cookies()->empty()); +}; + IN_PROC_BROWSER_TEST_F(ContentSettingsTest, ContentSettingsBlockDataURLs) { GURL url("data:text/html,<title>Data URL</title><script>alert(1)</script>");
diff --git a/chrome/browser/engagement/site_engagement_service.cc b/chrome/browser/engagement/site_engagement_service.cc index 52cbaf0..b875eb6 100644 --- a/chrome/browser/engagement/site_engagement_service.cc +++ b/chrome/browser/engagement/site_engagement_service.cc
@@ -15,7 +15,6 @@ #include "base/time/clock.h" #include "base/time/default_clock.h" #include "base/values.h" -#include "chrome/browser/banners/app_banner_settings_helper.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/engagement/site_engagement_eviction_policy.h" #include "chrome/browser/engagement/site_engagement_helper.h" @@ -282,8 +281,7 @@ // return true immediately. if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableSiteEngagementService) || - SiteEngagementEvictionPolicy::IsEnabled() || - AppBannerSettingsHelper::ShouldUseSiteEngagementScore()) { + SiteEngagementEvictionPolicy::IsEnabled()) { return true; }
diff --git a/chrome/browser/engagement/site_engagement_service.h b/chrome/browser/engagement/site_engagement_service.h index 46bf9896..6489fff 100644 --- a/chrome/browser/engagement/site_engagement_service.h +++ b/chrome/browser/engagement/site_engagement_service.h
@@ -180,7 +180,6 @@ FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest, GetTotalUserInputPoints); FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest, CleanupOriginsOnHistoryDeletion); - FRIEND_TEST_ALL_PREFIXES(AppBannerSettingsHelperTest, SiteEngagementTrigger); // Only used in tests. SiteEngagementService(Profile* profile, scoped_ptr<base::Clock> clock);
diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc index b7fc936..eeee086 100644 --- a/chrome/browser/net/chrome_network_delegate.cc +++ b/chrome/browser/net/chrome_network_delegate.cc
@@ -14,6 +14,7 @@ #include "base/debug/dump_without_crashing.h" #include "base/debug/stack_trace.h" #include "base/logging.h" +#include "base/metrics/field_trial.h" #include "base/metrics/histogram.h" #include "base/metrics/sparse_histogram.h" #include "base/metrics/user_metrics.h" @@ -725,6 +726,14 @@ return experimental_web_platform_features_enabled_; } +bool ChromeNetworkDelegate::OnAreStrictSecureCookiesEnabled() const { + const std::string enforce_strict_secure_group = + base::FieldTrialList::FindFullName("StrictSecureCookies"); + return experimental_web_platform_features_enabled_ || + base::StartsWith(enforce_strict_secure_group, "Enabled", + base::CompareCase::INSENSITIVE_ASCII); +} + bool ChromeNetworkDelegate::OnCancelURLRequestWithPolicyViolatingReferrerHeader( const net::URLRequest& request, const GURL& target_url,
diff --git a/chrome/browser/net/chrome_network_delegate.h b/chrome/browser/net/chrome_network_delegate.h index e0ab87af..901e5423 100644 --- a/chrome/browser/net/chrome_network_delegate.h +++ b/chrome/browser/net/chrome_network_delegate.h
@@ -183,6 +183,7 @@ const GURL& url, const GURL& first_party_for_cookies) const override; bool OnAreExperimentalCookieFeaturesEnabled() const override; + bool OnAreStrictSecureCookiesEnabled() const override; bool OnCancelURLRequestWithPolicyViolatingReferrerHeader( const net::URLRequest& request, const GURL& target_url,
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc index b4dfc61..a7416d75 100644 --- a/chrome/browser/ssl/ssl_browser_tests.cc +++ b/chrome/browser/ssl/ssl_browser_tests.cc
@@ -552,36 +552,6 @@ net::EmbeddedTestServer https_server_mismatched_; net::SpawnedTestServer wss_server_expired_; - protected: - // Navigates to an interstitial and clicks through the certificate - // error; then navigates to a page at |path| that loads unsafe content. - void SetUpUnsafeContentsWithUserException(const std::string& path) { - ASSERT_TRUE(https_server_.Start()); - // Note that it is necessary to user https_server_mismatched_ here over the - // other invalid cert servers. This is because the test relies on the two - // servers having different hosts since SSL exceptions are per-host, not per - // origin, and https_server_mismatched_ uses 'localhost' rather than - // '127.0.0.1'. - ASSERT_TRUE(https_server_mismatched_.Start()); - - // Navigate to an unsafe site. Proceed with interstitial page to indicate - // the user approves the bad certificate. - ui_test_utils::NavigateToURL( - browser(), https_server_mismatched_.GetURL("/ssl/blank_page.html")); - WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); - CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID, - AuthState::SHOWING_INTERSTITIAL); - ProceedThroughInterstitial(tab); - CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID, - AuthState::NONE); - - std::string replacement_path; - GetFilePathWithHostAndPortReplacement( - path, https_server_mismatched_.host_port_pair(), &replacement_path); - ui_test_utils::NavigateToURL(browser(), - https_server_.GetURL(replacement_path)); - } - private: typedef net::SpawnedTestServer::SSLOptions SSLOptions; @@ -2152,7 +2122,10 @@ // This test, and the related test TestUnsafeContentsWithUserException, verify // that if unsafe content is loaded but the host of that unsafe content has a -// user exception, the content runs and the security style is downgraded. +// user exception, the content runs and the security style remains +// authenticated. This is not necessarily the behavior that should exist, but it +// is verification that it does behave that way. See https://crbug.com/477868 +// for more inforamtion on this. IN_PROC_BROWSER_TEST_F(SSLUITest, TestUnsafeContentsInWorkerWithUserException) { ASSERT_TRUE(https_server_.Start()); // Note that it is necessary to user https_server_mismatched_ here over the @@ -2182,19 +2155,44 @@ ui_test_utils::NavigateToURL( browser(), https_server_.GetURL(page_with_unsafe_worker_path)); CheckWorkerLoadResult(tab, true); // Worker loads insecure content - CheckAuthenticationBrokenState(tab, CertError::NONE, - AuthState::RAN_INSECURE_CONTENT); + CheckAuthenticatedState(tab, CertError::NONE); } // Visits a page with unsafe content and makes sure that if a user exception to // the certificate error is present, the image is loaded and script executes. +// +// See the comment above SSLUITest.TestUnsafeContentsInWorkerWithUserException +// for a discussion about the desired behavior. IN_PROC_BROWSER_TEST_F(SSLUITest, TestUnsafeContentsWithUserException) { + ASSERT_TRUE(https_server_.Start()); + // Note that it is necessary to user https_server_mismatched_ here over the + // other invalid cert servers. This is because the test relies on the two + // servers having different hosts since SSL exceptions are per-host, not per + // origin, and https_server_mismatched_ uses 'localhost' rather than + // '127.0.0.1'. + ASSERT_TRUE(https_server_mismatched_.Start()); + + // Navigate to an unsafe site. Proceed with interstitial page to indicate + // the user approves the bad certificate. + ui_test_utils::NavigateToURL( + browser(), https_server_mismatched_.GetURL("/ssl/blank_page.html")); WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); - ASSERT_NO_FATAL_FAILURE(SetUpUnsafeContentsWithUserException( - "/ssl/page_with_unsafe_contents.html")); - CheckAuthenticationBrokenState( - tab, CertError::NONE, - AuthState::RAN_INSECURE_CONTENT | AuthState::DISPLAYED_INSECURE_CONTENT); + CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID, + AuthState::SHOWING_INTERSTITIAL); + ProceedThroughInterstitial(tab); + CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID, + AuthState::NONE); + + std::string replacement_path; + GetFilePathWithHostAndPortReplacement( + "/ssl/page_with_unsafe_contents.html", + https_server_mismatched_.host_port_pair(), &replacement_path); + ui_test_utils::NavigateToURL(browser(), + https_server_.GetURL(replacement_path)); + + // When the bad content is filtered, the state is expected to be + // authenticated. + CheckAuthenticatedState(tab, AuthState::NONE); int img_width; EXPECT_TRUE(content::ExecuteScriptAndExtractInt( @@ -2208,38 +2206,7 @@ EXPECT_TRUE(content::ExecuteScriptAndExtractBool( tab, "window.domAutomationController.send(IsFooSet());", &js_result)); EXPECT_TRUE(js_result); - - // Test that active subresources with the same certificate errors as - // the main resources don't cause mixed content UI downgrades. (Such - // errors would be confusing and duplicative.) - std::string replacement_path; - GetFilePathWithHostAndPortReplacement( - "/ssl/page_with_unsafe_contents.html", - https_server_mismatched_.host_port_pair(), &replacement_path); - ui_test_utils::NavigateToURL( - browser(), https_server_mismatched_.GetURL(replacement_path)); - js_result = false; - EXPECT_TRUE(content::ExecuteScriptAndExtractBool( - tab, "window.domAutomationController.send(IsFooSet());", &js_result)); - EXPECT_TRUE(js_result); - CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID, - AuthState::NONE); -} - -// Like the test above, but only displaying inactive content (an image). -IN_PROC_BROWSER_TEST_F(SSLUITest, TestUnsafeImageWithUserException) { - WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); - ASSERT_NO_FATAL_FAILURE( - SetUpUnsafeContentsWithUserException("/ssl/page_with_unsafe_image.html")); - CheckAuthenticatedState(tab, AuthState::DISPLAYED_INSECURE_CONTENT); - - int img_width; - EXPECT_TRUE(content::ExecuteScriptAndExtractInt( - tab, "window.domAutomationController.send(ImageWidth());", &img_width)); - // In order to check that the image was loaded, we check its width. - // The actual image (Google logo) is 114 pixels wide, so we assume a good - // image is greater than 100. - EXPECT_GT(img_width, 100); + CheckAuthenticatedState(tab, CertError::NONE); } // Test that when the browser blocks displaying insecure content (images), the
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index f71178a..9443ec0 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc
@@ -520,12 +520,6 @@ const char kDisableSimplifiedFullscreenUI[] = "disable-simplified-fullscreen-ui"; -// Enable the Site Engagement App Banner which triggers app install banners -// using the site engagement service rather than a navigation-based heuristic. -// Implicitly enables the site engagement service. -const char kEnableSiteEngagementAppBanner[] = - "enable-site-engagement-app-banner"; - // Enable the Site Engagement Eviction Policy which evicts temporary storage // using the site engagement service. Implicitly enables the site engagement // service.
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 67908f2..6a4e48f 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h
@@ -150,7 +150,6 @@ extern const char kDisableSettingsWindow[]; extern const char kEnableSimplifiedFullscreenUI[]; extern const char kDisableSimplifiedFullscreenUI[]; -extern const char kEnableSiteEngagementAppBanner[]; extern const char kEnableSiteEngagementEvictionPolicy[]; extern const char kEnableSiteEngagementService[]; extern const char kEnableSupervisedUserManagedBookmarksFolder[];
diff --git a/chrome/test/data/setsecurecookie.html b/chrome/test/data/setsecurecookie.html new file mode 100644 index 0000000..18dc2dd --- /dev/null +++ b/chrome/test/data/setsecurecookie.html
@@ -0,0 +1,17 @@ +<html> +<head> +<title>This page sets a secure cookie</title> +<script type="text/javascript"> +function makeCookie() +{ + console.log("cookies = " + document.cookie); + expireAt = new Date; + expireAt.setMonth(expireAt.getMonth() + 3); + username = "Good"; + document.cookie = "name=" + username + ";expires=" + expireAt.toGMTString() + + ";secure"; +} +makeCookie(); +</script> +</head> +</html>
diff --git a/chrome/test/data/ssl/page_with_dynamic_unsafe_image.html b/chrome/test/data/ssl/page_with_dynamic_unsafe_image.html deleted file mode 100644 index d232531..0000000 --- a/chrome/test/data/ssl/page_with_dynamic_unsafe_image.html +++ /dev/null
@@ -1,13 +0,0 @@ -<html> -<head><title>Page with unsafe image loaded dynamically</title> -<script> - var url = "https://REPLACE_WITH_HOST_AND_PORT/ssl/google_files/logo.gif"; - - function AddImage() { - var img = document.createElement("img"); - img.src = url; - document.body.appendChild(img); - } -</script> -<body></body> -</html>
diff --git a/chrome/test/data/ssl/page_with_unsafe_image.html b/chrome/test/data/ssl/page_with_unsafe_image.html deleted file mode 100644 index 9136e377..0000000 --- a/chrome/test/data/ssl/page_with_unsafe_image.html +++ /dev/null
@@ -1,14 +0,0 @@ -<html> -<head><title>Page with unsafe image</title> -<script> - function ImageWidth() { - return document.getElementById("bad_image").width; - } -</script> -</head> - -<body> -This page contains an image which is served over an insecure HTTPS connection...<br> -<img id="bad_image" src="https://REPLACE_WITH_HOST_AND_PORT/ssl/google_files/logo.gif"/> -</body> -</html>
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.cc index eaaf44e3..572cce52 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.cc
@@ -250,6 +250,10 @@ "DataReductionProxy.HeaderTamperDetectionHTTP_Image_500KB", carrier_id_); } + } else if (net::MatchesMimeType("video/*", mime_type)) { + REPORT_TAMPER_DETECTION_UMA( + scheme_is_https_, "DataReductionProxy.HeaderTamperDetectionHTTPS_Video", + "DataReductionProxy.HeaderTamperDetectionHTTP_Video", carrier_id_); } } @@ -490,6 +494,12 @@ REPORT_TAMPER_DETECTION_UMA_COMPRESSION_RATIO( scheme_is_https_, "_Image_500KB", compression_ratio); } + } else if (net::MatchesMimeType("video/*", mime_type)) { + REPORT_TAMPER_DETECTION_UMA_AND_COMPRESSION_RATIO( + scheme_is_https_, + "DataReductionProxy.HeaderTamperedHTTPS_ContentLength_Video", + "DataReductionProxy.HeaderTamperedHTTP_ContentLength_Video", + carrier_id_, "_Video", compression_ratio); } else { REPORT_TAMPER_DETECTION_UMA( scheme_is_https_,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.h index 03611d6..b497712 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.h
@@ -105,6 +105,8 @@ HistogramCount); FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest, DetectAndReport); + FRIEND_TEST_ALL_PREFIXES(DataReductionProxyTamperDetectionTest, + CompressionRatio); // Reports UMA for the numbers of responses with valid fingerprints, separated // by MIME type.
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection_unittest.cc index cdda92c..fff0914 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection_unittest.cc
@@ -4,9 +4,9 @@ #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.h" -#include <string.h> #include <algorithm> #include <map> +#include <string> #include <vector> #include "base/base64.h" @@ -14,6 +14,7 @@ #include "base/memory/scoped_ptr.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" +#include "base/strings/stringprintf.h" #include "base/test/histogram_tester.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers_test_utils.h" @@ -606,45 +607,35 @@ // Checks the correctness of histogram for Javascript {"HTTP/1.1 200 OK\n" "Content-Type: text/javascript\n", - "_JS", - -1, - ""}, + "_JS", -1, ""}, // Checks the correctness of histogram for CSS {"HTTP/1.1 200 OK\n" "Content-Type: text/css\n", - "_CSS", - -1, - ""}, + "_CSS", -1, ""}, // Checks the correctness of histogram for image {"HTTP/1.1 200 OK\n" "Content-Type: image/test\n", - "_Image", - 1, - "_Image_0_10KB"}, + "_Image", 1, "_Image_0_10KB"}, // Checks the correctness of histogram for GIF {"HTTP/1.1 200 OK\n" "Content-Type: image/gif\n", - "_Image_GIF", - 20 * 1024, - "_Image_10_100KB"}, + "_Image_GIF", 20 * 1024, "_Image_10_100KB"}, // Checks the correctness of histogram for JPG {"HTTP/1.1 200 OK\n" "Content-Type: image/jpeg\n", - "_Image_JPG", - 200 * 1024, - "_Image_100_500KB"}, + "_Image_JPG", 200 * 1024, "_Image_100_500KB"}, // Checks the correctness of histogram for PNG {"HTTP/1.1 200 OK\n" "Content-Type: image/png\n", - "_Image_PNG", - 600 * 1024, - "_Image_500KB"}, + "_Image_PNG", 600 * 1024, "_Image_500KB"}, // Checks the correctness of histogram for WebP {"HTTP/1.1 200 OK\n" "Content-Type: image/webp\n", - "_Image_WEBP", - -1, - ""}, + "_Image_WEBP", -1, ""}, + // Checks the correctness of histogram for Video + {"HTTP/1.1 200 OK\n" + "Content-Type: video/webm\n", + "_Video", -1, ""}, }; const int carrier_id = 100; @@ -665,37 +656,113 @@ tamper_detection.ReportUMAForTamperDetectionCount( test.original_content_length); histogram_tester.ExpectTotalCount( - std::string("DataReductionProxy.HeaderTamperDetectionHTTP") + - (https ? "S" : "") + test.histogram_name_suffix + "_Total", + base::StringPrintf("DataReductionProxy.HeaderTamperDetectionHTTP%s" + "%s_Total", + (https ? "S" : ""), + test.histogram_name_suffix.c_str()), 1); histogram_tester.ExpectUniqueSample( - std::string("DataReductionProxy.HeaderTamperDetectionHTTP") + - (https ? "S" : "") + test.histogram_name_suffix, + base::StringPrintf("DataReductionProxy.HeaderTamperDetectionHTTP%s" + "%s", + (https ? "S" : ""), + test.histogram_name_suffix.c_str()), carrier_id, 1); histogram_tester.ExpectTotalCount( - std::string("DataReductionProxy.HeaderTamperDetectionHTTP") + - (https ? "S" : "") + "_Total", + base::StringPrintf("DataReductionProxy.HeaderTamperDetectionHTTP%s" + "_Total", + (https ? "S" : "")), 1); histogram_tester.ExpectUniqueSample( - std::string("DataReductionProxy.HeaderTamperDetectionHTTP") + - (https ? "S" : ""), + base::StringPrintf("DataReductionProxy.HeaderTamperDetectionHTTP%s", + (https ? "S" : "")), carrier_id, 1); if (test.original_content_length != -1) { histogram_tester.ExpectTotalCount( - std::string("DataReductionProxy.HeaderTamperDetectionHTTP") + - (https ? "S" : "") + test.image_histogram_name_suffix + - "_Total", + base::StringPrintf("DataReductionProxy.HeaderTamperDetectionHTTP%s" + "%s_Total", + (https ? "S" : ""), + test.image_histogram_name_suffix.c_str()), 1); histogram_tester.ExpectUniqueSample( - std::string("DataReductionProxy.HeaderTamperDetectionHTTP") + - (https ? "S" : "") + test.image_histogram_name_suffix, + base::StringPrintf("DataReductionProxy.HeaderTamperDetectionHTTP%s" + "%s", + (https ? "S" : ""), + test.image_histogram_name_suffix.c_str()), carrier_id, 1); } } } } +// Tests function ReportUMAForContentLength, with the focus on compression +// ratio. +TEST_F(DataReductionProxyTamperDetectionTest, CompressionRatio) { + struct { + std::string raw_header; + std::string histogram_name_suffix; + int original_content_length; + int content_length; + int compression_ratio; + ; + } tests[] = { + // Checks the correctness of histogram for Video + {"HTTP/1.1 200 OK\n" + "Content-Type: video/webm\n", + "_Video", 1000, 800, 80}, + // Checks the correctness of histogram for JPEG + {"HTTP/1.1 200 OK\n" + "Content-Type: image/jpg\n", + "_Image_JPG", 1000, 1, 0}, + // Checks the correctness of histogram for PNG + {"HTTP/1.1 200 OK\n" + "Content-Type: image/png\n", + "_Image_PNG", 1000, 0, 0}, + // Checks the correctness of histogram for WebP + {"HTTP/1.1 200 OK\n" + "Content-Type: image/webp\n", + "_Image_WEBP", 1000, 5000, 500}, + }; + + const int carrier_id = 100; + + for (auto& test : tests) { + std::string raw_headers(test.raw_header); + HeadersToRaw(&raw_headers); + scoped_refptr<net::HttpResponseHeaders> headers( + new net::HttpResponseHeaders(raw_headers)); + + // Test HTTPS and HTTP separately. + int https_values[] = {true, false}; + for (auto https : https_values) { + base::HistogramTester histogram_tester; + + DataReductionProxyTamperDetection tamper_detection(headers.get(), https, + carrier_id); + tamper_detection.ReportUMAForContentLength(test.content_length, + test.original_content_length); + histogram_tester.ExpectTotalCount( + base::StringPrintf("DataReductionProxy.HeaderTamperedHTTP%s" + "_ContentLength%s_Total", + (https ? "S" : ""), + test.histogram_name_suffix.c_str()), + 1); + histogram_tester.ExpectUniqueSample( + base::StringPrintf("DataReductionProxy.HeaderTamperedHTTP%s" + "_ContentLength%s", + (https ? "S" : ""), + test.histogram_name_suffix.c_str()), + carrier_id, 1); + histogram_tester.ExpectUniqueSample( + base::StringPrintf("DataReductionProxy.HeaderTamperedHTTP%s" + "_CompressionRatio%s", + (https ? "S" : ""), + test.histogram_name_suffix.c_str()), + test.compression_ratio, 1); + } + } +} + // Tests main function DetectAndReport. TEST_F(DataReductionProxyTamperDetectionTest, DetectAndReport) { struct {
diff --git a/components/web_view/frame.cc b/components/web_view/frame.cc index 39077ae..de267a3 100644 --- a/components/web_view/frame.cc +++ b/components/web_view/frame.cc
@@ -387,12 +387,12 @@ // case we do not use the WindowTreeClient (because the app has a Window // already // and ends up reusing it). - DCHECK(!window_tree_client.get()); + DCHECK(!window_tree_client); ChangeClient(frame_client, user_data.Pass(), window_tree_client.Pass(), app_id, navigation_start_time); } else { waiting_for_on_will_navigate_ack_ = true; - DCHECK(window_tree_client.get()); + DCHECK(window_tree_client); // TODO(sky): url isn't correct here, it should be a security origin. frame_client_->OnWillNavigate( url.spec(),
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc index e297d778..671708a 100644 --- a/content/browser/browser_child_process_host_impl.cc +++ b/content/browser/browser_child_process_host_impl.cc
@@ -401,8 +401,6 @@ const base::Process& process = child_process_->GetProcess(); DCHECK(process.IsValid()); -#if defined(OS_WIN) - // TODO(jam): enable on POSIX if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) { mojo::embedder::ScopedPlatformHandle client_pipe = mojo::embedder::ChildProcessLaunched(process.Handle()); @@ -415,7 +413,6 @@ #endif process.Handle(), true))); } -#endif #if defined(OS_WIN) // Start a WaitableEventWatcher that will invoke OnProcessExitedEarly if the
diff --git a/content/browser/frame_host/render_frame_message_filter.cc b/content/browser/frame_host/render_frame_message_filter.cc index 462f219..f14f8eb 100644 --- a/content/browser/frame_host/render_frame_message_filter.cc +++ b/content/browser/frame_host/render_frame_message_filter.cc
@@ -351,22 +351,22 @@ } net::CookieOptions options; + bool experimental_web_platform_features_enabled = + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableExperimentalWebPlatformFeatures); + const std::string enforce_strict_secure_group = + base::FieldTrialList::FindFullName(kEnforceStrictSecureExperiment); + if (experimental_web_platform_features_enabled) + options.set_enforce_prefixes(); + if (experimental_web_platform_features_enabled || + base::StartsWith(enforce_strict_secure_group, "Enabled", + base::CompareCase::INSENSITIVE_ASCII)) { + options.set_enforce_strict_secure(); + } if (GetContentClient()->browser()->AllowSetCookie( url, first_party_for_cookies, cookie, resource_context_, - render_process_id_, render_frame_id, &options)) { + render_process_id_, render_frame_id, options)) { net::URLRequestContext* context = GetRequestContextForURL(url); - bool experimental_web_platform_features_enabled = - base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableExperimentalWebPlatformFeatures); - const std::string enforce_strict_secure_group = - base::FieldTrialList::FindFullName(kEnforceStrictSecureExperiment); - if (experimental_web_platform_features_enabled) - options.set_enforce_prefixes(); - if (experimental_web_platform_features_enabled || - base::StartsWith(enforce_strict_secure_group, "Enabled", - base::CompareCase::INSENSITIVE_ASCII)) { - options.set_enforce_strict_secure(); - } // Pass a null callback since we don't care about when the 'set' completes. context->cookie_store()->SetCookieWithOptionsAsync( url, cookie, options, net::CookieStore::SetCookiesCallback());
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc index e8a404f..6238b25 100644 --- a/content/browser/loader/resource_loader.cc +++ b/content/browser/loader/resource_loader.cc
@@ -115,9 +115,6 @@ GetSSLStatusForRequest(request->url(), request->ssl_info(), info->GetChildID(), &ssl_status); response->head.security_info = SerializeSecurityInfo(ssl_status); - response->head.has_major_certificate_errors = - net::IsCertStatusError(ssl_status.cert_status) && - !net::IsCertStatusMinorError(ssl_status.cert_status); } else { // We should not have any SSL state. DCHECK(!request->ssl_info().cert_status);
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index c695f6f..12fb07aa 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2478,8 +2478,6 @@ SendExternalMojoShellHandleToChild(GetHandle(), this); #endif -#if defined(OS_WIN) - // TODO(jam): enable on POSIX if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk") && child_process_launcher_.get()) { base::ProcessHandle process_handle = @@ -2495,7 +2493,6 @@ #endif process_handle, true))); } -#endif // Allow Mojo to be setup before the renderer sees any Chrome IPC messages. // This way, Mojo can be safely used from the renderer in response to any
diff --git a/content/browser/ssl/ssl_manager.cc b/content/browser/ssl/ssl_manager.cc index c1b42f0..cd6c2bea 100644 --- a/content/browser/ssl/ssl_manager.cc +++ b/content/browser/ssl/ssl_manager.cc
@@ -134,7 +134,11 @@ NotifyDidChangeVisibleSSLState(); } -void SSLManager::DidRunInsecureContent(const GURL& security_origin) { +void SSLManager::DidDisplayInsecureContent() { + UpdateEntry(controller_->GetLastCommittedEntry()); +} + +void SSLManager::DidRunInsecureContent(const std::string& security_origin) { NavigationEntryImpl* navigation_entry = controller_->GetLastCommittedEntry(); policy()->DidRunInsecureContent(navigation_entry, security_origin); UpdateEntry(navigation_entry);
diff --git a/content/browser/ssl/ssl_manager.h b/content/browser/ssl/ssl_manager.h index fb31a25..6e46705 100644 --- a/content/browser/ssl/ssl_manager.h +++ b/content/browser/ssl/ssl_manager.h
@@ -31,7 +31,6 @@ struct LoadFromMemoryCacheDetails; struct ResourceRedirectDetails; struct ResourceRequestDetails; -struct SSLStatus; // The SSLManager SSLManager controls the SSL UI elements in a WebContents. It // listens for various events that influence when these elements should or @@ -89,7 +88,8 @@ void DidReceiveResourceRedirect(const ResourceRedirectDetails& details); // Insecure content entry point. - void DidRunInsecureContent(const GURL& security_origin); + void DidDisplayInsecureContent(); + void DidRunInsecureContent(const std::string& security_origin); private: // Updates the NavigationEntry with our current state. This will
diff --git a/content/browser/ssl/ssl_policy.cc b/content/browser/ssl/ssl_policy.cc index 06677dc..ed8d80b3 100644 --- a/content/browser/ssl/ssl_policy.cc +++ b/content/browser/ssl/ssl_policy.cc
@@ -105,7 +105,7 @@ } void SSLPolicy::DidRunInsecureContent(NavigationEntryImpl* entry, - const GURL& security_origin) { + const std::string& security_origin) { if (!entry) return; @@ -113,16 +113,20 @@ if (!site_instance) return; - backend_->HostRanInsecureContent(security_origin.host(), + backend_->HostRanInsecureContent(GURL(security_origin).host(), site_instance->GetProcess()->GetID()); } void SSLPolicy::OnRequestStarted(SSLRequestInfo* info) { - if (info->ssl_cert_id() && info->url().SchemeIsCryptographic() && - !net::IsCertStatusError(info->ssl_cert_status())) { - // If the scheme is https: or wss: *and* the security info for the - // cert has been set (i.e. the cert id is not 0) and the cert did - // not have any errors, revoke any previous decisions that + // TODO(abarth): This mechanism is wrong. What we should be doing is sending + // this information back through WebKit and out some FrameLoaderClient + // methods. + + if (net::IsCertStatusError(info->ssl_cert_status())) { + backend_->HostRanInsecureContent(info->url().host(), info->child_id()); + } else if (info->ssl_cert_id() && info->url().SchemeIsCryptographic()) { + // If the scheme is https: or wss: *and* the security info for the cert has + // been set (i.e. the cert id is not 0), revoke any previous decisions that // have occurred. If the cert info has not been set, do nothing since it // isn't known if the connection was actually a valid connection or if it // had a cert error.
diff --git a/content/browser/ssl/ssl_policy.h b/content/browser/ssl/ssl_policy.h index c002bfc..2855a1b 100644 --- a/content/browser/ssl/ssl_policy.h +++ b/content/browser/ssl/ssl_policy.h
@@ -36,7 +36,7 @@ void OnCertError(SSLCertErrorHandler* handler); void DidRunInsecureContent(NavigationEntryImpl* entry, - const GURL& security_origin); + const std::string& security_origin); // We have started a resource request with the given info. void OnRequestStarted(SSLRequestInfo* info);
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index da841da..7556ae8 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -645,10 +645,6 @@ OnDidDisplayInsecureContent) IPC_MESSAGE_HANDLER(FrameHostMsg_DidRunInsecureContent, OnDidRunInsecureContent) - IPC_MESSAGE_HANDLER(FrameHostMsg_DidDisplayContentWithCertificateErrors, - OnDidDisplayContentWithCertificateErrors) - IPC_MESSAGE_HANDLER(FrameHostMsg_DidRunContentWithCertificateErrors, - OnDidRunContentWithCertificateErrors) IPC_MESSAGE_HANDLER(ViewHostMsg_GoToEntryAtOffset, OnGoToEntryAtOffset) IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateZoomLimits, OnUpdateZoomLimits) IPC_MESSAGE_HANDLER(ViewHostMsg_PageScaleFactorChanged, @@ -3185,12 +3181,12 @@ GetController().GetBrowserContext()); } -void WebContentsImpl::OnDidRunInsecureContent(const GURL& security_origin, - const GURL& target_url) { +void WebContentsImpl::OnDidRunInsecureContent( + const std::string& security_origin, const GURL& target_url) { LOG(WARNING) << security_origin << " ran insecure content from " << target_url.possibly_invalid_spec(); RecordAction(base::UserMetricsAction("SSL.RanInsecureContent")); - if (base::EndsWith(security_origin.spec(), kDotGoogleDotCom, + if (base::EndsWith(security_origin, kDotGoogleDotCom, base::CompareCase::INSENSITIVE_ASCII)) RecordAction(base::UserMetricsAction("SSL.RanInsecureContentGoogle")); controller_.ssl_manager()->DidRunInsecureContent(security_origin); @@ -3198,39 +3194,6 @@ GetController().GetBrowserContext()); } -void WebContentsImpl::OnDidDisplayContentWithCertificateErrors( - const GURL& url, - const std::string& security_info) { - SSLStatus ssl; - if (!DeserializeSecurityInfo(security_info, &ssl)) { - bad_message::ReceivedBadMessage( - GetRenderProcessHost(), - bad_message::WC_CONTENT_WITH_CERT_ERRORS_BAD_SECURITY_INFO); - return; - } - - displayed_insecure_content_ = true; - SSLManager::NotifySSLInternalStateChanged( - GetController().GetBrowserContext()); -} - -void WebContentsImpl::OnDidRunContentWithCertificateErrors( - const GURL& security_origin, - const GURL& url, - const std::string& security_info) { - SSLStatus ssl; - if (!DeserializeSecurityInfo(security_info, &ssl)) { - bad_message::ReceivedBadMessage( - GetRenderProcessHost(), - bad_message::WC_CONTENT_WITH_CERT_ERRORS_BAD_SECURITY_INFO); - return; - } - - controller_.ssl_manager()->DidRunInsecureContent(security_origin); - SSLManager::NotifySSLInternalStateChanged( - GetController().GetBrowserContext()); -} - void WebContentsImpl::OnDocumentLoadedInFrame() { if (!HasValidFrameSource()) return;
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index 016566e..213cc58 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -841,14 +841,8 @@ const std::string& mime_type, ResourceType resource_type); void OnDidDisplayInsecureContent(); - void OnDidRunInsecureContent(const GURL& security_origin, + void OnDidRunInsecureContent(const std::string& security_origin, const GURL& target_url); - void OnDidDisplayContentWithCertificateErrors( - const GURL& url, - const std::string& security_info); - void OnDidRunContentWithCertificateErrors(const GURL& security_origin, - const GURL& url, - const std::string& security_info); void OnDocumentLoadedInFrame(); void OnDidFinishLoad(const GURL& url); void OnGoToEntryAtOffset(int offset);
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc index cf466cc..07977ba 100644 --- a/content/child/child_thread_impl.cc +++ b/content/child/child_thread_impl.cc
@@ -414,6 +414,7 @@ IPC::Logging::GetInstance()->SetIPCSender(this); #endif + mojo_ipc_support_.reset(new IPC::ScopedIPCSupport(GetIOTaskRunner())); mojo_application_.reset(new MojoApplication(GetIOTaskRunner())); sync_message_filter_ = channel_->CreateSyncMessageFilter(); @@ -653,10 +654,8 @@ OnProcessBackgrounded) IPC_MESSAGE_HANDLER(MojoMsg_BindExternalMojoShellHandle, OnBindExternalMojoShellHandle) -#if defined(OS_WIN) IPC_MESSAGE_HANDLER(ChildProcessMsg_SetMojoParentPipeHandle, OnSetMojoParentPipeHandle) -#endif IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP()
diff --git a/content/child/child_thread_impl.h b/content/child/child_thread_impl.h index 09a58b8..9f4df7f 100644 --- a/content/child/child_thread_impl.h +++ b/content/child/child_thread_impl.h
@@ -235,6 +235,7 @@ void EnsureConnected(); + scoped_ptr<IPC::ScopedIPCSupport> mojo_ipc_support_; scoped_ptr<MojoApplication> mojo_application_; std::string channel_name_;
diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc index dbcff212..bea6020 100644 --- a/content/child/web_url_loader_impl.cc +++ b/content/child/web_url_loader_impl.cc
@@ -887,7 +887,6 @@ response->setTextEncodingName(WebString::fromUTF8(info.charset)); response->setExpectedContentLength(info.content_length); response->setSecurityInfo(info.security_info); - response->setHasMajorCertificateErrors(info.has_major_certificate_errors); response->setAppCacheID(info.appcache_id); response->setAppCacheManifestURL(info.appcache_manifest_url); response->setWasCached(!info.load_timing.request_start_time.is_null() &&
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h index 01d5fdf..36aebda 100644 --- a/content/common/frame_messages.h +++ b/content/common/frame_messages.h
@@ -1224,22 +1224,9 @@ // Sent when the renderer runs insecure content in a secure origin. IPC_MESSAGE_ROUTED2(FrameHostMsg_DidRunInsecureContent, - GURL /* security_origin */, + std::string /* security_origin */, GURL /* target URL */) -// Sent when the renderer displays content that was loaded with -// certificate errors. -IPC_MESSAGE_ROUTED2(FrameHostMsg_DidDisplayContentWithCertificateErrors, - GURL /* resource url */, - std::string /* serialized security info */) - -// Sent when the renderer runs content that was loaded with certificate -// errors. -IPC_MESSAGE_ROUTED3(FrameHostMsg_DidRunContentWithCertificateErrors, - GURL /* security_origin */, - GURL /* resource url */, - std::string /* serialized security info */) - // Response to FrameMsg_GetSavableResourceLinks. IPC_MESSAGE_ROUTED3(FrameHostMsg_SavableResourceLinksResponse, std::vector<GURL> /* savable resource links */,
diff --git a/content/common/resource_messages.h b/content/common/resource_messages.h index a1918ed..dc4bac4 100644 --- a/content/common/resource_messages.h +++ b/content/common/resource_messages.h
@@ -115,7 +115,6 @@ IPC_STRUCT_TRAITS_MEMBER(mime_type) IPC_STRUCT_TRAITS_MEMBER(charset) IPC_STRUCT_TRAITS_MEMBER(security_info) - IPC_STRUCT_TRAITS_MEMBER(has_major_certificate_errors) IPC_STRUCT_TRAITS_MEMBER(content_length) IPC_STRUCT_TRAITS_MEMBER(encoded_data_length) IPC_STRUCT_TRAITS_MEMBER(appcache_id)
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc index cc76f06c..9e803011 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc
@@ -175,7 +175,7 @@ ResourceContext* context, int render_process_id, int render_frame_id, - net::CookieOptions* options) { + const net::CookieOptions& options) { return true; }
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index d3d9f01..0f80710 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h
@@ -361,7 +361,7 @@ ResourceContext* context, int render_process_id, int render_frame_id, - net::CookieOptions* options); + const net::CookieOptions& options); // This is called on the IO thread. virtual bool AllowSaveLocalState(ResourceContext* context);
diff --git a/content/public/common/resource_response.cc b/content/public/common/resource_response.cc index 12773554..12f1dd7 100644 --- a/content/public/common/resource_response.cc +++ b/content/public/common/resource_response.cc
@@ -19,8 +19,6 @@ new_response->head.mime_type = head.mime_type; new_response->head.charset = head.charset; new_response->head.security_info = head.security_info; - new_response->head.has_major_certificate_errors = - head.has_major_certificate_errors; new_response->head.content_length = head.content_length; new_response->head.encoded_data_length = head.encoded_data_length; new_response->head.appcache_id = head.appcache_id;
diff --git a/content/public/common/resource_response_info.cc b/content/public/common/resource_response_info.cc index f05ee19..1d4e304 100644 --- a/content/public/common/resource_response_info.cc +++ b/content/public/common/resource_response_info.cc
@@ -10,8 +10,7 @@ namespace content { ResourceResponseInfo::ResourceResponseInfo() - : has_major_certificate_errors(false), - content_length(-1), + : content_length(-1), encoded_data_length(-1), appcache_id(kAppCacheNoCacheId), was_fetched_via_spdy(false), @@ -23,7 +22,8 @@ was_fallback_required_by_service_worker(false), response_type_via_service_worker( blink::WebServiceWorkerResponseTypeDefault), - is_using_lofi(false) {} + is_using_lofi(false) { +} ResourceResponseInfo::~ResourceResponseInfo() { }
diff --git a/content/public/common/resource_response_info.h b/content/public/common/resource_response_info.h index 8b81f6d..1a0f126 100644 --- a/content/public/common/resource_response_info.h +++ b/content/public/common/resource_response_info.h
@@ -50,9 +50,6 @@ // response. This may include information about the SSL connection used. std::string security_info; - // True if the resource was loaded in spite of certificate errors. - bool has_major_certificate_errors; - // Content length if available. -1 if not available int64 content_length;
diff --git a/content/renderer/DEPS b/content/renderer/DEPS index b070955..3a49854 100644 --- a/content/renderer/DEPS +++ b/content/renderer/DEPS
@@ -29,5 +29,8 @@ '.*_[a-z]*browsertest.*': [ "+content/public/browser", "+content/shell", + ], + "render_thread_impl_browsertest\.cc": [ + "+content/app/mojo/mojo_init.h", ], }
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 860e3d5..314fe7b 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -48,7 +48,6 @@ #include "content/common/savable_subframe.h" #include "content/common/service_worker/service_worker_types.h" #include "content/common/site_isolation_policy.h" -#include "content/common/ssl_status_serialization.h" #include "content/common/swapped_out_messages.h" #include "content/common/view_messages.h" #include "content/public/common/bindings_policy.h" @@ -568,38 +567,6 @@ void OnGotContentHandlerID(uint32_t content_handler_id) {} -bool IsContentWithCertificateErrorsRelevantToUI( - const blink::WebURL& url, - const blink::WebCString& security_info, - const blink::WebURL& main_resource_url, - const blink::WebCString& main_resource_security_info) { - content::SSLStatus ssl_status; - content::SSLStatus main_resource_ssl_status; - CHECK(DeserializeSecurityInfo(security_info, &ssl_status)); - CHECK(DeserializeSecurityInfo(main_resource_security_info, - &main_resource_ssl_status)); - - if (!GURL(main_resource_url).SchemeIsCryptographic()) - return false; - - // Do not handle subresource certificate errors if they are the same - // as errors that occured during the main page load. This compares - // most, but not all, fields of SSLStatus. For example, this check - // does not compare |content_status| because the navigation entry - // might have mixed content but also have the exact same SSL - // connection properties as the subresource, thereby making the - // subresource errors duplicative. - return (!url::Origin(GURL(url)) - .IsSameOriginWith(url::Origin(GURL(main_resource_url))) || - main_resource_ssl_status.security_style != - ssl_status.security_style || - main_resource_ssl_status.cert_id != ssl_status.cert_id || - main_resource_ssl_status.cert_status != ssl_status.cert_status || - main_resource_ssl_status.security_bits != ssl_status.security_bits || - main_resource_ssl_status.connection_status != - ssl_status.connection_status); -} - } // namespace // static @@ -3706,38 +3673,12 @@ const blink::WebSecurityOrigin& origin, const blink::WebURL& target) { Send(new FrameHostMsg_DidRunInsecureContent( - routing_id_, GURL(origin.toString().utf8()), target)); + routing_id_, origin.toString().utf8(), target)); GetContentClient()->renderer()->RecordRapporURL( "ContentSettings.MixedScript.RanMixedScript", GURL(origin.toString().utf8())); } -void RenderFrameImpl::didDisplayContentWithCertificateErrors( - const blink::WebURL& url, - const blink::WebCString& security_info, - const blink::WebURL& main_resource_url, - const blink::WebCString& main_resource_security_info) { - if (!IsContentWithCertificateErrorsRelevantToUI( - url, security_info, main_resource_url, main_resource_security_info)) { - return; - } - Send(new FrameHostMsg_DidDisplayContentWithCertificateErrors(routing_id_, url, - security_info)); -} - -void RenderFrameImpl::didRunContentWithCertificateErrors( - const blink::WebURL& url, - const blink::WebCString& security_info, - const blink::WebURL& main_resource_url, - const blink::WebCString& main_resource_security_info) { - if (!IsContentWithCertificateErrorsRelevantToUI( - url, security_info, main_resource_url, main_resource_security_info)) { - return; - } - Send(new FrameHostMsg_DidRunContentWithCertificateErrors( - routing_id_, GURL(main_resource_url).GetOrigin(), url, security_info)); -} - void RenderFrameImpl::didChangePerformanceTiming() { FOR_EACH_OBSERVER(RenderFrameObserver, observers_,
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index bae9b33..c357ff8 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -522,16 +522,6 @@ void didDisplayInsecureContent() override; void didRunInsecureContent(const blink::WebSecurityOrigin& origin, const blink::WebURL& target) override; - void didDisplayContentWithCertificateErrors( - const blink::WebURL& url, - const blink::WebCString& security_info, - const blink::WebURL& main_resource_url, - const blink::WebCString& main_resource_security_info) override; - void didRunContentWithCertificateErrors( - const blink::WebURL& url, - const blink::WebCString& security_info, - const blink::WebURL& main_resource_url, - const blink::WebCString& main_resource_security_info) override; void didChangePerformanceTiming() override; void didCreateScriptContext(blink::WebLocalFrame* frame, v8::Local<v8::Context> context,
diff --git a/content/renderer/render_thread_impl_browsertest.cc b/content/renderer/render_thread_impl_browsertest.cc index c31cc14..d814e56 100644 --- a/content/renderer/render_thread_impl_browsertest.cc +++ b/content/renderer/render_thread_impl_browsertest.cc
@@ -9,7 +9,8 @@ #include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" #include "base/thread_task_runner_handle.h" -#include "components/scheduler/renderer/renderer_scheduler.h" +#include "components/scheduler/renderer/renderer_scheduler.h" +#include "content/app/mojo/mojo_init.h" #include "content/common/in_process_child_thread_params.h" #include "content/common/resource_messages.h" #include "content/common/websocket_messages.h" @@ -173,6 +174,7 @@ scoped_ptr<scheduler::RendererScheduler> renderer_scheduler = scheduler::RendererScheduler::Create(); + InitializeMojo(); thread_ = new RenderThreadImplForTest( InProcessChildThreadParams(test_helper_->GetChannelId(), test_helper_->GetIOTaskRunner()),
diff --git a/content/shell/browser/shell_network_delegate.cc b/content/shell/browser/shell_network_delegate.cc index c4cd0da..db264ab 100644 --- a/content/shell/browser/shell_network_delegate.cc +++ b/content/shell/browser/shell_network_delegate.cc
@@ -5,6 +5,7 @@ #include "content/shell/browser/shell_network_delegate.h" #include "base/command_line.h" +#include "base/strings/string_util.h" #include "content/public/common/content_switches.h" #include "net/base/net_errors.h" #include "net/base/static_cookie_policy.h" @@ -112,4 +113,8 @@ switches::kEnableExperimentalWebPlatformFeatures); } +bool ShellNetworkDelegate::OnAreStrictSecureCookiesEnabled() const { + return OnAreExperimentalCookieFeaturesEnabled(); +} + } // namespace content
diff --git a/content/shell/browser/shell_network_delegate.h b/content/shell/browser/shell_network_delegate.h index cffc3b9f..cb8d656 100644 --- a/content/shell/browser/shell_network_delegate.h +++ b/content/shell/browser/shell_network_delegate.h
@@ -53,6 +53,7 @@ bool OnCanAccessFile(const net::URLRequest& request, const base::FilePath& path) const override; bool OnAreExperimentalCookieFeaturesEnabled() const override; + bool OnAreStrictSecureCookiesEnabled() const override; DISALLOW_COPY_AND_ASSIGN(ShellNetworkDelegate); };
diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java index 6e20600..b11244e0 100644 --- a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java +++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
@@ -186,10 +186,15 @@ ThreadUtils.runOnUiThread(new Runnable() { @Override public void run() { - ChromeBluetoothRemoteGattCharacteristic - chromeBluetoothRemoteGattCharacteristic = - mWrapperToChromeCharacteristicsMap.get(characteristic); - chromeBluetoothRemoteGattCharacteristic.onCharacteristicRead(status); + ChromeBluetoothRemoteGattCharacteristic chromeCharacteristic = + mWrapperToChromeCharacteristicsMap.get(characteristic); + if (chromeCharacteristic == null) { + // Android events arriving with no Chrome object is expected rarely: only + // when the event races object destruction. + Log.v(TAG, "onCharacteristicRead when chromeCharacteristic == null."); + } else { + chromeCharacteristic.onCharacteristicRead(status); + } } }); } @@ -201,10 +206,15 @@ ThreadUtils.runOnUiThread(new Runnable() { @Override public void run() { - ChromeBluetoothRemoteGattCharacteristic - chromeBluetoothRemoteGattCharacteristic = - mWrapperToChromeCharacteristicsMap.get(characteristic); - chromeBluetoothRemoteGattCharacteristic.onCharacteristicWrite(status); + ChromeBluetoothRemoteGattCharacteristic chromeCharacteristic = + mWrapperToChromeCharacteristicsMap.get(characteristic); + if (chromeCharacteristic == null) { + // Android events arriving with no Chrome object is expected rarely: only + // when the event races object destruction. + Log.v(TAG, "onCharacteristicWrite when chromeCharacteristic == null."); + } else { + chromeCharacteristic.onCharacteristicWrite(status); + } } }); }
diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java index dd0d2617..3b64681 100644 --- a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java +++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java
@@ -42,6 +42,7 @@ */ @CalledByNative private void onBluetoothRemoteGattCharacteristicAndroidDestruction() { + Log.v(TAG, "ChromeBluetoothRemoteGattCharacteristic Destroyed."); mNativeBluetoothRemoteGattCharacteristicAndroid = 0; mChromeBluetoothDevice.mWrapperToChromeCharacteristicsMap.remove(mCharacteristic); }
diff --git a/device/bluetooth/bluetooth_gatt_characteristic_unittest.cc b/device/bluetooth/bluetooth_gatt_characteristic_unittest.cc index 17e77e9..bbca500 100644 --- a/device/bluetooth/bluetooth_gatt_characteristic_unittest.cc +++ b/device/bluetooth/bluetooth_gatt_characteristic_unittest.cc
@@ -214,6 +214,42 @@ #endif // defined(OS_ANDROID) #if defined(OS_ANDROID) +// Tests ReadRemoteCharacteristic completing after Chrome objects are deleted. +TEST_F(BluetoothGattCharacteristicTest, ReadRemoteCharacteristic_AfterDeleted) { + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); + + characteristic1_->ReadRemoteCharacteristic( + GetReadValueCallback(Call::NOT_EXPECTED), + GetGattErrorCallback(Call::NOT_EXPECTED)); + + RememberCharacteristicForSubsequentAction(characteristic1_); + DeleteDevice(device_); + + std::vector<uint8_t> empty_vector; + SimulateGattCharacteristicRead(/* use remembered characteristic */ nullptr, + empty_vector); +} +#endif // defined(OS_ANDROID) + +#if defined(OS_ANDROID) +// Tests WriteRemoteCharacteristic completing after Chrome objects are deleted. +TEST_F(BluetoothGattCharacteristicTest, + WriteRemoteCharacteristic_AfterDeleted) { + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); + + std::vector<uint8_t> empty_vector; + characteristic1_->WriteRemoteCharacteristic( + empty_vector, GetCallback(Call::NOT_EXPECTED), + GetGattErrorCallback(Call::NOT_EXPECTED)); + + RememberCharacteristicForSubsequentAction(characteristic1_); + DeleteDevice(device_); + + SimulateGattCharacteristicWrite(/* use remembered characteristic */ nullptr); +} +#endif // defined(OS_ANDROID) + +#if defined(OS_ANDROID) // Tests ReadRemoteCharacteristic and GetValue with non-empty value buffer. TEST_F(BluetoothGattCharacteristicTest, ReadRemoteCharacteristic) { ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate());
diff --git a/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java b/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java index d01cc1e..e9485e58 100644 --- a/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java +++ b/device/bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java
@@ -428,6 +428,7 @@ final int mProperties; final UUID mUuid; byte[] mValue; + static FakeBluetoothGattCharacteristic sRememberedCharacteristic; public FakeBluetoothGattCharacteristic( FakeBluetoothGattService service, int instanceId, int properties, UUID uuid) { @@ -441,10 +442,23 @@ // Simulate a value being read from a characteristic. @CalledByNative("FakeBluetoothGattCharacteristic") + private static void rememberCharacteristic( + ChromeBluetoothRemoteGattCharacteristic chromeCharacteristic) { + sRememberedCharacteristic = + (FakeBluetoothGattCharacteristic) chromeCharacteristic.mCharacteristic; + } + + // Simulate a value being read from a characteristic. + @CalledByNative("FakeBluetoothGattCharacteristic") private static void valueRead(ChromeBluetoothRemoteGattCharacteristic chromeCharacteristic, int status, byte[] value) { - FakeBluetoothGattCharacteristic fakeCharacteristic = - (FakeBluetoothGattCharacteristic) chromeCharacteristic.mCharacteristic; + if (chromeCharacteristic == null && sRememberedCharacteristic == null) + throw new IllegalArgumentException( + "rememberCharacteristic wasn't called previously."); + + FakeBluetoothGattCharacteristic fakeCharacteristic = (chromeCharacteristic == null) + ? sRememberedCharacteristic + : (FakeBluetoothGattCharacteristic) chromeCharacteristic.mCharacteristic; fakeCharacteristic.mValue = value; fakeCharacteristic.mService.mDevice.mGattCallback.onCharacteristicRead( @@ -455,8 +469,13 @@ @CalledByNative("FakeBluetoothGattCharacteristic") private static void valueWrite( ChromeBluetoothRemoteGattCharacteristic chromeCharacteristic, int status) { - FakeBluetoothGattCharacteristic fakeCharacteristic = - (FakeBluetoothGattCharacteristic) chromeCharacteristic.mCharacteristic; + if (chromeCharacteristic == null && sRememberedCharacteristic == null) + throw new IllegalArgumentException( + "rememberCharacteristic wasn't called previously."); + + FakeBluetoothGattCharacteristic fakeCharacteristic = (chromeCharacteristic == null) + ? sRememberedCharacteristic + : (FakeBluetoothGattCharacteristic) chromeCharacteristic.mCharacteristic; fakeCharacteristic.mService.mDevice.mGattCallback.onCharacteristicWrite( fakeCharacteristic, status);
diff --git a/device/bluetooth/test/bluetooth_test.h b/device/bluetooth/test/bluetooth_test.h index a0066e9..3ddfec9 100644 --- a/device/bluetooth/test/bluetooth_test.h +++ b/device/bluetooth/test/bluetooth_test.h
@@ -118,6 +118,14 @@ const std::string& uuid, int properties) {} + // Remembers |characteristic|'s platform specific object to be used in a + // subsequent call to methods such as SimulateGattCharacteristicRead that + // accept a nullptr value to select this remembered characteristic. This + // enables tests where the platform attempts to reference characteristic + // objects after the Chrome objects have been deleted, e.g. with DeleteDevice. + virtual void RememberCharacteristicForSubsequentAction( + BluetoothGattCharacteristic* characteristic) {} + // Simulates a Characteristic Set Notify success. virtual void SimulateGattNotifySessionStarted( BluetoothGattCharacteristic* characteristic) {} @@ -128,6 +136,8 @@ BluetoothGattCharacteristic* characteristic) {} // Simulates a Characteristic Read operation succeeding, returning |value|. + // If |characteristic| is null, acts upon the characteristic provided to + // RememberCharacteristicForSubsequentAction. virtual void SimulateGattCharacteristicRead( BluetoothGattCharacteristic* characteristic, const std::vector<uint8>& value) {} @@ -143,6 +153,8 @@ BluetoothGattCharacteristic* characteristic) {} // Simulates a Characteristic Write operation succeeding, returning |value|. + // If |characteristic| is null, acts upon the characteristic provided to + // RememberCharacteristicForSubsequentAction. virtual void SimulateGattCharacteristicWrite( BluetoothGattCharacteristic* characteristic) {} @@ -156,7 +168,7 @@ virtual void SimulateGattCharacteristicWriteWillFailSynchronouslyOnce( BluetoothGattCharacteristic* characteristic) {} - // Remove the device from the adapter and delete it. + // Removes the device from the adapter and deletes it. virtual void DeleteDevice(BluetoothDevice* device); // Callbacks that increment |callback_count_|, |error_callback_count_|:
diff --git a/device/bluetooth/test/bluetooth_test_android.cc b/device/bluetooth/test/bluetooth_test_android.cc index bb55650..d822a7c 100644 --- a/device/bluetooth/test/bluetooth_test_android.cc +++ b/device/bluetooth/test/bluetooth_test_android.cc
@@ -163,6 +163,16 @@ base::android::ConvertUTF8ToJavaString(env, uuid).obj(), properties); } +void BluetoothTestAndroid::RememberCharacteristicForSubsequentAction( + BluetoothGattCharacteristic* characteristic) { + BluetoothRemoteGattCharacteristicAndroid* characteristic_android = + static_cast<BluetoothRemoteGattCharacteristicAndroid*>(characteristic); + + Java_FakeBluetoothGattCharacteristic_rememberCharacteristic( + base::android::AttachCurrentThread(), + characteristic_android->GetJavaObject().obj()); +} + void BluetoothTestAndroid::SimulateGattNotifySessionStarted( BluetoothGattCharacteristic* characteristic) { // Android doesn't provide any sort of callback for when notifications have @@ -190,7 +200,9 @@ JNIEnv* env = base::android::AttachCurrentThread(); Java_FakeBluetoothGattCharacteristic_valueRead( - env, characteristic_android->GetJavaObject().obj(), + env, + characteristic_android ? characteristic_android->GetJavaObject().obj() + : nullptr, 0, // android.bluetooth.BluetoothGatt.GATT_SUCCESS base::android::ToJavaByteArray(env, value).obj()); } @@ -226,7 +238,8 @@ static_cast<BluetoothRemoteGattCharacteristicAndroid*>(characteristic); Java_FakeBluetoothGattCharacteristic_valueWrite( base::android::AttachCurrentThread(), - characteristic_android->GetJavaObject().obj(), + characteristic_android ? characteristic_android->GetJavaObject().obj() + : nullptr, 0); // android.bluetooth.BluetoothGatt.GATT_SUCCESS }
diff --git a/device/bluetooth/test/bluetooth_test_android.h b/device/bluetooth/test/bluetooth_test_android.h index e4c1c82a..664863a3 100644 --- a/device/bluetooth/test/bluetooth_test_android.h +++ b/device/bluetooth/test/bluetooth_test_android.h
@@ -39,6 +39,8 @@ void SimulateGattCharacteristic(BluetoothGattService* service, const std::string& uuid, int properties) override; + void RememberCharacteristicForSubsequentAction( + BluetoothGattCharacteristic* characteristic) override; void SimulateGattNotifySessionStarted( BluetoothGattCharacteristic* characteristic) override; void SimulateGattCharacteristicSetNotifyWillFailSynchronouslyOnce(
diff --git a/mojo/edk/embedder/embedder.cc b/mojo/edk/embedder/embedder.cc index eb572c57..35e55ba 100644 --- a/mojo/edk/embedder/embedder.cc +++ b/mojo/edk/embedder/embedder.cc
@@ -65,15 +65,9 @@ } ScopedPlatformHandle ChildProcessLaunched(base::ProcessHandle child_process) { -#if defined(OS_WIN) PlatformChannelPair token_channel; new ChildBrokerHost(child_process, token_channel.PassServerHandle()); return token_channel.PassClientHandle(); -#else - // TODO(jam): create this for POSIX. Need to implement channel reading first - // so we don't leak handles. - return ScopedPlatformHandle(); -#endif } void ChildProcessLaunched(base::ProcessHandle child_process, @@ -165,9 +159,11 @@ ScopedMessagePipeHandle CreateMessagePipe( ScopedPlatformHandle platform_handle) { + MojoCreateMessagePipeOptions options = { + static_cast<uint32_t>(sizeof(MojoCreateMessagePipeOptions)), + MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE}; scoped_refptr<MessagePipeDispatcher> dispatcher = - MessagePipeDispatcher::Create( - MessagePipeDispatcher::kDefaultCreateOptions); + MessagePipeDispatcher::Create(options); ScopedMessagePipeHandle rv( MessagePipeHandle(internal::g_core->AddDispatcher(dispatcher)));
diff --git a/mojo/edk/embedder/embedder_unittest.cc b/mojo/edk/embedder/embedder_unittest.cc index 60a2b801..4f6493f 100644 --- a/mojo/edk/embedder/embedder_unittest.cc +++ b/mojo/edk/embedder/embedder_unittest.cc
@@ -34,14 +34,7 @@ MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED; -class EmbedderTest : public test::MojoSystemTest { - public: - EmbedderTest() {} - ~EmbedderTest() override {} - - private: - MOJO_DISALLOW_COPY_AND_ASSIGN(EmbedderTest); -}; +typedef testing::Test EmbedderTest; TEST_F(EmbedderTest, ChannelBasic) { MojoHandle server_mp, client_mp; @@ -85,8 +78,11 @@ MojoCreateMessagePipe(nullptr, &server_mp, &client_mp)); MojoHandle server_mp2, client_mp2; + MojoCreateMessagePipeOptions options; + options.struct_size = sizeof(MojoCreateMessagePipeOptions); + options.flags = MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE; ASSERT_EQ(MOJO_RESULT_OK, - MojoCreateMessagePipe(nullptr, &server_mp2, &client_mp2)); + MojoCreateMessagePipe(&options, &server_mp2, &client_mp2)); // Write to server2 and wait for client2 to be readable before sending it. // client2's MessagePipeDispatcher will have the message below in its @@ -165,9 +161,12 @@ ASSERT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &server_mp, &client_mp)); + MojoCreateMessagePipeOptions options; + options.struct_size = sizeof(MojoCreateMessagePipeOptions); + options.flags = MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE; MojoHandle server_mp2, client_mp2; ASSERT_EQ(MOJO_RESULT_OK, - MojoCreateMessagePipe(nullptr, &server_mp2, &client_mp2)); + MojoCreateMessagePipe(&options, &server_mp2, &client_mp2)); static const size_t kNumMessages = 1001; for (size_t i = 0; i < kNumMessages; i++) { @@ -465,114 +464,108 @@ } MOJO_MULTIPROCESS_TEST_CHILD_TEST(MultiprocessChannelsClient) { - base::MessageLoop message_loop; ScopedPlatformHandle client_platform_handle = test::MultiprocessTestHelper::client_platform_handle.Pass(); EXPECT_TRUE(client_platform_handle.is_valid()); - base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart); + MojoHandle client_mp = CreateMessagePipe( + client_platform_handle.Pass()).release().value(); - { - test::ScopedIPCSupport ipc_support(test_io_thread.task_runner()); - MojoHandle client_mp = CreateMessagePipe( - client_platform_handle.Pass()).release().value(); + // 1. Read the first message from |client_mp|. + MojoHandleSignalsState state; + ASSERT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, &state)); + ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals); + ASSERT_EQ(kSignalAll, state.satisfiable_signals); - // 1. Read the first message from |client_mp|. - MojoHandleSignalsState state; - ASSERT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE, &state)); - ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals); - ASSERT_EQ(kSignalAll, state.satisfiable_signals); + char buffer[1000] = {}; + uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer)); + ASSERT_EQ(MOJO_RESULT_OK, + MojoReadMessage(client_mp, buffer, &num_bytes, nullptr, nullptr, + MOJO_READ_MESSAGE_FLAG_NONE)); + const char kHello[] = "hello"; + ASSERT_EQ(sizeof(kHello), num_bytes); + EXPECT_STREQ(kHello, buffer); - char buffer[1000] = {}; - uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer)); - ASSERT_EQ(MOJO_RESULT_OK, - MojoReadMessage(client_mp, buffer, &num_bytes, nullptr, nullptr, - MOJO_READ_MESSAGE_FLAG_NONE)); - const char kHello[] = "hello"; - ASSERT_EQ(sizeof(kHello), num_bytes); - EXPECT_STREQ(kHello, buffer); + // 2. Write a message to |client_mp| (attaching nothing). + const char kWorld[] = "world!"; + ASSERT_EQ(MOJO_RESULT_OK, + MojoWriteMessage(client_mp, kWorld, + static_cast<uint32_t>(sizeof(kWorld)), nullptr, + 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); - // 2. Write a message to |client_mp| (attaching nothing). - const char kWorld[] = "world!"; - ASSERT_EQ(MOJO_RESULT_OK, - MojoWriteMessage(client_mp, kWorld, - static_cast<uint32_t>(sizeof(kWorld)), nullptr, - 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); + // 4. Read a message from |client_mp|, which should have |mp1| attached. + ASSERT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, &state)); + // The other end of the handle may or may not be closed at this point, so we + // can't test MOJO_HANDLE_SIGNAL_WRITABLE or MOJO_HANDLE_SIGNAL_PEER_CLOSED. + ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, + state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); + ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, + state.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE); + // TODO(vtl): If the scope were to end here (and |client_mp| closed), we'd + // die (again due to |Channel::HandleLocalError()|). + memset(buffer, 0, sizeof(buffer)); + num_bytes = static_cast<uint32_t>(sizeof(buffer)); + MojoHandle mp1 = MOJO_HANDLE_INVALID; + uint32_t num_handles = 1; + ASSERT_EQ(MOJO_RESULT_OK, + MojoReadMessage(client_mp, buffer, &num_bytes, &mp1, &num_handles, + MOJO_READ_MESSAGE_FLAG_NONE)); + const char kBar[] = "Bar"; + ASSERT_EQ(sizeof(kBar), num_bytes); + EXPECT_STREQ(kBar, buffer); + ASSERT_EQ(1u, num_handles); + EXPECT_NE(mp1, MOJO_HANDLE_INVALID); + // TODO(vtl): If the scope were to end here (and the two handles closed), + // we'd die due to |Channel::RunRemoteMessagePipeEndpoint()| not handling + // write errors (assuming the parent had closed the pipe). - // 4. Read a message from |client_mp|, which should have |mp1| attached. - ASSERT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE, &state)); - // The other end of the handle may or may not be closed at this point, so we - // can't test MOJO_HANDLE_SIGNAL_WRITABLE or MOJO_HANDLE_SIGNAL_PEER_CLOSED. - ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, - state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); - ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, - state.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE); - // TODO(vtl): If the scope were to end here (and |client_mp| closed), we'd - // die (again due to |Channel::HandleLocalError()|). - memset(buffer, 0, sizeof(buffer)); - num_bytes = static_cast<uint32_t>(sizeof(buffer)); - MojoHandle mp1 = MOJO_HANDLE_INVALID; - uint32_t num_handles = 1; - ASSERT_EQ(MOJO_RESULT_OK, - MojoReadMessage(client_mp, buffer, &num_bytes, &mp1, &num_handles, - MOJO_READ_MESSAGE_FLAG_NONE)); - const char kBar[] = "Bar"; - ASSERT_EQ(sizeof(kBar), num_bytes); - EXPECT_STREQ(kBar, buffer); - ASSERT_EQ(1u, num_handles); - EXPECT_NE(mp1, MOJO_HANDLE_INVALID); - // TODO(vtl): If the scope were to end here (and the two handles closed), - // we'd die due to |Channel::RunRemoteMessagePipeEndpoint()| not handling - // write errors (assuming the parent had closed the pipe). + // 6. Close |client_mp|. + ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp)); - // 6. Close |client_mp|. - ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp)); + // Create a new message pipe (endpoints |mp2| and |mp3|). + MojoHandle mp2, mp3; + ASSERT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &mp2, &mp3)); - // Create a new message pipe (endpoints |mp2| and |mp3|). - MojoHandle mp2, mp3; - ASSERT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &mp2, &mp3)); + // 7. Write a message to |mp3|. + const char kBaz[] = "baz"; + ASSERT_EQ(MOJO_RESULT_OK, + MojoWriteMessage(mp3, kBaz, static_cast<uint32_t>(sizeof(kBaz)), + nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); - // 7. Write a message to |mp3|. - const char kBaz[] = "baz"; - ASSERT_EQ(MOJO_RESULT_OK, - MojoWriteMessage(mp3, kBaz, static_cast<uint32_t>(sizeof(kBaz)), - nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); + // 8. Close |mp3|. + ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp3)); - // 8. Close |mp3|. - ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp3)); + // 9. Write a message to |mp1|, attaching |mp2|. + const char kQuux[] = "quux"; + ASSERT_EQ(MOJO_RESULT_OK, + MojoWriteMessage(mp1, kQuux, static_cast<uint32_t>(sizeof(kQuux)), + &mp2, 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); + mp2 = MOJO_HANDLE_INVALID; - // 9. Write a message to |mp1|, attaching |mp2|. - const char kQuux[] = "quux"; - ASSERT_EQ(MOJO_RESULT_OK, - MojoWriteMessage(mp1, kQuux, static_cast<uint32_t>(sizeof(kQuux)), - &mp2, 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); - mp2 = MOJO_HANDLE_INVALID; + // 3. Read a message from |mp1|. + ASSERT_EQ(MOJO_RESULT_OK, MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, &state)); + ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals); + ASSERT_EQ(kSignalAll, state.satisfiable_signals); - // 3. Read a message from |mp1|. - ASSERT_EQ(MOJO_RESULT_OK, MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE, &state)); - ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals); - ASSERT_EQ(kSignalAll, state.satisfiable_signals); + memset(buffer, 0, sizeof(buffer)); + num_bytes = static_cast<uint32_t>(sizeof(buffer)); + ASSERT_EQ(MOJO_RESULT_OK, + MojoReadMessage(mp1, buffer, &num_bytes, nullptr, nullptr, + MOJO_READ_MESSAGE_FLAG_NONE)); + const char kFoo[] = "FOO"; + ASSERT_EQ(sizeof(kFoo), num_bytes); + EXPECT_STREQ(kFoo, buffer); - memset(buffer, 0, sizeof(buffer)); - num_bytes = static_cast<uint32_t>(sizeof(buffer)); - ASSERT_EQ(MOJO_RESULT_OK, - MojoReadMessage(mp1, buffer, &num_bytes, nullptr, nullptr, - MOJO_READ_MESSAGE_FLAG_NONE)); - const char kFoo[] = "FOO"; - ASSERT_EQ(sizeof(kFoo), num_bytes); - EXPECT_STREQ(kFoo, buffer); - - // 11. Wait on |mp1| (which should eventually fail) and then close it. - ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE, &state)); - ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals); - ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfiable_signals); - ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp1)); - } + // 11. Wait on |mp1| (which should eventually fail) and then close it. + ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, &state)); + ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals); + ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfiable_signals); + ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp1)); } // TODO(vtl): Test immediate write & close.
diff --git a/mojo/edk/system/BUILD.gn b/mojo/edk/system/BUILD.gn index fe113d2..54e3e3e 100644 --- a/mojo/edk/system/BUILD.gn +++ b/mojo/edk/system/BUILD.gn
@@ -69,6 +69,8 @@ "raw_channel.h", "raw_channel_posix.cc", "raw_channel_win.cc", + "routed_raw_channel.cc", + "routed_raw_channel.h", "shared_buffer_dispatcher.cc", "shared_buffer_dispatcher.h", "simple_dispatcher.cc",
diff --git a/mojo/edk/system/broker.h b/mojo/edk/system/broker.h index ce4c9565..f78fff7 100644 --- a/mojo/edk/system/broker.h +++ b/mojo/edk/system/broker.h
@@ -6,23 +6,26 @@ #define MOJO_EDK_SYSTEM_BROKER_H_ #include <stdint.h> -#include <vector> #include "mojo/edk/embedder/scoped_platform_handle.h" namespace mojo { namespace edk { +class MessagePipeDispatcher; +class RawChannel; // An interface for communicating to a central "broker" process from each -// process using the EDK. This is needed because child processes are sandboxed. -// It is safe to call from any thread. +// process using the EDK. It serves two purposes: +// 1) Windows only: brokering to help child processes as they can't create +// named pipes or duplicate handles. +// 2) All platforms: support multiplexed messages pipes. + class MOJO_SYSTEM_IMPL_EXPORT Broker { public: virtual ~Broker() {} #if defined(OS_WIN) - // All these methods are needed because sandboxed Windows processes can't - // create named pipes or duplicate handles. + // It is safe to call these three methods from any thread. // Create a PlatformChannelPair. virtual void CreatePlatformChannelPair(ScopedPlatformHandle* server, @@ -40,6 +43,20 @@ size_t count, PlatformHandle* handles) = 0; #endif + + // Multiplexing related methods. They are called from the IO thread only. + + // Called by |message_pipe| so that it receives messages for the given + // globally unique |pipe_id|. When the connection is established, + // MessagePipeDispatcher::GotNonTransferableChannel is called with the channel + // that it can use for sending messages. + virtual void ConnectMessagePipe(uint64_t pipe_id, + MessagePipeDispatcher* message_pipe) = 0; + + // Called by |message_pipe| when it's closing so that its route can be + // unregistered. + virtual void CloseMessagePipe(uint64_t pipe_id, + MessagePipeDispatcher* message_pipe) = 0; }; } // namespace edk
diff --git a/mojo/edk/system/broker_messages.h b/mojo/edk/system/broker_messages.h index 351cbe6..7d8946d 100644 --- a/mojo/edk/system/broker_messages.h +++ b/mojo/edk/system/broker_messages.h
@@ -8,6 +8,7 @@ #include <stdint.h> #include "base/compiler_specific.h" +#include "base/process/process_handle.h" namespace mojo { namespace edk { @@ -15,7 +16,11 @@ // This header defines the message format between ChildBroker and // ChildBrokerHost. -enum MessageId { +#if defined(OS_WIN) +// Windows only messages needed because sandboxed child processes need the +// parent's help. They are sent synchronously from child to parent and each have +// a response. They are sent over a raw pipe. +enum WindowsSandboxMessages { // The reply is two HANDLEs. CREATE_PLATFORM_CHANNEL_PAIR = 0, // The reply is tokens of the same count of passed in handles. @@ -28,17 +33,48 @@ struct BrokerMessage { uint32_t size; - MessageId id; + WindowsSandboxMessages id; // Data, if any, follows. union { -#if defined(OS_WIN) HANDLE handles[1]; // If HANDLE_TO_TOKEN. uint64_t tokens[1]; // If TOKEN_TO_HANDLE. -#endif }; }; -const int kBrokerMessageHeaderSize = sizeof(uint32_t) + sizeof(MessageId); +const int kBrokerMessageHeaderSize = + sizeof(uint32_t) + sizeof(WindowsSandboxMessages); + +#endif + +// Multiplexing related messages. They are all asynchronous messages. +// They are sent over RawChannel. +enum MultiplexMessages { + // Messages from child to parent. + CONNECT_MESSAGE_PIPE = 0, + CANCEL_CONNECT_MESSAGE_PIPE, + + // Messages from parent to child. + CONNECT_TO_PROCESS, + PEER_PIPE_CONNECTED, +}; + +struct ConnectMessagePipeMessage { + // CONNECT_MESSAGE_PIPE or CANCEL_CONNECT_MESSAGE_PIPE + MultiplexMessages type; + uint64_t pipe_id; +}; + +struct ConnectToProcessMessage { + MultiplexMessages type; // CONNECT_TO_PROCESS + base::ProcessId process_id; + // Also has an attached platform handle. +}; + +struct PeerPipeConnectedMessage { + MultiplexMessages type; // PEER_PIPE_CONNECTED + uint64_t pipe_id; + base::ProcessId process_id; +}; } // namespace edk } // namespace mojo
diff --git a/mojo/edk/system/broker_state.cc b/mojo/edk/system/broker_state.cc index 6eb4ae9..b875b31 100644 --- a/mojo/edk/system/broker_state.cc +++ b/mojo/edk/system/broker_state.cc
@@ -4,9 +4,13 @@ #include "mojo/edk/system/broker_state.h" +#include "base/bind.h" #include "base/rand_util.h" #include "mojo/edk/embedder/embedder_internal.h" #include "mojo/edk/embedder/platform_channel_pair.h" +#include "mojo/edk/system/child_broker_host.h" +#include "mojo/edk/system/message_pipe_dispatcher.h" +#include "mojo/edk/system/routed_raw_channel.h" namespace mojo { namespace edk { @@ -28,7 +32,7 @@ const PlatformHandle* platform_handles, size_t count, uint64_t* tokens) { - base::AutoLock auto_locker(lock_); + base::AutoLock auto_locker(token_map_lock_); for (size_t i = 0; i < count; ++i) { if (platform_handles[i].is_valid()) { uint64_t token; @@ -47,7 +51,7 @@ void BrokerState::TokenToHandle(const uint64_t* tokens, size_t count, PlatformHandle* handles) { - base::AutoLock auto_locker(lock_); + base::AutoLock auto_locker(token_map_lock_); for (size_t i = 0; i < count; ++i) { auto it = token_map_.find(tokens[i]); if (it == token_map_.end()) { @@ -60,9 +64,155 @@ } #endif -BrokerState::BrokerState() : broker_thread_("Mojo Broker Thread") { - base::Thread::Options options(base::MessageLoop::TYPE_IO, 0); - broker_thread_.StartWithOptions(options); +void BrokerState::ConnectMessagePipe(uint64_t pipe_id, + MessagePipeDispatcher* message_pipe) { + DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); + base::AutoLock auto_lock(lock_); + if (pending_connects_.find(pipe_id) != pending_connects_.end()) { + // Both ends of the message pipe are in this process. + if (!in_process_pipes_channel1_) { + PlatformChannelPair channel_pair; + in_process_pipes_channel1_ = new RoutedRawChannel( + channel_pair.PassServerHandle(), + base::Bind(&BrokerState::ChannelDestructed, base::Unretained(this))); + in_process_pipes_channel2_ = new RoutedRawChannel( + channel_pair.PassClientHandle(), + base::Bind(&BrokerState::ChannelDestructed, base::Unretained(this))); + } + + connected_pipes_[pending_connects_[pipe_id]] = in_process_pipes_channel1_; + connected_pipes_[message_pipe] = in_process_pipes_channel2_; + in_process_pipes_channel1_->AddRoute(pipe_id, pending_connects_[pipe_id]); + in_process_pipes_channel2_->AddRoute(pipe_id, message_pipe); + pending_connects_[pipe_id]->GotNonTransferableChannel( + in_process_pipes_channel1_->channel()); + message_pipe->GotNonTransferableChannel( + in_process_pipes_channel2_->channel()); + + pending_connects_.erase(pipe_id); + return; + } + + if (pending_child_connects_.find(pipe_id) != pending_child_connects_.end()) { + // A child process has already tried to connect. + EnsureProcessesConnected(base::GetCurrentProcId(), + pending_child_connects_[pipe_id]->GetProcessId()); + pending_child_connects_[pipe_id]->ConnectMessagePipe( + pipe_id, base::GetCurrentProcId()); + base::ProcessId peer_pid = pending_child_connects_[pipe_id]->GetProcessId(); + pending_child_connects_.erase(pipe_id); + connected_pipes_[message_pipe] = child_channels_[peer_pid]; + child_channels_[peer_pid]->AddRoute(pipe_id, message_pipe); + message_pipe->GotNonTransferableChannel( + child_channels_[peer_pid]->channel()); + return; + } + + pending_connects_[pipe_id] = message_pipe; +} + +void BrokerState::CloseMessagePipe(uint64_t pipe_id, + MessagePipeDispatcher* message_pipe) { + DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); + base::AutoLock auto_lock(lock_); + + CHECK(connected_pipes_.find(message_pipe) != connected_pipes_.end()); + connected_pipes_[message_pipe]->RemoveRoute(pipe_id, message_pipe); + connected_pipes_.erase(message_pipe); +} + +void BrokerState::ChildBrokerHostCreated(ChildBrokerHost* child_broker_host) { + base::AutoLock auto_lock(lock_); + CHECK(child_processes_.find(child_broker_host->GetProcessId()) == + child_processes_.end()); + child_processes_[child_broker_host->GetProcessId()] = child_broker_host; +} + +void BrokerState::ChildBrokerHostDestructed( + ChildBrokerHost* child_broker_host) { + DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); + base::AutoLock auto_lock(lock_); + + for (auto it = pending_child_connects_.begin(); + it != pending_child_connects_.end();) { + if (it->second == child_broker_host) { + // Since we can't do it = pending_child_connects_.erase(it); until + // hash_map uses unordered_map on posix. + auto cur = it++; + pending_child_connects_.erase(cur); + } else { + it++; + } + } + + base::ProcessId pid = child_broker_host->GetProcessId(); + for (auto it = connected_processes_.begin(); + it != connected_processes_.end();) { + if ((*it).first == pid || (*it).second == pid) { + // Since we can't do it = pending_child_connects_.erase(it); until + // hash_map uses unordered_map on posix. + auto cur = it++; + connected_processes_.erase(cur); + } else { + it++; + } + } + + CHECK(child_processes_.find(pid) != child_processes_.end()); + child_processes_.erase(pid); +} + +void BrokerState::HandleConnectMessagePipe(ChildBrokerHost* pipe_process, + uint64_t pipe_id) { + DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); + base::AutoLock auto_lock(lock_); + if (pending_child_connects_.find(pipe_id) != pending_child_connects_.end()) { + // Another child process is waiting to connect to the given pipe. + ChildBrokerHost* pending_pipe_process = pending_child_connects_[pipe_id]; + EnsureProcessesConnected(pipe_process->GetProcessId(), + pending_pipe_process->GetProcessId()); + pending_pipe_process->ConnectMessagePipe( + pipe_id, pipe_process->GetProcessId()); + pipe_process->ConnectMessagePipe( + pipe_id, pending_pipe_process->GetProcessId()); + pending_child_connects_.erase(pipe_id); + return; + } + + if (pending_connects_.find(pipe_id) != pending_connects_.end()) { + // This parent process is the other side of the given pipe. + EnsureProcessesConnected(base::GetCurrentProcId(), + pipe_process->GetProcessId()); + MessagePipeDispatcher* pending_pipe = pending_connects_[pipe_id]; + connected_pipes_[pending_pipe] = + child_channels_[pipe_process->GetProcessId()]; + child_channels_[pipe_process->GetProcessId()]->AddRoute( + pipe_id, pending_pipe); + pending_pipe->GotNonTransferableChannel( + child_channels_[pipe_process->GetProcessId()]->channel()); + pipe_process->ConnectMessagePipe( + pipe_id, base::GetCurrentProcId()); + pending_connects_.erase(pipe_id); + return; + } + + // This is the first connection request for pipe_id to reach the parent. + pending_child_connects_[pipe_id] = pipe_process; +} + +void BrokerState::HandleCancelConnectMessagePipe(uint64_t pipe_id) { + DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); + base::AutoLock auto_lock(lock_); + if (pending_child_connects_.find(pipe_id) == pending_child_connects_.end()) { + NOTREACHED() << "Can't find entry for pipe_id " << pipe_id; + } else { + pending_child_connects_.erase(pipe_id); + } +} + +BrokerState::BrokerState() + : in_process_pipes_channel1_(nullptr), + in_process_pipes_channel2_(nullptr) { DCHECK(!internal::g_broker); internal::g_broker = this; } @@ -70,5 +220,49 @@ BrokerState::~BrokerState() { } +void BrokerState::EnsureProcessesConnected(base::ProcessId pid1, + base::ProcessId pid2) { + DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); + lock_.AssertAcquired(); + CHECK_NE(pid1, pid2); + CHECK_NE(pid2, base::GetCurrentProcId()); + std::pair<base::ProcessId, base::ProcessId> processes; + processes.first = std::min(pid1, pid2); + processes.second = std::max(pid1, pid2); + if (connected_processes_.find(processes) != connected_processes_.end()) + return; + + connected_processes_.insert(processes); + PlatformChannelPair channel_pair; + if (pid1 == base::GetCurrentProcId()) { + CHECK(child_channels_.find(pid2) == child_channels_.end()); + CHECK(child_processes_.find(pid2) != child_processes_.end()); + child_channels_[pid2] = new RoutedRawChannel( + channel_pair.PassServerHandle(), + base::Bind(&BrokerState::ChannelDestructed, base::Unretained(this))); + child_processes_[pid2]->ConnectToProcess(base::GetCurrentProcId(), + channel_pair.PassClientHandle()); + return; + } + + CHECK(child_processes_.find(pid1) != child_processes_.end()); + CHECK(child_processes_.find(pid2) != child_processes_.end()); + child_processes_[pid1]->ConnectToProcess(pid2, + channel_pair.PassServerHandle()); + child_processes_[pid2]->ConnectToProcess(pid1, + channel_pair.PassClientHandle()); +} + +void BrokerState::ChannelDestructed(RoutedRawChannel* channel) { + DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); + base::AutoLock auto_lock(lock_); + for (auto it : child_channels_) { + if (it.second == channel) { + child_channels_.erase(it.first); + break; + } + } +} + } // namespace edk } // namespace mojo
diff --git a/mojo/edk/system/broker_state.h b/mojo/edk/system/broker_state.h index cf982c7..29f3ffe 100644 --- a/mojo/edk/system/broker_state.h +++ b/mojo/edk/system/broker_state.h
@@ -7,15 +7,18 @@ #include "base/compiler_specific.h" #include "base/containers/hash_tables.h" +#include "base/macros.h" #include "base/memory/singleton.h" +#include "base/process/process_handle.h" #include "base/synchronization/lock.h" -#include "base/threading/thread.h" #include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/edk/system/broker.h" #include "mojo/edk/system/system_impl_export.h" namespace mojo { namespace edk { +class ChildBrokerHost; +class RoutedRawChannel; // Common broker state that has to live in a parent process. There is one // instance of this class in the parent process. This class implements the @@ -24,7 +27,7 @@ public: static BrokerState* GetInstance(); - // Broker implementation. + // Broker implementation: #if defined(OS_WIN) void CreatePlatformChannelPair(ScopedPlatformHandle* server, ScopedPlatformHandle* client) override; @@ -35,10 +38,20 @@ size_t count, PlatformHandle* handles) override; #endif + void ConnectMessagePipe(uint64_t pipe_id, + MessagePipeDispatcher* message_pipe) override; + void CloseMessagePipe(uint64_t pipe_id, + MessagePipeDispatcher* message_pipe) override; - scoped_refptr<base::TaskRunner> broker_thread() { - return broker_thread_.task_runner(); - } + // Called by ChildBrokerHost on construction and destruction. + void ChildBrokerHostCreated(ChildBrokerHost* child_broker_host); + void ChildBrokerHostDestructed(ChildBrokerHost* child_broker_host); + + // These are called by ChildBrokerHost as they dispatch IPCs from ChildBroker. + // They are called on the IO thread. + void HandleConnectMessagePipe(ChildBrokerHost* pipe_process, + uint64_t pipe_id); + void HandleCancelConnectMessagePipe(uint64_t pipe_id); private: friend struct base::DefaultSingletonTraits<BrokerState>; @@ -46,20 +59,58 @@ BrokerState(); ~BrokerState() override; - // A separate thread to handle sync IPCs from child processes for exchanging - // platform handles with tokens. We use a separate thread because latency is - // very sensitive (since any time a pipe is created or sent, a child process - // makes a sync call to this class). - base::Thread broker_thread_; + // Checks if there's a direct channel between the two processes, and if not + // creates one and tells them about it. + // If one of the processes is the current one, it should be pid1. + // Called on the IO thread. + void EnsureProcessesConnected(base::ProcessId pid1, base::ProcessId pid2); + + // Callback when a RoutedRawChannel is destroyed for cleanup. + // Called on the IO thread. + void ChannelDestructed(RoutedRawChannel* channel); #if defined(OS_WIN) // Used in the parent (unsandboxed) process to hold a mapping between HANDLES // and tokens. When a child process wants to send a HANDLE to another process, // it exchanges it to a token and then the other process exchanges that token // back to a HANDLE. - base::Lock lock_; // Guards access to below. + base::Lock token_map_lock_; base::hash_map<uint64_t, HANDLE> token_map_; #endif + + // For pending connects originiating in this process. + // Only accessed on the IO thread. + base::hash_map<uint64_t, MessagePipeDispatcher*> pending_connects_; + + // For connected message pipes in this process. This is needed so that when a + // MessagePipeDispatcher is closed we can remove the route for the + // corresponding RoutedRawChannel. + // Only accessed on the IO thread. + base::hash_map<MessagePipeDispatcher*, RoutedRawChannel*> connected_pipes_; + + base::Lock lock_; // Guards access to below. + + // Holds a map of all the RoutedRawChannel that connect this parent process to + // a child process. The key is the child process'd pid. + base::hash_map<base::ProcessId, RoutedRawChannel*> child_channels_; + + base::hash_map<uint64_t, ChildBrokerHost*> pending_child_connects_; + + // Each entry is an std::pair of ints of processe IDs that have + // RoutedRawChannel objects between them. The pair always has the smaller + // process id value first. + // For now, we don't reap connections if there are no more routes between two + // processes. + base::hash_set<std::pair<base::ProcessId, base::ProcessId>> + connected_processes_; + + base::hash_map<base::ProcessId, ChildBrokerHost*> child_processes_; + + // Used for message pipes in the same process. + RoutedRawChannel* in_process_pipes_channel1_; + RoutedRawChannel* in_process_pipes_channel2_; + + DISALLOW_COPY_AND_ASSIGN(BrokerState); }; } // namespace edk
diff --git a/mojo/edk/system/child_broker.cc b/mojo/edk/system/child_broker.cc index 7d7b4c6..fbfeb3d 100644 --- a/mojo/edk/system/child_broker.cc +++ b/mojo/edk/system/child_broker.cc
@@ -4,9 +4,13 @@ #include "mojo/edk/system/child_broker.h" +#include "base/bind.h" #include "base/logging.h" #include "mojo/edk/embedder/embedder_internal.h" +#include "mojo/edk/embedder/platform_channel_pair.h" #include "mojo/edk/system/broker_messages.h" +#include "mojo/edk/system/message_pipe_dispatcher.h" +#include "mojo/edk/system/routed_raw_channel.h" namespace mojo { namespace edk { @@ -17,23 +21,41 @@ } void ChildBroker::SetChildBrokerHostHandle(ScopedPlatformHandle handle) { - handle_ = handle.Pass(); + ScopedPlatformHandle parent_async_channel_handle; +#if defined(OS_POSIX) + parent_async_channel_handle = handle.Pass(); +#else + // On Windows we have two pipes to the parent. The first is for the token + // exchange for creating and passing handles, since the child needs the + // parent's help if it is sandboxed. The second is the same as POSIX, which is + // used for multiplexing related messages. So on Windows, we send the second + // pipe as the first string over the first one. + parent_sync_channel_ = handle.Pass(); + + HANDLE parent_handle = INVALID_HANDLE_VALUE; + DWORD bytes_read = 0; + BOOL rv = ReadFile(parent_sync_channel_.get().handle, &parent_handle, + sizeof(parent_handle), &bytes_read, NULL); + CHECK(rv); + parent_async_channel_handle.reset(PlatformHandle(parent_handle)); +#endif + + parent_async_channel_ = + RawChannel::Create(parent_async_channel_handle.Pass()); + internal::g_io_thread_task_runner->PostTask( + FROM_HERE, + base::Bind(&RawChannel::Init, base::Unretained(parent_async_channel_), + this)); + lock_.Unlock(); } #if defined(OS_WIN) void ChildBroker::CreatePlatformChannelPair( ScopedPlatformHandle* server, ScopedPlatformHandle* client) { - BrokerMessage message; - message.size = kBrokerMessageHeaderSize; - message.id = CREATE_PLATFORM_CHANNEL_PAIR; - - uint32_t response_size = 2 * sizeof(HANDLE); - HANDLE handles[2]; - if (WriteAndReadResponse(&message, handles, response_size)) { - server->reset(PlatformHandle(handles[0])); - client->reset(PlatformHandle(handles[1])); - } + lock_.Lock(); + CreatePlatformChannelPairNoLock(server, client); + lock_.Unlock(); } void ChildBroker::HandleToToken(const PlatformHandle* platform_handles, @@ -49,7 +71,9 @@ message->handles[i] = platform_handles[i].handle; uint32_t response_size = static_cast<int>(count) * sizeof(uint64_t); + lock_.Lock(); WriteAndReadResponse(message, tokens, response_size); + lock_.Unlock(); } void ChildBroker::TokenToHandle(const uint64_t* tokens, @@ -67,14 +91,85 @@ std::vector<HANDLE> handles_temp(count); uint32_t response_size = static_cast<uint32_t>(handles_temp.size()) * sizeof(HANDLE); + lock_.Lock(); if (WriteAndReadResponse(message, &handles_temp[0], response_size)) { for (uint32_t i = 0; i < count; ++i) handles[i].handle = handles_temp[i]; + lock_.Unlock(); } } #endif -ChildBroker::ChildBroker() { +void ChildBroker::ConnectMessagePipe(uint64_t pipe_id, + MessagePipeDispatcher* message_pipe) { + DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); + lock_.Lock(); + + ConnectMessagePipeMessage data; + data.pipe_id = pipe_id; + if (pending_connects_.find(pipe_id) != pending_connects_.end()) { + // Both ends of the message pipe are in the same process. + // First, tell the browser side that to remove its bookkeeping for a pending + // connect, since it'll never get the other side. + + data.type = CANCEL_CONNECT_MESSAGE_PIPE; + scoped_ptr<MessageInTransit> message(new MessageInTransit( + MessageInTransit::Type::MESSAGE, sizeof(data), &data)); + parent_async_channel_->WriteMessage(message.Pass()); + + if (!in_process_pipes_channel1_) { + ScopedPlatformHandle server_handle, client_handle; +#if defined(OS_WIN) + CreatePlatformChannelPairNoLock(&server_handle, &client_handle); +#else + PlatformChannelPair channel_pair; + server_handle = channel_pair.PassServerHandle(); + client_handle = channel_pair.PassClientHandle(); +#endif + in_process_pipes_channel1_ = new RoutedRawChannel( + server_handle.Pass(), + base::Bind(&ChildBroker::ChannelDestructed, base::Unretained(this))); + in_process_pipes_channel2_ = new RoutedRawChannel( + client_handle.Pass(), + base::Bind(&ChildBroker::ChannelDestructed, base::Unretained(this))); + } + + connected_pipes_[pending_connects_[pipe_id]] = in_process_pipes_channel1_; + connected_pipes_[message_pipe] = in_process_pipes_channel2_; + in_process_pipes_channel1_->AddRoute(pipe_id, pending_connects_[pipe_id]); + in_process_pipes_channel2_->AddRoute(pipe_id, message_pipe); + pending_connects_[pipe_id]->GotNonTransferableChannel( + in_process_pipes_channel1_->channel()); + message_pipe->GotNonTransferableChannel( + in_process_pipes_channel2_->channel()); + + pending_connects_.erase(pipe_id); + lock_.Unlock(); + return; + } + + data.type = CONNECT_MESSAGE_PIPE; + scoped_ptr<MessageInTransit> message(new MessageInTransit( + MessageInTransit::Type::MESSAGE, sizeof(data), &data)); + pending_connects_[pipe_id] = message_pipe; + parent_async_channel_->WriteMessage(message.Pass()); + + lock_.Unlock(); +} + +void ChildBroker::CloseMessagePipe( + uint64_t pipe_id, MessagePipeDispatcher* message_pipe) { + DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); + lock_.Lock(); + CHECK(connected_pipes_.find(message_pipe) != connected_pipes_.end()); + connected_pipes_[message_pipe]->RemoveRoute(pipe_id, message_pipe); + connected_pipes_.erase(message_pipe); + lock_.Unlock(); +} + +ChildBroker::ChildBroker() + : in_process_pipes_channel1_(nullptr), + in_process_pipes_channel2_(nullptr) { DCHECK(!internal::g_broker); internal::g_broker = this; // Block any threads from calling this until we have a pipe to the parent. @@ -84,18 +179,80 @@ ChildBroker::~ChildBroker() { } +void ChildBroker::OnReadMessage( + const MessageInTransit::View& message_view, + ScopedPlatformHandleVectorPtr platform_handles) { + DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); + lock_.Lock(); + MultiplexMessages type = + *static_cast<const MultiplexMessages*>(message_view.bytes()); + if (type == CONNECT_TO_PROCESS) { + DCHECK_EQ(platform_handles->size(), 1u); + ScopedPlatformHandle handle((*platform_handles.get())[0]); + (*platform_handles.get())[0] = PlatformHandle(); + + const ConnectToProcessMessage* message = + static_cast<const ConnectToProcessMessage*>(message_view.bytes()); + + CHECK(channels_.find(message->process_id) == channels_.end()); + channels_[message->process_id] = new RoutedRawChannel( + handle.Pass(), + base::Bind(&ChildBroker::ChannelDestructed, base::Unretained(this))); + } else if (type == PEER_PIPE_CONNECTED) { + DCHECK(!platform_handles); + const PeerPipeConnectedMessage* message = + static_cast<const PeerPipeConnectedMessage*>(message_view.bytes()); + + uint64_t pipe_id = message->pipe_id; + uint64_t peer_pid = message->process_id; + + CHECK(pending_connects_.find(pipe_id) != pending_connects_.end()); + MessagePipeDispatcher* pipe = pending_connects_[pipe_id]; + pending_connects_.erase(pipe_id); + if (channels_.find(peer_pid) == channels_.end()) { + // We saw the peer process die before we got the reply from the parent. + pipe->OnError(ERROR_READ_SHUTDOWN); + } else { + CHECK(connected_pipes_.find(pipe) == connected_pipes_.end()); + connected_pipes_[pipe] = channels_[peer_pid]; + channels_[peer_pid]->AddRoute(pipe_id, pipe); + pipe->GotNonTransferableChannel(channels_[peer_pid]->channel()); + } + } else { + NOTREACHED(); + } + + lock_.Unlock(); +} + +void ChildBroker::OnError(Error error) { + // The parent process shut down. +} + +void ChildBroker::ChannelDestructed(RoutedRawChannel* channel) { + DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); + lock_.Lock(); + for (auto it : channels_) { + if (it.second == channel) { + channels_.erase(it.first); + break; + } + } + lock_.Unlock(); +} + +#if defined(OS_WIN) + bool ChildBroker::WriteAndReadResponse(BrokerMessage* message, void* response, uint32_t response_size) { - lock_.Lock(); - CHECK(handle_.is_valid()); + CHECK(parent_sync_channel_.is_valid()); bool result = true; -#if defined(OS_WIN) DWORD bytes_written = 0; // This will always write in one chunk per // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150.aspx. - BOOL rv = WriteFile(handle_.get().handle, message, message->size, + BOOL rv = WriteFile(parent_sync_channel_.get().handle, message, message->size, &bytes_written, NULL); if (!rv || bytes_written != message->size) { LOG(ERROR) << "Child token serializer couldn't write message."; @@ -103,8 +260,8 @@ } else { while (response_size) { DWORD bytes_read = 0; - rv = ReadFile(handle_.get().handle, response, response_size, &bytes_read, - NULL); + rv = ReadFile(parent_sync_channel_.get().handle, response, response_size, + &bytes_read, NULL); if (!rv) { LOG(ERROR) << "Child token serializer couldn't read result."; result = false; @@ -114,12 +271,25 @@ response = static_cast<char*>(response) + bytes_read; } } -#endif - - lock_.Unlock(); return result; } +void ChildBroker::CreatePlatformChannelPairNoLock( + ScopedPlatformHandle* server, ScopedPlatformHandle* client) { + BrokerMessage message; + message.size = kBrokerMessageHeaderSize; + message.id = CREATE_PLATFORM_CHANNEL_PAIR; + + uint32_t response_size = 2 * sizeof(HANDLE); + HANDLE handles[2]; + if (WriteAndReadResponse(&message, handles, response_size)) { + server->reset(PlatformHandle(handles[0])); + client->reset(PlatformHandle(handles[1])); + } +} + +#endif + } // namespace edk } // namespace mojo
diff --git a/mojo/edk/system/child_broker.h b/mojo/edk/system/child_broker.h index 689739a..366daa74 100644 --- a/mojo/edk/system/child_broker.h +++ b/mojo/edk/system/child_broker.h
@@ -5,20 +5,28 @@ #ifndef MOJO_EDK_SYSTEM_CHILD_BROKER_H_ #define MOJO_EDK_SYSTEM_CHILD_BROKER_H_ +#include "base/compiler_specific.h" +#include "base/containers/hash_tables.h" +#include "base/macros.h" #include "base/memory/singleton.h" +#include "base/process/process_handle.h" #include "base/synchronization/lock_impl.h" #include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/edk/system/broker.h" +#include "mojo/edk/system/raw_channel.h" #include "mojo/edk/system/system_impl_export.h" namespace mojo { namespace edk { +class RoutedRawChannel; struct BrokerMessage; // An implementation of Broker used in (sandboxed) child processes. It talks // over sync IPCs to the (unsandboxed) parent process (specifically, -// ParentBroker) to convert handles to tokens and vice versa. -class MOJO_SYSTEM_IMPL_EXPORT ChildBroker : public Broker { +// ChildBrokerHost) to convert handles to tokens and vice versa. It also sends +// async messages to handle message pipe multiplexing. +class MOJO_SYSTEM_IMPL_EXPORT ChildBroker + : public Broker, public RawChannel::Delegate { public: static ChildBroker* GetInstance(); @@ -36,6 +44,10 @@ size_t count, PlatformHandle* handles) override; #endif + void ConnectMessagePipe(uint64_t pipe_id, + MessagePipeDispatcher* message_pipe) override; + void CloseMessagePipe(uint64_t pipe_id, + MessagePipeDispatcher* message_pipe) override; private: friend struct base::DefaultSingletonTraits<ChildBroker>; @@ -43,17 +55,68 @@ ChildBroker(); ~ChildBroker() override; + // RawChannel::Delegate implementation: + void OnReadMessage( + const MessageInTransit::View& message_view, + ScopedPlatformHandleVectorPtr platform_handles) override; + void OnError(Error error) override; + + // Callback for when a RoutedRawChannel is destroyed for cleanup. + void ChannelDestructed(RoutedRawChannel* channel); + +#if defined(OS_WIN) // Helper method to write the given message and read back the result. bool WriteAndReadResponse(BrokerMessage* message, void* response, uint32_t response_size); + void CreatePlatformChannelPairNoLock(ScopedPlatformHandle* server, + ScopedPlatformHandle* client); + + // Pipe used for communication to the parent process. We use a pipe directly + // instead of bindings or RawChannel because we need to send synchronous + // messages with replies from any thread. + ScopedPlatformHandle parent_sync_channel_; +#endif + // Guards access to below. // We use LockImpl instead of Lock because the latter adds thread checking // that we don't want (since we lock in the constructor and unlock on another // thread. base::internal::LockImpl lock_; - ScopedPlatformHandle handle_; + + // RawChannel used for asynchronous communication to and from the parent + // process. Since these messages are bidirectional, we can't use + // |parent_sync_channel_| which is only used for sync messages to the parent. + // However since the messages are asynchronous, we can use RawChannel for + // convenience instead of writing and reading from pipes manually. Although it + // would be convenient, we don't use Mojo IPC because it would be a layering + // violation (and cirular dependency) if the system layer depended on + // bindings. + RawChannel* parent_async_channel_; + + // Maps from routing ids to the MessagePipeDispatcher that have requested to + // connect to them. When the parent replies with which process they should be + // connected to, they will migrate to |connected_pipes_|. + base::hash_map<uint64_t, MessagePipeDispatcher*> pending_connects_; + + // Map from MessagePipeDispatcher to its RoutedRawChannel. This is needed so + // that when a MessagePipeDispatcher is closed we can remove the route for the + // corresponding RoutedRawChannel. + // Note the key is MessagePipeDispatcher*, instead of pipe_id, because when + // the two pipes are in the same process they will have one pipe_id but be + // connected to the two RoutedRawChannel objects below. + base::hash_map<MessagePipeDispatcher*, RoutedRawChannel*> connected_pipes_; + + // Holds a map of all the RoutedRawChannel that connect this child process to + // any other process. The key is the peer process'd pid. + base::hash_map<base::ProcessId, RoutedRawChannel*> channels_; + + // Used for message pipes in the same process. + RoutedRawChannel* in_process_pipes_channel1_; + RoutedRawChannel* in_process_pipes_channel2_; + + DISALLOW_COPY_AND_ASSIGN(ChildBroker); }; } // namespace edk
diff --git a/mojo/edk/system/child_broker_host.cc b/mojo/edk/system/child_broker_host.cc index b7f055a..ae7236f 100644 --- a/mojo/edk/system/child_broker_host.cc +++ b/mojo/edk/system/child_broker_host.cc
@@ -6,77 +6,177 @@ #include "base/bind.h" #include "base/lazy_instance.h" +#include "mojo/edk/embedder/embedder_internal.h" #include "mojo/edk/embedder/platform_channel_pair.h" #include "mojo/edk/system/broker_messages.h" #include "mojo/edk/system/broker_state.h" #include "mojo/edk/system/configuration.h" +#include "mojo/edk/system/core.h" +#include "mojo/edk/system/platform_handle_dispatcher.h" namespace mojo { namespace edk { namespace { +#if defined(OS_WIN) static const int kDefaultReadBufferSize = 256; +#endif } ChildBrokerHost::ChildBrokerHost(base::ProcessHandle child_process, ScopedPlatformHandle pipe) - : child_process_(child_process), - pipe_(pipe.Pass()), - num_bytes_read_(0) { -#if defined(OS_WIN) + : process_id_(base::GetProcId(child_process)) { + ScopedPlatformHandle parent_async_channel_handle; +#if defined(OS_POSIX) + parent_async_channel_handle = pipe.Pass(); +#else + child_process_ = child_process; + sync_channel_ = pipe.Pass(); memset(&read_context_.overlapped, 0, sizeof(read_context_.overlapped)); read_context_.handler = this; memset(&write_context_.overlapped, 0, sizeof(write_context_.overlapped)); write_context_.handler = this; -#else - // TODO(jam) - (void)child_process_; // Suppress -Wunused-private-field. - (void)num_bytes_read_; // Suppress -Wunused-private-field. -#endif - read_data_.resize(kDefaultReadBufferSize); - BrokerState::GetInstance()->broker_thread()->PostTask( + num_bytes_read_ = 0; + + // See comment in ChildBroker::SetChildBrokerHostHandle. Summary is we need + // two pipes on Windows, so send the second one over the first one. + PlatformChannelPair parent_pipe; + parent_async_channel_handle = parent_pipe.PassServerHandle(); + + HANDLE duplicated_child_handle = + DuplicateToChild(parent_pipe.PassClientHandle().release().handle); + BOOL rv = WriteFile(sync_channel_.get().handle, + &duplicated_child_handle, sizeof(duplicated_child_handle), + NULL, &write_context_.overlapped); + DCHECK(rv || GetLastError() == ERROR_IO_PENDING); + + internal::g_io_thread_task_runner->PostTask( FROM_HERE, base::Bind(&ChildBrokerHost::RegisterIOHandler, base::Unretained(this))); +#endif + + child_channel_ = RawChannel::Create(parent_async_channel_handle.Pass()); + internal::g_io_thread_task_runner->PostTask( + FROM_HERE, + base::Bind(&RawChannel::Init, base::Unretained(child_channel_), this)); + internal::g_io_thread_task_runner->PostTask( + FROM_HERE, + base::Bind(&RawChannel::EnsureLazyInitialized, + base::Unretained(child_channel_))); + + BrokerState::GetInstance()->ChildBrokerHostCreated(this); +} + +base::ProcessId ChildBrokerHost::GetProcessId() { + return process_id_; +} + +void ChildBrokerHost::ConnectToProcess(base::ProcessId process_id, + ScopedPlatformHandle pipe) { + if (!child_channel_) + return; // Can happen at process shutdown on Windows. + ConnectToProcessMessage data; + data.type = CONNECT_TO_PROCESS; + data.process_id = process_id; + scoped_ptr<MessageInTransit> message(new MessageInTransit( + MessageInTransit::Type::MESSAGE, sizeof(data), &data)); + scoped_refptr<Dispatcher> dispatcher = + PlatformHandleDispatcher::Create(pipe.Pass()); + internal::g_core->AddDispatcher(dispatcher); + scoped_ptr<DispatcherVector> dispatchers(new DispatcherVector); + dispatchers->push_back(dispatcher); + message->SetDispatchers(dispatchers.Pass()); + message->SerializeAndCloseDispatchers(); + child_channel_->WriteMessage(message.Pass()); +} + +void ChildBrokerHost::ConnectMessagePipe(uint64_t pipe_id, + base::ProcessId process_id) { + if (!child_channel_) + return; // Can happen at process shutdown on Windows. + PeerPipeConnectedMessage data; + data.type = PEER_PIPE_CONNECTED; + data.pipe_id = pipe_id; + data.process_id = process_id; + scoped_ptr<MessageInTransit> message(new MessageInTransit( + MessageInTransit::Type::MESSAGE, sizeof(data), &data)); + child_channel_->WriteMessage(message.Pass()); } ChildBrokerHost::~ChildBrokerHost() { + DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); + BrokerState::GetInstance()->ChildBrokerHostDestructed(this); + if (child_channel_) + child_channel_->Shutdown(); } -void ChildBrokerHost::RegisterIOHandler() { -#if defined(OS_WIN) - base::MessageLoopForIO::current()->RegisterIOHandler( - pipe_.get().handle, this); - BeginRead(); -#elif defined(OS_POSIX) - // TOOD(jam): setup +void ChildBrokerHost::OnReadMessage( + const MessageInTransit::View& message_view, + ScopedPlatformHandleVectorPtr platform_handles) { + DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); + CHECK(!platform_handles); + if (message_view.num_bytes() != + static_cast<uint32_t>(sizeof(ConnectMessagePipeMessage))) { + NOTREACHED(); + delete this; + } + + const ConnectMessagePipeMessage* message = + static_cast<const ConnectMessagePipeMessage*>(message_view.bytes()); + switch(message->type) { + case CONNECT_MESSAGE_PIPE: + BrokerState::GetInstance()->HandleConnectMessagePipe(this, + message->pipe_id); + break; + case CANCEL_CONNECT_MESSAGE_PIPE: + BrokerState::GetInstance()->HandleCancelConnectMessagePipe( + message->pipe_id); + break; + default: + NOTREACHED(); + delete this; + } +} + +void ChildBrokerHost::OnError(Error error) { + DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); + child_channel_->Shutdown(); + child_channel_ = nullptr; + // On Windows, we have two pipes to the child process. It's easier to wait + // until we get the error from the pipe that uses asynchronous I/O. +#if !defined(OS_WIN) + delete this; #endif } -void ChildBrokerHost::BeginRead() { #if defined(OS_WIN) - BOOL rv = ReadFile(pipe_.get().handle, &read_data_[num_bytes_read_], +void ChildBrokerHost::RegisterIOHandler() { + base::MessageLoopForIO::current()->RegisterIOHandler( + sync_channel_.get().handle, this); + BeginRead(); +} + +void ChildBrokerHost::BeginRead() { + BOOL rv = ReadFile(sync_channel_.get().handle, + &read_data_[num_bytes_read_], static_cast<int>(read_data_.size() - num_bytes_read_), nullptr, &read_context_.overlapped); if (rv || GetLastError() == ERROR_IO_PENDING) return; - if (rv == ERROR_BROKEN_PIPE) { + if (GetLastError() == ERROR_BROKEN_PIPE) { delete this; return; } NOTREACHED() << "Unknown error in ChildBrokerHost " << rv; -#endif } -#if defined(OS_WIN) void ChildBrokerHost::OnIOCompleted(base::MessageLoopForIO::IOContext* context, DWORD bytes_transferred, DWORD error) { - if (context != &read_context_) - return; - + DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); if (error == ERROR_BROKEN_PIPE) { delete this; return; // Child process exited or crashed. @@ -88,6 +188,11 @@ return; } + if (context == &write_context_) { + write_data_.clear(); + return; + } + num_bytes_read_ += bytes_transferred; CHECK_GE(num_bytes_read_, sizeof(uint32_t)); BrokerMessage* message = reinterpret_cast<BrokerMessage*>(&read_data_[0]); @@ -97,6 +202,15 @@ return; } + // This should never fire because we only get new requests from a child + // process after it has read all the previous data we wrote. + if (!write_data_.empty()) { + NOTREACHED() << "ChildBrokerHost shouldn't have data to write when it gets " + << " a new request"; + delete this; + return; + } + if (message->id == CREATE_PLATFORM_CHANNEL_PAIR) { PlatformChannelPair channel_pair; uint32_t response_size = 2 * sizeof(HANDLE); @@ -152,7 +266,7 @@ return; } - BOOL rv = WriteFile(pipe_.get().handle, &write_data_[0], + BOOL rv = WriteFile(sync_channel_.get().handle, &write_data_[0], static_cast<int>(write_data_.size()), NULL, &write_context_.overlapped); DCHECK(rv || GetLastError() == ERROR_IO_PENDING);
diff --git a/mojo/edk/system/child_broker_host.h b/mojo/edk/system/child_broker_host.h index 7f4bc61..a91218a 100644 --- a/mojo/edk/system/child_broker_host.h +++ b/mojo/edk/system/child_broker_host.h
@@ -8,20 +8,24 @@ #include <vector> #include "base/compiler_specific.h" +#include "base/macros.h" #include "base/message_loop/message_loop.h" #include "base/process/process_handle.h" #include "mojo/edk/embedder/scoped_platform_handle.h" +#include "mojo/edk/system/raw_channel.h" #include "mojo/edk/system/system_impl_export.h" namespace mojo { namespace edk { -// Responds to requests from a child process to exchange handles to tokens and -// vice versa. There is one object of this class per child process host object. +// Responds to requests from ChildBroker. This is used to handle message pipe +// multiplexing and Windows sandbox messages. There is one object of this class +// per child process host object. // This object will delete itself when it notices that the pipe is broken. class MOJO_SYSTEM_IMPL_EXPORT ChildBrokerHost + : public RawChannel::Delegate #if defined(OS_WIN) - : NON_EXPORTED_BASE(public base::MessageLoopForIO::IOHandler) { + , NON_EXPORTED_BASE(public base::MessageLoopForIO::IOHandler) { #else { #endif @@ -33,17 +37,29 @@ // this class. ChildBrokerHost(base::ProcessHandle child_process, ScopedPlatformHandle pipe); - private: -#if defined(OS_WIN) - ~ChildBrokerHost() override; -#else - ~ChildBrokerHost(); -#endif + base::ProcessId GetProcessId(); + // Sends a message to the child process to connect to |process_id| via |pipe|. + void ConnectToProcess(base::ProcessId process_id, ScopedPlatformHandle pipe); + + // Sends a message to the child process that |pipe_id|'s other end is in + // |process_id|. + void ConnectMessagePipe(uint64_t pipe_id, base::ProcessId process_id); + + private: + ~ChildBrokerHost() override; + + // RawChannel::Delegate implementation: + void OnReadMessage( + const MessageInTransit::View& message_view, + ScopedPlatformHandleVectorPtr platform_handles) override; + void OnError(Error error) override; + +#if defined(OS_WIN) void RegisterIOHandler(); void BeginRead(); -#if defined(OS_WIN) + // base::MessageLoopForIO::IOHandler implementation: void OnIOCompleted(base::MessageLoopForIO::IOContext* context, DWORD bytes_transferred, DWORD error) override; @@ -53,18 +69,29 @@ HANDLE DuplicateFromChild(HANDLE handle); #endif - base::ProcessHandle child_process_; - ScopedPlatformHandle pipe_; + base::ProcessId process_id_; + + // Channel used to receive and send multiplexing related messages. + RawChannel* child_channel_; #if defined(OS_WIN) + // Handle to the child process, used for duplication of handles. + base::ProcessHandle child_process_; + + // Pipe used for synchronous messages from the child. Responses are written to + // it as well. + ScopedPlatformHandle sync_channel_; + base::MessageLoopForIO::IOContext read_context_; base::MessageLoopForIO::IOContext write_context_; -#endif std::vector<char> read_data_; // How many bytes in read_data_ we already read. uint32_t num_bytes_read_; std::vector<char> write_data_; +#endif + + DISALLOW_COPY_AND_ASSIGN(ChildBrokerHost); }; } // namespace edk
diff --git a/mojo/edk/system/core.cc b/mojo/edk/system/core.cc index 77b06f0cc..454b487 100644 --- a/mojo/edk/system/core.cc +++ b/mojo/edk/system/core.cc
@@ -7,6 +7,7 @@ #include <vector> #include "base/logging.h" +#include "base/rand_util.h" #include "base/time/time.h" #include "mojo/edk/embedder/embedder_internal.h" #include "mojo/edk/embedder/platform_channel_pair.h" @@ -206,18 +207,28 @@ return MOJO_RESULT_RESOURCE_EXHAUSTED; } - ScopedPlatformHandle server_handle, client_handle; + if (validated_options.flags & + MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE) { + ScopedPlatformHandle server_handle, client_handle; #if defined(OS_WIN) - internal::g_broker->CreatePlatformChannelPair(&server_handle, &client_handle); + internal::g_broker->CreatePlatformChannelPair(&server_handle, + &client_handle); #else - PlatformChannelPair channel_pair; - server_handle = channel_pair.PassServerHandle(); - client_handle = channel_pair.PassClientHandle(); + PlatformChannelPair channel_pair; + server_handle = channel_pair.PassServerHandle(); + client_handle = channel_pair.PassClientHandle(); #endif - dispatcher0->Init(server_handle.Pass(), nullptr, 0u, nullptr, 0u, nullptr, - nullptr); - dispatcher1->Init(client_handle.Pass(), nullptr, 0u, nullptr, 0u, nullptr, - nullptr); + dispatcher0->Init(server_handle.Pass(), nullptr, 0u, nullptr, 0u, nullptr, + nullptr); + dispatcher1->Init(client_handle.Pass(), nullptr, 0u, nullptr, 0u, nullptr, + nullptr); + } else { + uint64_t pipe_id = 0; + while (pipe_id == 0) + pipe_id = base::RandUint64(); + dispatcher0->InitNonTransferable(pipe_id); + dispatcher1->InitNonTransferable(pipe_id); + } *message_pipe_handle0 = handle_pair.first; *message_pipe_handle1 = handle_pair.second;
diff --git a/mojo/edk/system/core_test_base.h b/mojo/edk/system/core_test_base.h index 774dc95..7ed8a7a 100644 --- a/mojo/edk/system/core_test_base.h +++ b/mojo/edk/system/core_test_base.h
@@ -22,7 +22,7 @@ class CoreTestBase_MockHandleInfo; -class CoreTestBase : public MojoSystemTest { +class CoreTestBase : public testing::Test { public: using MockHandleInfo = CoreTestBase_MockHandleInfo;
diff --git a/mojo/edk/system/core_unittest.cc b/mojo/edk/system/core_unittest.cc index cbbd905..9604bbd 100644 --- a/mojo/edk/system/core_unittest.cc +++ b/mojo/edk/system/core_unittest.cc
@@ -730,8 +730,11 @@ #endif MojoHandle h_passed[2]; + MojoCreateMessagePipeOptions options; + options.struct_size = sizeof(MojoCreateMessagePipeOptions); + options.flags = MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE; ASSERT_EQ(MOJO_RESULT_OK, - core()->CreateMessagePipe(nullptr, &h_passed[0], &h_passed[1])); + core()->CreateMessagePipe(&options, &h_passed[0], &h_passed[1])); // Make sure that |h_passed[]| work properly. ASSERT_EQ(MOJO_RESULT_OK,
diff --git a/mojo/edk/system/data_pipe_unittest.cc b/mojo/edk/system/data_pipe_unittest.cc index 5c8f0f8..0880f6084 100644 --- a/mojo/edk/system/data_pipe_unittest.cc +++ b/mojo/edk/system/data_pipe_unittest.cc
@@ -32,7 +32,7 @@ // TODO(vtl): Get rid of this. const size_t kMaxPoll = 100; -class DataPipeTest : public test::MojoSystemTest { +class DataPipeTest : public testing::Test { public: DataPipeTest() : producer_(MOJO_HANDLE_INVALID), consumer_(MOJO_HANDLE_INVALID) {}
diff --git a/mojo/edk/system/dispatcher.h b/mojo/edk/system/dispatcher.h index fb757c7..d1c7b1f6 100644 --- a/mojo/edk/system/dispatcher.h +++ b/mojo/edk/system/dispatcher.h
@@ -300,6 +300,7 @@ // Available to subclasses. (Note: Returns a non-const reference, just like // |base::AutoLock|'s constructor takes a non-const reference.) base::Lock& lock() const { return lock_; } + bool is_closed() const { return is_closed_; } private: friend class DispatcherTransport;
diff --git a/mojo/edk/system/message_in_transit.cc b/mojo/edk/system/message_in_transit.cc index b85efc7..05fd98f 100644 --- a/mojo/edk/system/message_in_transit.cc +++ b/mojo/edk/system/message_in_transit.cc
@@ -166,6 +166,7 @@ header()->type = type; header()->num_bytes = num_bytes; header()->unused = 0; + header()->route_id = 0; // Note: If dispatchers are subsequently attached, then |total_size| will have // to be adjusted. UpdateTotalSize();
diff --git a/mojo/edk/system/message_in_transit.h b/mojo/edk/system/message_in_transit.h index 78dc40a..bebaaf7 100644 --- a/mojo/edk/system/message_in_transit.h +++ b/mojo/edk/system/message_in_transit.h
@@ -103,6 +103,7 @@ return static_cast<const char*>(buffer_) + sizeof(Header); } Type type() const { return header()->type; } + uint64_t route_id() const { return header()->route_id; } private: const Header* header() const { return static_cast<const Header*>(buffer_); } @@ -171,6 +172,9 @@ Type type() const { return header()->type; } + void set_route_id(uint64_t route_id) { header()->route_id = route_id; } + uint64_t route_id() const { return header()->route_id; } + // Gets the dispatchers attached to this message; this may return null if // there are none. Note that the caller may mutate the set of dispatchers // (e.g., take ownership of all the dispatchers, leaving the vector empty). @@ -200,9 +204,10 @@ // |SerializeAndCloseDispatchers()| has not been called. uint32_t total_size; Type type; // 2 bytes. - Type unusedforalignment; // 2 bytes. + uint16_t unusedforalignment; // 2 bytes. uint32_t num_bytes; uint32_t unused; + uint64_t route_id; }; const Header* header() const {
diff --git a/mojo/edk/system/message_pipe_dispatcher.cc b/mojo/edk/system/message_pipe_dispatcher.cc index 6ebab748..55e03fa 100644 --- a/mojo/edk/system/message_pipe_dispatcher.cc +++ b/mojo/edk/system/message_pipe_dispatcher.cc
@@ -25,10 +25,13 @@ const size_t kInvalidMessagePipeHandleIndex = static_cast<size_t>(-1); struct MOJO_ALIGNAS(8) SerializedMessagePipeHandleDispatcher { + bool transferable; + bool write_error; + uint64_t pipe_id; // If transferable is false. + // The following members are only set if transferable is true. // Could be |kInvalidMessagePipeHandleIndex| if the other endpoint of the MP // was closed. size_t platform_handle_index; - bool write_error; size_t shared_memory_handle_index; // (Or |kInvalidMessagePipeHandleIndex|.) uint32_t shared_memory_size; @@ -90,7 +93,8 @@ const MojoCreateMessagePipeOptions* in_options, MojoCreateMessagePipeOptions* out_options) { const MojoCreateMessagePipeOptionsFlags kKnownFlags = - MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE; + MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE | + MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE; *out_options = kDefaultCreateOptions; if (!in_options) @@ -119,6 +123,7 @@ char* serialized_write_buffer, size_t serialized_write_buffer_size, std::vector<int>* serialized_read_fds, std::vector<int>* serialized_write_fds) { + CHECK(transferable_); if (message_pipe.get().is_valid()) { channel_ = RawChannel::Create(message_pipe.Pass()); @@ -132,8 +137,14 @@ } } +void MessagePipeDispatcher::InitNonTransferable(uint64_t pipe_id) { + CHECK(!transferable_); + pipe_id_ = pipe_id; +} + void MessagePipeDispatcher::InitOnIO() { base::AutoLock locker(lock()); + CHECK(transferable_); calling_init_ = true; if (channel_) channel_->Init(this); @@ -142,10 +153,28 @@ void MessagePipeDispatcher::CloseOnIO() { base::AutoLock locker(lock()); + if (transferable_) { + if (channel_) { + channel_->Shutdown(); + channel_ = nullptr; + } + } else { + if (non_transferable_state_ == CONNECT_CALLED || + non_transferable_state_ == WAITING_FOR_READ_OR_WRITE) { + if (non_transferable_state_ == WAITING_FOR_READ_OR_WRITE) + RequestNontransferableChannel(); - if (channel_) { - channel_->Shutdown(); - channel_ = nullptr; + // We can't cancel the pending request yet, since the other side of the + // message pipe would want to get pending outgoing messages (if any) or + // at least know that this end was closed. So keep this object alive until + // then. + non_transferable_state_ = WAITING_FOR_CONNECT_TO_CLOSE; + AddRef(); + } else if (non_transferable_state_ == CONNECTED) { + internal::g_broker->CloseMessagePipe(pipe_id_, this); + non_transferable_state_ = CLOSED; + channel_ = nullptr; + } } } @@ -153,6 +182,30 @@ return Type::MESSAGE_PIPE; } +void MessagePipeDispatcher::GotNonTransferableChannel(RawChannel* channel) { + base::AutoLock locker(lock()); + channel_ = channel; + while (!non_transferable_outgoing_message_queue_.IsEmpty()) { + channel_->WriteMessage( + non_transferable_outgoing_message_queue_.GetMessage()); + } + + if (non_transferable_state_ == WAITING_FOR_CONNECT_TO_CLOSE) { + // We kept this object alive until it's connected, we can release it now. + // Since we're in a callback from the Broker, call it asynchronously. + internal::g_io_thread_task_runner->PostTask( + FROM_HERE, + base::Bind(&Broker::CloseMessagePipe, + base::Unretained(internal::g_broker), pipe_id_, + base::Unretained(this))); + non_transferable_state_ = CLOSED; + channel_ = nullptr; + base::MessageLoop::current()->ReleaseSoon(FROM_HERE, this); + } else { + non_transferable_state_ = CONNECTED; + } +} + #if defined(OS_WIN) // TODO(jam): this is copied from RawChannelWin till I figure out what's the // best way we want to share this. @@ -186,6 +239,14 @@ const SerializedMessagePipeHandleDispatcher* serialization = static_cast<const SerializedMessagePipeHandleDispatcher*>(source); + + scoped_refptr<MessagePipeDispatcher> rv( + new MessagePipeDispatcher(serialization->transferable)); + if (!rv->transferable_) { + rv->InitNonTransferable(serialization->pipe_id); + return rv; + } + if (serialization->shared_memory_size != (serialization->serialized_read_buffer_size + serialization->serialized_write_buffer_size + @@ -233,8 +294,6 @@ } } - scoped_refptr<MessagePipeDispatcher> rv( - Create(MessagePipeDispatcher::kDefaultCreateOptions)); rv->write_error_ = serialization->write_error; std::vector<int> serialized_read_fds; @@ -269,8 +328,15 @@ while (message_queue_size) { size_t message_size; - CHECK(MessageInTransit::GetNextMessageSize( - message_queue_data, message_queue_size, &message_size)); + if (!MessageInTransit::GetNextMessageSize( + message_queue_data, message_queue_size, &message_size)) { + NOTREACHED() << "Couldn't read message size from serialized data."; + return nullptr; + } + if (message_size > message_queue_size) { + NOTREACHED() << "Invalid serialized message size."; + return nullptr; + } MessageInTransit::View message_view(message_size, message_queue_data); message_queue_size -= message_size; message_queue_data += message_size; @@ -333,14 +399,17 @@ return rv; } -MessagePipeDispatcher::MessagePipeDispatcher() +MessagePipeDispatcher::MessagePipeDispatcher(bool transferable) : channel_(nullptr), - serialized_(false), serialized_read_fds_length_(0u), serialized_write_fds_length_(0u), serialized_message_fds_length_(0u), + pipe_id_(0), + non_transferable_state_(WAITING_FOR_READ_OR_WRITE), + serialized_(false), calling_init_(false), - write_error_(false) { + write_error_(false), + transferable_(transferable) { } MessagePipeDispatcher::~MessagePipeDispatcher() { @@ -369,6 +438,16 @@ } void MessagePipeDispatcher::SerializeInternal() { + serialized_ = true; + if (!transferable_) { + CHECK(non_transferable_state_ == WAITING_FOR_READ_OR_WRITE) + << "Non transferable message pipe being sent after read/write. " + << "MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE must be used if " + << "the pipe can be sent after it's read or written."; + non_transferable_state_ = SERIALISED; + return; + } + // We need to stop watching handle immediately, even though not on IO thread, // so that other messages aren't read after this. std::vector<int> serialized_read_fds, serialized_write_fds; @@ -385,8 +464,6 @@ serialized_write_fds.end()); serialized_write_fds_length_ = serialized_write_fds.size(); channel_ = nullptr; - if (write_error) - write_error = true; } else { // It's valid that the other side wrote some data and closed its end. } @@ -441,20 +518,18 @@ all_platform_handles->at(i) = PlatformHandle(); } #endif + } serialized_message_queue_.insert( serialized_message_queue_.end(), static_cast<const char*>(message->transport_data()->buffer()), static_cast<const char*>(message->transport_data()->buffer()) + transport_data_buffer_size); - } } for (size_t i = 0; i < dispatchers.size(); ++i) dispatchers[i]->TransportEnded(); } - - serialized_ = true; } scoped_refptr<Dispatcher> @@ -463,21 +538,24 @@ SerializeInternal(); - // TODO(vtl): Currently, there are no options, so we just use - // |kDefaultCreateOptions|. Eventually, we'll have to duplicate the options - // too. - scoped_refptr<MessagePipeDispatcher> rv = Create(kDefaultCreateOptions); - rv->serialized_platform_handle_ = serialized_platform_handle_.Pass(); - serialized_message_queue_.swap(rv->serialized_message_queue_); - serialized_read_buffer_.swap(rv->serialized_read_buffer_); - serialized_write_buffer_.swap(rv->serialized_write_buffer_); - serialized_fds_.swap(rv->serialized_fds_); - rv->serialized_read_fds_length_ = serialized_read_fds_length_; - rv->serialized_write_fds_length_ = serialized_write_fds_length_; - rv->serialized_message_fds_length_ = serialized_message_fds_length_; + scoped_refptr<MessagePipeDispatcher> rv( + new MessagePipeDispatcher(transferable_)); rv->serialized_ = true; - rv->write_error_ = write_error_; - return scoped_refptr<Dispatcher>(rv.get()); + if (transferable_) { + rv->serialized_platform_handle_ = serialized_platform_handle_.Pass(); + serialized_message_queue_.swap(rv->serialized_message_queue_); + serialized_read_buffer_.swap(rv->serialized_read_buffer_); + serialized_write_buffer_.swap(rv->serialized_write_buffer_); + serialized_fds_.swap(rv->serialized_fds_); + rv->serialized_read_fds_length_ = serialized_read_fds_length_; + rv->serialized_write_fds_length_ = serialized_write_fds_length_; + rv->serialized_message_fds_length_ = serialized_message_fds_length_; + rv->write_error_ = write_error_; + } else { + rv->pipe_id_ = pipe_id_; + rv->non_transferable_state_ = non_transferable_state_; + } + return rv; } MojoResult MessagePipeDispatcher::WriteMessageImplNoLock( @@ -485,15 +563,17 @@ uint32_t num_bytes, std::vector<DispatcherTransport>* transports, MojoWriteMessageFlags flags) { + lock().AssertAcquired(); DCHECK(!transports || (transports->size() > 0 && transports->size() <= GetConfiguration().max_message_num_handles)); - lock().AssertAcquired(); - - if (!channel_ || write_error_) + if (write_error_ || + (transferable_ && !channel_) || + (!transferable_ && non_transferable_state_ == CLOSED)) { return MOJO_RESULT_FAILED_PRECONDITION; + } if (num_bytes > GetConfiguration().max_message_num_bytes) return MOJO_RESULT_RESOURCE_EXHAUSTED; @@ -506,7 +586,17 @@ } message->SerializeAndCloseDispatchers(); - channel_->WriteMessage(message.Pass()); + if (!transferable_) + message->set_route_id(pipe_id_); + if (!transferable_ && + (non_transferable_state_ == WAITING_FOR_READ_OR_WRITE || + non_transferable_state_ == CONNECT_CALLED)) { + if (non_transferable_state_ == WAITING_FOR_READ_OR_WRITE) + RequestNontransferableChannel(); + non_transferable_outgoing_message_queue_.AddMessage(message.Pass()); + } else { + channel_->WriteMessage(message.Pass()); + } return MOJO_RESULT_OK; } @@ -518,8 +608,17 @@ uint32_t* num_dispatchers, MojoReadMessageFlags flags) { lock().AssertAcquired(); - if (channel_) + if (channel_) { channel_->EnsureLazyInitialized(); + } else if (!transferable_) { + if (non_transferable_state_ == WAITING_FOR_READ_OR_WRITE) { + RequestNontransferableChannel(); + return MOJO_RESULT_SHOULD_WAIT; + } else if (non_transferable_state_ == CONNECT_CALLED) { + return MOJO_RESULT_SHOULD_WAIT; + } + } + DCHECK(!dispatchers || dispatchers->empty()); const uint32_t max_bytes = !num_bytes ? 0 : *num_bytes; @@ -583,14 +682,22 @@ HandleSignalsState rv; if (!message_queue_.IsEmpty()) rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_READABLE; - if (channel_ || !message_queue_.IsEmpty()) + if (!message_queue_.IsEmpty() || + (transferable_ && channel_) || + (!transferable_ && non_transferable_state_ != CLOSED)) rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE; - if (channel_ && !write_error_) { + if (!write_error_ && + ((transferable_ && channel_) || + (!transferable_ && non_transferable_state_ != CLOSED))) { rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_WRITABLE; rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_WRITABLE; } - if (!channel_ || write_error_) + if (write_error_ || + (transferable_ && !channel_) || + (!transferable_ && + ((non_transferable_state_ == CLOSED) || is_closed()))) { rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; + } rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; return rv; } @@ -601,8 +708,13 @@ uintptr_t context, HandleSignalsState* signals_state) { lock().AssertAcquired(); - if (channel_) + if (channel_) { channel_->EnsureLazyInitialized(); + } else if (!transferable_ && + non_transferable_state_ == WAITING_FOR_READ_OR_WRITE) { + RequestNontransferableChannel(); + } + HandleSignalsState state = GetHandleSignalsStateImplNoLock(); if (state.satisfies(signals)) { if (signals_state) @@ -653,6 +765,8 @@ CloseImplNoLock(); SerializedMessagePipeHandleDispatcher* serialization = static_cast<SerializedMessagePipeHandleDispatcher*>(destination); + serialization->transferable = transferable_; + serialization->pipe_id = pipe_id_; if (serialized_platform_handle_.is_valid()) { serialization->platform_handle_index = platform_handles->size(); platform_handles->push_back(serialized_platform_handle_.release()); @@ -796,7 +910,18 @@ // called, that is safe since this class always does a PostTask to the IO // thread to self destruct. if (channel_ && error != ERROR_WRITE) { - channel_->Shutdown(); + if (transferable_) { + channel_->Shutdown(); + } else { + CHECK_NE(non_transferable_state_, CLOSED); + // Since we're in a callback from the Broker, call it asynchronously. + internal::g_io_thread_task_runner->PostTask( + FROM_HERE, + base::Bind(&Broker::CloseMessagePipe, + base::Unretained(internal::g_broker), pipe_id_, + base::Unretained(this))); + non_transferable_state_ = CLOSED; + } channel_ = nullptr; } awakable_list_.AwakeForStateChange(GetHandleSignalsStateImplNoLock()); @@ -824,10 +949,14 @@ if ((*transports)[i].GetType() == Dispatcher::Type::MESSAGE_PIPE) { MessagePipeDispatcher* mp = static_cast<MessagePipeDispatcher*>(((*transports)[i]).dispatcher()); - if (channel_ && mp->channel_ && channel_->IsOtherEndOf(mp->channel_)) { + if (transferable_ && mp->transferable_ && + channel_ && mp->channel_ && channel_->IsOtherEndOf(mp->channel_)) { // The other case should have been disallowed by |Core|. (Note: |port| // is the peer port of the handle given to |WriteMessage()|.) return MOJO_RESULT_INVALID_ARGUMENT; + } else if (!transferable_ && !mp->transferable_ && + pipe_id_ == mp->pipe_id_) { + return MOJO_RESULT_INVALID_ARGUMENT; } } } @@ -849,5 +978,19 @@ return MOJO_RESULT_OK; } +void MessagePipeDispatcher::RequestNontransferableChannel() { + lock().AssertAcquired(); + CHECK(!transferable_); + CHECK_EQ(non_transferable_state_, WAITING_FOR_READ_OR_WRITE); + non_transferable_state_ = CONNECT_CALLED; + + // PostTask since the broker can call us back synchronously. + internal::g_io_thread_task_runner->PostTask( + FROM_HERE, + base::Bind(&Broker::ConnectMessagePipe, + base::Unretained(internal::g_broker), pipe_id_, + base::Unretained(this))); +} + } // namespace edk } // namespace mojo
diff --git a/mojo/edk/system/message_pipe_dispatcher.h b/mojo/edk/system/message_pipe_dispatcher.h index 5248583..d70d3bc 100644 --- a/mojo/edk/system/message_pipe_dispatcher.h +++ b/mojo/edk/system/message_pipe_dispatcher.h
@@ -9,6 +9,7 @@ #include "mojo/edk/embedder/platform_channel_pair.h" #include "mojo/edk/system/awakable_list.h" #include "mojo/edk/system/dispatcher.h" +#include "mojo/edk/system/message_in_transit_queue.h" #include "mojo/edk/system/raw_channel.h" #include "mojo/edk/system/system_impl_export.h" #include "mojo/public/cpp/system/macros.h" @@ -27,8 +28,10 @@ static const MojoCreateMessagePipeOptions kDefaultCreateOptions; static scoped_refptr<MessagePipeDispatcher> Create( - const MojoCreateMessagePipeOptions& /*validated_options*/) { - return make_scoped_refptr(new MessagePipeDispatcher()); + const MojoCreateMessagePipeOptions& validated_options) { + return make_scoped_refptr(new MessagePipeDispatcher( + !!(validated_options.flags & + MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE))); } // Validates and/or sets default options for |MojoCreateMessagePipeOptions|. @@ -40,6 +43,7 @@ const MojoCreateMessagePipeOptions* in_options, MojoCreateMessagePipeOptions* out_options); + // Initializes a transferable message pipe. // Must be called before any other methods. (This method is not thread-safe.) void Init( ScopedPlatformHandle message_pipe, @@ -48,9 +52,24 @@ std::vector<int>* serialized_read_fds, std::vector<int>* serialized_write_fds); + // Initializes a nontransferable message pipe. + void InitNonTransferable(uint64_t pipe_id); + // |Dispatcher| public methods: Type GetType() const override; + // RawChannel::Delegate methods: + void OnReadMessage( + const MessageInTransit::View& message_view, + ScopedPlatformHandleVectorPtr platform_handles) override; + void OnError(Error error) override; + + // Called by broker when a route is established between this + // MessagePipeDispatcher and another one. This object will receive messages + // sent to its pipe_id. It should tag all outgoing messages by calling + // MessageInTransit::set_route_id with pipe_id_. + void GotNonTransferableChannel(RawChannel* channel); + // The "opposite" of |SerializeAndClose()|. (Typically this is called by // |Dispatcher::Deserialize()|.) static scoped_refptr<MessagePipeDispatcher> Deserialize( @@ -59,7 +78,9 @@ PlatformHandleVector* platform_handles); private: - MessagePipeDispatcher(); + // See MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE's definition for an + // explanation of what is a transferable pipe. + explicit MessagePipeDispatcher(bool transferable); ~MessagePipeDispatcher() override; void InitOnIO(); @@ -96,12 +117,6 @@ void TransportStarted() override; void TransportEnded() override; - // |RawChannel::Delegate methods: - void OnReadMessage( - const MessageInTransit::View& message_view, - ScopedPlatformHandleVectorPtr platform_handles) override; - void OnError(Error error) override; - // Calls ReleaseHandle and serializes the raw channel. This is split into a // function because it's called in two different ways: // 1) When serializing "live" dispatchers that are passed to MojoWriteMessage, @@ -115,14 +130,20 @@ MessageInTransit* message, std::vector<DispatcherTransport>* transports); + // Called whenever a read or write is done on a non-transferable pipe, which + // "binds" the pipe id to this object. + void RequestNontransferableChannel(); + // Protected by |lock()|: RawChannel* channel_; // Queue of incoming messages that we read from RawChannel but haven't been // consumed through MojoReadMessage yet. MessageInTransitQueue message_queue_; + + // The following members are only used when transferable_ is false; + // When sending MP, contains serialized message_queue_. - bool serialized_; std::vector<char> serialized_message_queue_; std::vector<char> serialized_read_buffer_; std::vector<char> serialized_write_buffer_; @@ -133,14 +154,40 @@ size_t serialized_write_fds_length_; size_t serialized_message_fds_length_; ScopedPlatformHandle serialized_platform_handle_; + + // The following members are only used when transferable_ is true; + + // The unique id shared by both ends of a non-transferable message pipe. This + // is held on until a read or write are done, and at that point it's used to + // get a RawChannel. + uint64_t pipe_id_; + enum NonTransferableState { + WAITING_FOR_READ_OR_WRITE, + CONNECT_CALLED, + CONNECTED, + WAITING_FOR_CONNECT_TO_CLOSE, + CLOSED, + SERIALISED, + }; + + NonTransferableState non_transferable_state_; + // Messages that were written while we were waiting to get a RawChannel. + MessageInTransitQueue non_transferable_outgoing_message_queue_; + + + // The following members are used for both modes of transferable_. + AwakableList awakable_list_; // If DispatcherTransport is created. Must be set before lock() is called to // avoid deadlocks with RawChannel calling us. base::Lock started_transport_; + bool serialized_; bool calling_init_; bool write_error_; + // Whether it can be sent after read or write. + bool transferable_; MOJO_DISALLOW_COPY_AND_ASSIGN(MessagePipeDispatcher); };
diff --git a/mojo/edk/system/message_pipe_perftest.cc b/mojo/edk/system/message_pipe_perftest.cc index 5d59e656..e89143b9 100644 --- a/mojo/edk/system/message_pipe_perftest.cc +++ b/mojo/edk/system/message_pipe_perftest.cc
@@ -24,8 +24,7 @@ : public test::MultiprocessMessagePipeTestBase { public: MultiprocessMessagePipePerfTest() - : test::MultiprocessMessagePipeTestBase(base::MessageLoop::TYPE_IO), - message_count_(0), + : message_count_(0), message_size_(0) {} void SetUpMeasurement(int message_count, size_t message_size) { @@ -86,11 +85,6 @@ // (which it doesn't reply to). It'll return the number of messages received, // not including any "quitquitquit" message, modulo 100. MOJO_MULTIPROCESS_TEST_CHILD_MAIN(PingPongClient) { - SimplePlatformSupport platform_support; - base::MessageLoop message_loop(base::MessageLoop::TYPE_IO); - base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart); - test::ScopedIPCSupport ipc_support(test_io_thread.task_runner()); - ScopedPlatformHandle client_platform_handle = test::MultiprocessTestHelper::client_platform_handle.Pass(); CHECK(client_platform_handle.is_valid());
diff --git a/mojo/edk/system/message_pipe_test_utils.cc b/mojo/edk/system/message_pipe_test_utils.cc index 1e337fb..c752abc 100644 --- a/mojo/edk/system/message_pipe_test_utils.cc +++ b/mojo/edk/system/message_pipe_test_utils.cc
@@ -11,16 +11,7 @@ namespace test { #if !defined(OS_IOS) -MultiprocessMessagePipeTestBase::MultiprocessMessagePipeTestBase() - : test_io_thread_(base::TestIOThread::kAutoStart), - ipc_support_(test_io_thread_.task_runner()) { -} - -MultiprocessMessagePipeTestBase::MultiprocessMessagePipeTestBase( - base::MessageLoop::Type main_message_loop_type) - : message_loop_(main_message_loop_type), - test_io_thread_(base::TestIOThread::kAutoStart), - ipc_support_(test_io_thread_.task_runner()) { +MultiprocessMessagePipeTestBase::MultiprocessMessagePipeTestBase() { } MultiprocessMessagePipeTestBase::~MultiprocessMessagePipeTestBase() {
diff --git a/mojo/edk/system/message_pipe_test_utils.h b/mojo/edk/system/message_pipe_test_utils.h index e067329d..837d534a6 100644 --- a/mojo/edk/system/message_pipe_test_utils.h +++ b/mojo/edk/system/message_pipe_test_utils.h
@@ -5,12 +5,7 @@ #ifndef MOJO_EDK_SYSTEM_MESSAGE_PIPE_TEST_UTILS_H_ #define MOJO_EDK_SYSTEM_MESSAGE_PIPE_TEST_UTILS_H_ -#include "base/message_loop/message_loop.h" -#include "base/test/test_io_thread.h" -#include "mojo/edk/embedder/simple_platform_support.h" -#include "mojo/edk/system/test_utils.h" #include "mojo/edk/test/multiprocess_test_helper.h" -#include "mojo/edk/test/scoped_ipc_support.h" #include "mojo/public/cpp/system/macros.h" namespace mojo { @@ -25,19 +20,12 @@ class MultiprocessMessagePipeTestBase : public testing::Test { public: MultiprocessMessagePipeTestBase(); - MultiprocessMessagePipeTestBase( - base::MessageLoop::Type main_message_loop_type); ~MultiprocessMessagePipeTestBase() override; protected: - PlatformSupport* platform_support() { return &platform_support_; } test::MultiprocessTestHelper* helper() { return &helper_; } private: - SimplePlatformSupport platform_support_; - base::MessageLoop message_loop_; - base::TestIOThread test_io_thread_; - test::ScopedIPCSupport ipc_support_; test::MultiprocessTestHelper helper_; MOJO_DISALLOW_COPY_AND_ASSIGN(MultiprocessMessagePipeTestBase);
diff --git a/mojo/edk/system/message_pipe_unittest.cc b/mojo/edk/system/message_pipe_unittest.cc index 9283acc..0498b55 100644 --- a/mojo/edk/system/message_pipe_unittest.cc +++ b/mojo/edk/system/message_pipe_unittest.cc
@@ -16,7 +16,7 @@ MOJO_HANDLE_SIGNAL_PEER_CLOSED; static const char kHelloWorld[] = "hello world"; -class MessagePipeTest : public test::MojoSystemTest { +class MessagePipeTest : public testing::Test { public: MessagePipeTest() { CHECK_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &pipe0_, &pipe1_));
diff --git a/mojo/edk/system/multiprocess_message_pipe_unittest.cc b/mojo/edk/system/multiprocess_message_pipe_unittest.cc index 4bb3f133..f1afa0e1 100644 --- a/mojo/edk/system/multiprocess_message_pipe_unittest.cc +++ b/mojo/edk/system/multiprocess_message_pipe_unittest.cc
@@ -16,8 +16,7 @@ #include "base/files/scoped_temp_dir.h" #include "base/location.h" #include "base/logging.h" -#include "base/test/test_io_thread.h" -#include "build/build_config.h" // TODO(vtl): Remove this. +#include "build/build_config.h" #include "mojo/edk/embedder/embedder.h" #include "mojo/edk/embedder/platform_channel_pair.h" #include "mojo/edk/embedder/platform_shared_buffer.h" @@ -44,11 +43,6 @@ // (which it doesn't reply to). It'll return the number of messages received, // not including any "quitquitquit" message, modulo 100. MOJO_MULTIPROCESS_TEST_CHILD_MAIN(EchoEcho) { - SimplePlatformSupport platform_support; - base::MessageLoop message_loop; - base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart); - test::ScopedIPCSupport ipc_support(test_io_thread.task_runner()); - ScopedPlatformHandle client_platform_handle = test::MultiprocessTestHelper::client_platform_handle.Pass(); CHECK(client_platform_handle.is_valid()); @@ -208,11 +202,6 @@ } MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckSharedBuffer) { - SimplePlatformSupport platform_support; - base::MessageLoop message_loop; - base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart); - test::ScopedIPCSupport ipc_support(test_io_thread.task_runner()); - ScopedPlatformHandle client_platform_handle = test::MultiprocessTestHelper::client_platform_handle.Pass(); CHECK(client_platform_handle.is_valid()); @@ -382,11 +371,6 @@ } MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckPlatformHandleFile) { - SimplePlatformSupport platform_support; - base::MessageLoop message_loop; - base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart); - test::ScopedIPCSupport ipc_support(test_io_thread.task_runner()); - ScopedPlatformHandle client_platform_handle = test::MultiprocessTestHelper::client_platform_handle.Pass(); CHECK(client_platform_handle.is_valid()); @@ -501,11 +485,6 @@ #endif MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckMessagePipe) { - SimplePlatformSupport platform_support; - base::MessageLoop message_loop; - base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart); - test::ScopedIPCSupport ipc_support(test_io_thread.task_runner()); - ScopedPlatformHandle client_platform_handle = test::MultiprocessTestHelper::client_platform_handle.Pass(); CHECK(client_platform_handle.is_valid()); @@ -666,11 +645,6 @@ } MOJO_MULTIPROCESS_TEST_CHILD_MAIN(DataPipeConsumer) { - SimplePlatformSupport platform_support; - base::MessageLoop message_loop; - base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart); - test::ScopedIPCSupport ipc_support(test_io_thread.task_runner()); - ScopedPlatformHandle client_platform_handle = test::MultiprocessTestHelper::client_platform_handle.Pass(); CHECK(client_platform_handle.is_valid());
diff --git a/mojo/edk/system/raw_channel_unittest.cc b/mojo/edk/system/raw_channel_unittest.cc index fdc77d8..c2298d6 100644 --- a/mojo/edk/system/raw_channel_unittest.cc +++ b/mojo/edk/system/raw_channel_unittest.cc
@@ -23,7 +23,9 @@ #include "base/synchronization/waitable_event.h" #include "base/test/test_io_thread.h" #include "base/threading/simple_thread.h" -#include "build/build_config.h" // TODO(vtl): Remove this. +#include "build/build_config.h" +#include "mojo/edk/embedder/embedder.h" +#include "mojo/edk/embedder/embedder_internal.h" #include "mojo/edk/embedder/platform_channel_pair.h" #include "mojo/edk/embedder/platform_handle.h" #include "mojo/edk/embedder/scoped_platform_handle.h" @@ -73,7 +75,7 @@ // ----------------------------------------------------------------------------- -class RawChannelTest : public test::MojoSystemTest { +class RawChannelTest : public testing::Test { public: RawChannelTest() {} ~RawChannelTest() override {} @@ -89,6 +91,14 @@ handles[1].reset(); } + void FlushIOThread() { + base::WaitableEvent event(false, false); + internal::g_io_thread_task_runner->PostTask( + FROM_HERE, + base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event))); + event.Wait(); + } + protected: ScopedPlatformHandle handles[2]; @@ -189,7 +199,7 @@ WriteOnlyRawChannelDelegate delegate; RawChannel* rc = RawChannel::Create(handles[0].Pass()); TestMessageReaderAndChecker checker(handles[1].get()); - test_io_thread()->PostTaskAndWait( + internal::g_io_thread_task_runner->PostTask( FROM_HERE, base::Bind(&InitOnIOThread, rc, base::Unretained(&delegate))); @@ -205,7 +215,7 @@ for (uint32_t size = 1; size < 5 * 1000 * 1000; size += size / 2 + 1) EXPECT_TRUE(checker.ReadAndCheckNextMessage(size)) << size; - test_io_thread()->PostTaskAndWait( + internal::g_io_thread_task_runner->PostTask( FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(rc))); } @@ -274,7 +284,7 @@ TEST_F(RawChannelTest, OnReadMessage) { ReadCheckerRawChannelDelegate delegate; RawChannel* rc = RawChannel::Create(handles[0].Pass()); - test_io_thread()->PostTaskAndWait( + internal::g_io_thread_task_runner->PostTask( FROM_HERE, base::Bind(&InitOnIOThread, rc, base::Unretained(&delegate))); @@ -297,7 +307,7 @@ EXPECT_TRUE(WriteTestMessageToHandle(handles[1].get(), size)); delegate.Wait(); - test_io_thread()->PostTaskAndWait( + internal::g_io_thread_task_runner->PostTask( FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(rc))); } @@ -371,7 +381,7 @@ WriteOnlyRawChannelDelegate writer_delegate; RawChannel* writer_rc = RawChannel::Create(handles[0].Pass()); - test_io_thread()->PostTaskAndWait( + internal::g_io_thread_task_runner->PostTask( FROM_HERE, base::Bind(&InitOnIOThread, writer_rc, base::Unretained(&writer_delegate))); @@ -379,7 +389,7 @@ ReadCountdownRawChannelDelegate reader_delegate(kNumWriterThreads * kNumWriteMessagesPerThread); RawChannel* reader_rc = RawChannel::Create(handles[1].Pass()); - test_io_thread()->PostTaskAndWait( + internal::g_io_thread_task_runner->PostTask( FROM_HERE, base::Bind(&InitOnIOThread, reader_rc, base::Unretained(&reader_delegate))); @@ -401,11 +411,11 @@ // Wait for reading to finish. reader_delegate.Wait(); - test_io_thread()->PostTaskAndWait( + internal::g_io_thread_task_runner->PostTask( FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(reader_rc))); - test_io_thread()->PostTaskAndWait( + internal::g_io_thread_task_runner->PostTask( FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(writer_rc))); } @@ -470,9 +480,10 @@ TEST_F(RawChannelTest, OnError) { ErrorRecordingRawChannelDelegate delegate(0, true, true); RawChannel* rc = RawChannel::Create(handles[0].Pass()); - test_io_thread()->PostTaskAndWait( + internal::g_io_thread_task_runner->PostTask( FROM_HERE, base::Bind(&InitOnIOThread, rc, base::Unretained(&delegate))); + FlushIOThread(); // Close the handle of the other end, which should make writing fail. handles[1].reset(); @@ -491,7 +502,7 @@ // notification. (If we actually get another one, |OnError()| crashes.) test::Sleep(test::DeadlineFromMilliseconds(20)); - test_io_thread()->PostTaskAndWait( + internal::g_io_thread_task_runner->PostTask( FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(rc))); } @@ -513,9 +524,10 @@ // messages that were written. ErrorRecordingRawChannelDelegate delegate(kMessageCount, true, true); RawChannel* rc = RawChannel::Create(handles[0].Pass()); - test_io_thread()->PostTaskAndWait( + internal::g_io_thread_task_runner->PostTask( FROM_HERE, base::Bind(&InitOnIOThread, rc, base::Unretained(&delegate))); + FlushIOThread(); EXPECT_FALSE(rc->WriteMessage(MakeTestMessage(1))); @@ -528,7 +540,7 @@ // And then we should get a read error. delegate.WaitForReadError(); - test_io_thread()->PostTaskAndWait( + internal::g_io_thread_task_runner->PostTask( FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(rc))); } @@ -597,13 +609,13 @@ WriteOnlyRawChannelDelegate write_delegate; RawChannel* rc_write = RawChannel::Create(handles[0].Pass()); - test_io_thread()->PostTaskAndWait( + internal::g_io_thread_task_runner->PostTask( FROM_HERE, base::Bind(&InitOnIOThread, rc_write, base::Unretained(&write_delegate))); ReadPlatformHandlesCheckerRawChannelDelegate read_delegate; RawChannel* rc_read = RawChannel::Create(handles[1].Pass()); - test_io_thread()->PostTaskAndWait( + internal::g_io_thread_task_runner->PostTask( FROM_HERE, base::Bind(&InitOnIOThread, rc_read, base::Unretained(&read_delegate))); @@ -633,10 +645,10 @@ read_delegate.Wait(); - test_io_thread()->PostTaskAndWait( + internal::g_io_thread_task_runner->PostTask( FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(rc_read))); - test_io_thread()->PostTaskAndWait( + internal::g_io_thread_task_runner->PostTask( FROM_HERE, base::Bind(&RawChannel::Shutdown, base::Unretained(rc_write))); }
diff --git a/mojo/edk/system/routed_raw_channel.cc b/mojo/edk/system/routed_raw_channel.cc new file mode 100644 index 0000000..e2fe67e --- /dev/null +++ b/mojo/edk/system/routed_raw_channel.cc
@@ -0,0 +1,168 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/edk/system/routed_raw_channel.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "mojo/edk/embedder/embedder_internal.h" +#include "mojo/edk/system/message_pipe_dispatcher.h" + +namespace mojo { +namespace edk { + +namespace { +const uint64_t kInternalRoutingId = 0; + +// These are messages sent over our internal routing id above, meant for the +// other side's RoutedRawChannel to dispatch. +enum InternalMessages { + ROUTE_CLOSED = 0, +}; +} + +RoutedRawChannel::PendingMessage::PendingMessage() { +} + +RoutedRawChannel::PendingMessage::~PendingMessage() { +} + +RoutedRawChannel::RoutedRawChannel( + ScopedPlatformHandle handle, + const base::Callback<void(RoutedRawChannel*)>& destruct_callback) + : channel_(RawChannel::Create(handle.Pass())), + destruct_callback_(destruct_callback) { + internal::g_io_thread_task_runner->PostTask( + FROM_HERE, + base::Bind(&RawChannel::Init, base::Unretained(channel_), this)); + internal::g_io_thread_task_runner->PostTask( + FROM_HERE, + base::Bind(&RawChannel::EnsureLazyInitialized, + base::Unretained(channel_))); +} + +void RoutedRawChannel::AddRoute(uint64_t pipe_id, MessagePipeDispatcher* pipe) { + CHECK_NE(pipe_id, kInternalRoutingId) << kInternalRoutingId << " is reserved"; + base::AutoLock auto_lock(lock_); + CHECK(routes_.find(pipe_id) == routes_.end()); + routes_[pipe_id] = pipe; + + for (size_t i = 0; i < pending_messages_.size();) { + MessageInTransit::View view(pending_messages_[i]->message.size(), + &pending_messages_[i]->message[0]); + if (view.route_id() == pipe_id) { + pipe->OnReadMessage(view, pending_messages_[i]->handles.Pass()); + pending_messages_.erase(pending_messages_.begin() + i); + } else { + ++i; + } + } + + if (close_routes_.find(pipe_id) != close_routes_.end()) + pipe->OnError(ERROR_READ_SHUTDOWN); +} + +void RoutedRawChannel::RemoveRoute(uint64_t pipe_id, + MessagePipeDispatcher* pipe) { + base::AutoLock auto_lock(lock_); + CHECK(routes_.find(pipe_id) != routes_.end()); + CHECK_EQ(routes_[pipe_id], pipe); + routes_.erase(pipe_id); + + // Only send a message to the other side to close the route if we hadn't + // received a close route message. Otherwise they would keep going back and + // forth. + if (close_routes_.find(pipe_id) != close_routes_.end()) { + close_routes_.erase(pipe_id); + } else if (channel_) { + // Default route id of 0 to reach the other side's RoutedRawChannel. + char message_data[sizeof(char) + sizeof(uint64_t)]; + message_data[0] = ROUTE_CLOSED; + memcpy(&message_data[1], &pipe_id, sizeof(uint64_t)); + scoped_ptr<MessageInTransit> message(new MessageInTransit( + MessageInTransit::Type::MESSAGE, arraysize(message_data), + message_data)); + message->set_route_id(kInternalRoutingId); + channel_->WriteMessage(message.Pass()); + } + + if (!channel_ && routes_.empty()) { + // PostTask to avoid reentrancy since the broker might be calling us. + base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); + } +} + +RoutedRawChannel::~RoutedRawChannel() { + destruct_callback_.Run(this); +} + +void RoutedRawChannel::OnReadMessage( + const MessageInTransit::View& message_view, + ScopedPlatformHandleVectorPtr platform_handles) { + DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); + // Note: normally, when a message arrives here we should find a corresponding + // entry for the MessagePipeDispatcher with the given route_id. However it is + // possible that they just connected, and due to race conditions one side has + // connected and sent a message (and even closed) before the other side had a + // chance to register with this RoutedRawChannel. In that case, we must buffer + // all messages. + base::AutoLock auto_lock(lock_); + uint64_t route_id = message_view.route_id(); + if (route_id == kInternalRoutingId) { + if (message_view.num_bytes() != sizeof(char) + sizeof(uint64_t)) { + NOTREACHED() << "Invalid internal message in RoutedRawChannel."; + return; + } + const char* bytes = static_cast<const char*>(message_view.bytes()); + if (bytes[0] != ROUTE_CLOSED) { + NOTREACHED() << "Unknown internal message in RoutedRawChannel."; + return; + } + uint64_t closed_route = *reinterpret_cast<const uint64_t*>(&bytes[1]); + if (close_routes_.find(closed_route) != close_routes_.end()) { + NOTREACHED() << "Should only receive one ROUTE_CLOSED per route."; + return; + } + close_routes_.insert(closed_route); + if (routes_.find(closed_route) == routes_.end()) + return; // This side hasn't connected yet. + + routes_[closed_route]->OnError(ERROR_READ_SHUTDOWN); + return; + } + + if (routes_.find(route_id) != routes_.end()) { + routes_[route_id]->OnReadMessage(message_view, platform_handles.Pass()); + } else { + scoped_ptr<PendingMessage> msg(new PendingMessage); + msg->message.resize(message_view.total_size()); + memcpy(&msg->message[0], message_view.main_buffer(), + message_view.total_size()); + msg->handles = platform_handles.Pass(); + pending_messages_.push_back(msg.Pass()); + } +} + +void RoutedRawChannel::OnError(Error error) { + DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()); + bool destruct = false; + { + base::AutoLock auto_lock(lock_); + + channel_->Shutdown(); + channel_ = nullptr; + if (routes_.empty()) { + destruct = true; + } else { + for (auto it = routes_.begin(); it != routes_.end(); ++it) + it->second->OnError(error); + } + } + + if (destruct) + delete this; +} + +} // namespace edk +} // namespace mojo
diff --git a/mojo/edk/system/routed_raw_channel.h b/mojo/edk/system/routed_raw_channel.h new file mode 100644 index 0000000..c27b86c --- /dev/null +++ b/mojo/edk/system/routed_raw_channel.h
@@ -0,0 +1,78 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_EDK_SYSTEM_ROUTED_RAW_CHANNEL_H_ +#define MOJO_EDK_SYSTEM_ROUTED_RAW_CHANNEL_H_ + +#include "base/callback.h" +#include "base/containers/hash_tables.h" +#include "base/macros.h" +#include "base/synchronization/lock.h" +#include "mojo/edk/embedder/platform_handle_vector.h" +#include "mojo/edk/embedder/scoped_platform_handle.h" +#include "mojo/edk/system/broker.h" +#include "mojo/edk/system/raw_channel.h" +#include "mojo/edk/system/system_impl_export.h" + +namespace mojo { +namespace edk { +class RawChannel; + +// This class wraps a RawChannel and adds routing on top of it. +// Non-transferable MessagePipeDispatchers call here, indirectly through the +// Broker interface, to associate with their pipe_id. +class RoutedRawChannel : public RawChannel::Delegate { + public: + RoutedRawChannel( + ScopedPlatformHandle handle, + const base::Callback<void(RoutedRawChannel*)>& destruct_callback); + + // Connect the given |pipe| with the pipe_id route. Only non-transferable + // message pipes can call this, and they can only call it once. + void AddRoute(uint64_t pipe_id, MessagePipeDispatcher* pipe); + + // Called when the MessagePipeDispatcher is going away. + void RemoveRoute(uint64_t pipe_id, MessagePipeDispatcher* pipe); + + RawChannel* channel() { return channel_; } + + private: + friend class base::DeleteHelper<RoutedRawChannel>; + ~RoutedRawChannel() override; + + // RawChannel::Delegate implementation: + void OnReadMessage( + const MessageInTransit::View& message_view, + ScopedPlatformHandleVectorPtr platform_handles) override; + void OnError(Error error) override; + + RawChannel* channel_; + + base::Lock lock_; // Guards access to below. + base::hash_map<uint64_t, MessagePipeDispatcher*> routes_; + + // If we got messages before the route was added (due to race conditions + // between different channels), this is used to buffer them. + struct PendingMessage { + PendingMessage(); + ~PendingMessage(); + std::vector<char> message; + ScopedPlatformHandleVectorPtr handles; + }; + std::vector<scoped_ptr<PendingMessage>> pending_messages_; + + // If we got a ROUTE_CLOSED message for a route before it registered with us, + // we need to hold on to this information so that we can tell it that the + // connetion is closed when it does connect. + base::hash_set<uint64_t> close_routes_; + + base::Callback<void(RoutedRawChannel*)> destruct_callback_; + + DISALLOW_COPY_AND_ASSIGN(RoutedRawChannel); +}; + +} // namespace edk +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_ROUTED_RAW_CHANNEL_H_
diff --git a/mojo/edk/system/run_all_unittests.cc b/mojo/edk/system/run_all_unittests.cc index b68fd83..4421aa6 100644 --- a/mojo/edk/system/run_all_unittests.cc +++ b/mojo/edk/system/run_all_unittests.cc
@@ -5,9 +5,11 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/test/launcher/unit_test_launcher.h" +#include "base/test/test_io_thread.h" #include "base/test/test_suite.h" #include "mojo/edk/embedder/embedder.h" #include "mojo/edk/test/multiprocess_test_helper.h" +#include "mojo/edk/test/scoped_ipc_support.h" #include "testing/gtest/include/gtest/gtest.h" int main(int argc, char** argv) { @@ -31,6 +33,12 @@ mojo::edk::Init(); + base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart); + // Leak this because its destructor calls mojo::edk::ShutdownIPCSupport which + // really does nothing in the new EDK but does depend on the current message + // loop, which is destructed inside base::LaunchUnitTests. + new mojo::edk::test::ScopedIPCSupport(test_io_thread.task_runner()); + return base::LaunchUnitTests( argc, argv, base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
diff --git a/mojo/edk/system/test_utils.cc b/mojo/edk/system/test_utils.cc index 49e346b..0549f86 100644 --- a/mojo/edk/system/test_utils.cc +++ b/mojo/edk/system/test_utils.cc
@@ -69,15 +69,6 @@ return static_cast<MojoDeadline>(result); } - -MojoSystemTest::MojoSystemTest() - : test_io_thread_(base::TestIOThread::kAutoStart), - ipc_support_(test_io_thread_.task_runner()) { -} - -MojoSystemTest::~MojoSystemTest() { -} - } // namespace test } // namespace edk } // namespace mojo
diff --git a/mojo/edk/system/test_utils.h b/mojo/edk/system/test_utils.h index cf244b3..46398d9 100644 --- a/mojo/edk/system/test_utils.h +++ b/mojo/edk/system/test_utils.h
@@ -5,9 +5,7 @@ #ifndef MOJO_EDK_SYSTEM_TEST_UTILS_H_ #define MOJO_EDK_SYSTEM_TEST_UTILS_H_ -#include "base/test/test_io_thread.h" #include "base/time/time.h" -#include "mojo/edk/test/scoped_ipc_support.h" #include "mojo/public/c/system/types.h" #include "mojo/public/cpp/system/macros.h" #include "testing/gtest/include/gtest/gtest.h" @@ -54,23 +52,6 @@ MOJO_DISALLOW_COPY_AND_ASSIGN(Stopwatch); }; -// A base class which initializes and shuts down the necessary objects so that -// Mojo system calls can be made. -class MojoSystemTest : public testing::Test { - public: - MojoSystemTest(); - ~MojoSystemTest() override; - - base::TestIOThread* test_io_thread() { return &test_io_thread_; } - - private: - base::MessageLoop message_loop_; - base::TestIOThread test_io_thread_; - test::ScopedIPCSupport ipc_support_; - - MOJO_DISALLOW_COPY_AND_ASSIGN(MojoSystemTest); -}; - } // namespace test } // namespace edk } // namespace mojo
diff --git a/mojo/edk/test/BUILD.gn b/mojo/edk/test/BUILD.gn index 9a52c99..a77373b 100644 --- a/mojo/edk/test/BUILD.gn +++ b/mojo/edk/test/BUILD.gn
@@ -54,6 +54,7 @@ ":test_support_impl", "//base", "//base/test:test_support", + "//mojo/edk/test:test_support", "//mojo/public/c/test_support", # TODO(use_chrome_edk): temporary since the Mojo wrapper primitives are
diff --git a/mojo/edk/test/multiprocess_test_helper_unittest.cc b/mojo/edk/test/multiprocess_test_helper_unittest.cc index b3ae11d..7e99fb27a 100644 --- a/mojo/edk/test/multiprocess_test_helper_unittest.cc +++ b/mojo/edk/test/multiprocess_test_helper_unittest.cc
@@ -7,6 +7,7 @@ #include "base/logging.h" #include "build/build_config.h" #include "mojo/edk/embedder/scoped_platform_handle.h" +#include "mojo/edk/system/test_utils.h" #include "mojo/edk/test/test_utils.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/mojo/edk/test/run_all_perftests.cc b/mojo/edk/test/run_all_perftests.cc index d700bc3..c277a38 100644 --- a/mojo/edk/test/run_all_perftests.cc +++ b/mojo/edk/test/run_all_perftests.cc
@@ -4,17 +4,32 @@ #include "base/command_line.h" #include "base/test/perf_test_suite.h" +#include "base/test/test_io_thread.h" #include "mojo/edk/embedder/embedder.h" +#include "mojo/edk/test/multiprocess_test_helper.h" +#include "mojo/edk/test/scoped_ipc_support.h" #include "mojo/edk/test/test_support_impl.h" #include "mojo/public/tests/test_support_private.h" int main(int argc, char** argv) { - mojo::edk::Init(); - mojo::test::TestSupport::Init(new mojo::edk::test::TestSupportImpl()); + base::PerfTestSuite test(argc, argv); + + // Must be run before mojo::edk::Init. + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + mojo::edk::test::kBrokerHandleSwitch)) { + mojo::edk::PreInitializeChildProcess(); + } // TODO(use_chrome_edk): temporary to force new EDK. - base::PerfTestSuite test(argc, argv); base::CommandLine::ForCurrentProcess()->AppendSwitch("--use-new-edk"); + mojo::edk::Init(); + base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart); + // Leak this because its destructor calls mojo::edk::ShutdownIPCSupport which + // really does nothing in the new EDK but does depend on the current message + // loop, which is destructed inside base::LaunchUnitTests. + new mojo::edk::test::ScopedIPCSupport(test_io_thread.task_runner()); + mojo::test::TestSupport::Init(new mojo::edk::test::TestSupportImpl()); + return test.Run(); }
diff --git a/mojo/mojo_edk.gyp b/mojo/mojo_edk.gyp index 07edb34..a8cbc82 100644 --- a/mojo/mojo_edk.gyp +++ b/mojo/mojo_edk.gyp
@@ -105,6 +105,8 @@ 'edk/system/raw_channel.h', 'edk/system/raw_channel_posix.cc', 'edk/system/raw_channel_win.cc', + 'edk/system/routed_raw_channel.cc', + 'edk/system/routed_raw_channel.h', 'edk/system/shared_buffer_dispatcher.cc', 'edk/system/shared_buffer_dispatcher.h', 'edk/system/simple_dispatcher.cc',
diff --git a/mojo/public/c/system/message_pipe.h b/mojo/public/c/system/message_pipe.h index d42c3fc..4f5d4c78 100644 --- a/mojo/public/c/system/message_pipe.h +++ b/mojo/public/c/system/message_pipe.h
@@ -18,17 +18,26 @@ // |uint32_t struct_size|: Set to the size of the // |MojoCreateMessagePipeOptions| struct. (Used to allow for future // extensions.) -// |MojoCreateMessagePipeOptionsFlags flags|: Reserved for future use. +// |MojoCreateMessagePipeOptionsFlags flags|: Used to specify different modes +// of operation. // |MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE|: No flags; default mode. +// |MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE|: The message pipe +// can be sent over another pipe after it's been read, written or +// waited. This mode makes message pipes use more resources (one OS +// pipe each), so only specify if this functionality is required. typedef uint32_t MojoCreateMessagePipeOptionsFlags; #ifdef __cplusplus const MojoCreateMessagePipeOptionsFlags MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE = 0; +const MojoCreateMessagePipeOptionsFlags + MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE = 1; #else #define MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE \ ((MojoCreateMessagePipeOptionsFlags)0) +#define MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE \ + ((MojoCreateMessagePipeOptionsFlags)1) #endif MOJO_STATIC_ASSERT(MOJO_ALIGNOF(int64_t) == 8, "int64_t has weird alignment");
diff --git a/mojo/runner/host/child_process.cc b/mojo/runner/host/child_process.cc index 0dd6d84..a9f07bb 100644 --- a/mojo/runner/host/child_process.cc +++ b/mojo/runner/host/child_process.cc
@@ -124,7 +124,9 @@ // create a message pipe which requires this code to be run first. embedder::InitIPCSupport(embedder::ProcessType::NONE, this, io_runner_, embedder::ScopedPlatformHandle()); + } + void StartControllerThread() { // Create and start our controller thread. base::Thread::Options controller_thread_options; controller_thread_options.message_loop_type = @@ -305,7 +307,6 @@ ScopedMessagePipeHandle host_message_pipe(embedder::CreateChannel( platform_channel.Pass(), base::Bind(&DidCreateChannel), io_task_runner)); -#if defined(OS_WIN) if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) { // When using the new Mojo EDK, each message pipe is backed by a platform // handle. The one platform handle that comes on the command line is used @@ -339,9 +340,6 @@ #endif ))); } -#else - // TODO(jam): hook up on POSIX -#endif return host_message_pipe.Pass(); } @@ -385,6 +383,7 @@ app_context.Init(); ScopedMessagePipeHandle host_message_pipe = InitializeHostMessagePipe( platform_channel.Pass(), app_context.io_runner()); + app_context.StartControllerThread(); Blocker blocker; app_context.controller_runner()->PostTask( FROM_HERE,
diff --git a/mojo/runner/host/child_process_host.cc b/mojo/runner/host/child_process_host.cc index cb106933..770afb9 100644 --- a/mojo/runner/host/child_process_host.cc +++ b/mojo/runner/host/child_process_host.cc
@@ -39,11 +39,8 @@ channel_info_(nullptr), start_child_process_event_(false, false), weak_factory_(this) { -#if defined(OS_WIN) - // TODO(jam): enable on POSIX if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) serializer_platform_channel_pair_.reset(new edk::PlatformChannelPair(true)); -#endif child_message_pipe_ = embedder::CreateChannel( platform_channel_pair_.PassServerHandle(), @@ -71,7 +68,6 @@ DCHECK(!child_process_.IsValid()); DCHECK(child_message_pipe_.is_valid()); -#if defined(OS_WIN) if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) { std::string client_handle_as_string = serializer_platform_channel_pair_ @@ -86,7 +82,6 @@ MOJO_WRITE_MESSAGE_FLAG_NONE); DCHECK_EQ(rv, MOJO_RESULT_OK); } -#endif controller_.Bind( InterfacePtrInfo<ChildController>(child_message_pipe_.Pass(), 0u)); @@ -206,7 +201,6 @@ if (child_process_.IsValid()) { platform_channel_pair_.ChildProcessLaunched(); -#if defined(OS_WIN) if (serializer_platform_channel_pair_.get()) { serializer_platform_channel_pair_->ChildProcessLaunched(); mojo::embedder::ChildProcessLaunched( @@ -220,7 +214,6 @@ #endif ))); } -#endif } start_child_process_event_.Signal(); }
diff --git a/net/base/layered_network_delegate.cc b/net/base/layered_network_delegate.cc index e64019c0..265fa426 100644 --- a/net/base/layered_network_delegate.cc +++ b/net/base/layered_network_delegate.cc
@@ -256,9 +256,16 @@ return nested_network_delegate_->AreExperimentalCookieFeaturesEnabled(); } +bool LayeredNetworkDelegate::OnAreStrictSecureCookiesEnabled() const { + OnAreStrictSecureCookiesEnabledInternal(); + return nested_network_delegate_->AreStrictSecureCookiesEnabled(); +} + void LayeredNetworkDelegate::OnAreExperimentalCookieFeaturesEnabledInternal() const {} +void LayeredNetworkDelegate::OnAreStrictSecureCookiesEnabledInternal() const {} + bool LayeredNetworkDelegate:: OnCancelURLRequestWithPolicyViolatingReferrerHeader( const URLRequest& request,
diff --git a/net/base/layered_network_delegate.h b/net/base/layered_network_delegate.h index 9446043..9f0928e7 100644 --- a/net/base/layered_network_delegate.h +++ b/net/base/layered_network_delegate.h
@@ -84,6 +84,7 @@ bool OnCanEnablePrivacyMode(const GURL& url, const GURL& first_party_for_cookies) const final; bool OnAreExperimentalCookieFeaturesEnabled() const final; + bool OnAreStrictSecureCookiesEnabled() const final; bool OnCancelURLRequestWithPolicyViolatingReferrerHeader( const URLRequest& request, const GURL& target_url, @@ -158,6 +159,7 @@ const GURL& first_party_for_cookies) const; virtual void OnAreExperimentalCookieFeaturesEnabledInternal() const; + virtual void OnAreStrictSecureCookiesEnabledInternal() const; virtual void OnCancelURLRequestWithPolicyViolatingReferrerHeaderInternal( const URLRequest& request,
diff --git a/net/base/network_delegate.cc b/net/base/network_delegate.cc index 200905ec..ff4ee88f 100644 --- a/net/base/network_delegate.cc +++ b/net/base/network_delegate.cc
@@ -172,6 +172,10 @@ return OnAreExperimentalCookieFeaturesEnabled(); } +bool NetworkDelegate::AreStrictSecureCookiesEnabled() const { + return OnAreStrictSecureCookiesEnabled(); +} + bool NetworkDelegate::CancelURLRequestWithPolicyViolatingReferrerHeader( const URLRequest& request, const GURL& target_url,
diff --git a/net/base/network_delegate.h b/net/base/network_delegate.h index 0636f4e..979d3ec 100644 --- a/net/base/network_delegate.h +++ b/net/base/network_delegate.h
@@ -111,6 +111,8 @@ // secure scheme. https://crbug.com/459154, https://crbug.com/541511, // https://crbug.com/546820 bool AreExperimentalCookieFeaturesEnabled() const; + // TODO(jww): Remove this once we ship strict secure cookies. + bool AreStrictSecureCookiesEnabled() const; bool CancelURLRequestWithPolicyViolatingReferrerHeader( const URLRequest& request, @@ -295,6 +297,12 @@ // https://crbug.com/546820 virtual bool OnAreExperimentalCookieFeaturesEnabled() const = 0; + // Returns true if the embedder has enabled experimental features or + // specifically strict secure cookies, and false otherwise. + // + // TODO(jww): Remove this once we ship strict secure cookies. + virtual bool OnAreStrictSecureCookiesEnabled() const = 0; + // Called when the |referrer_url| for requesting |target_url| during handling // of the |request| is does not comply with the referrer policy (e.g. a // secure referrer for an insecure initial target).
diff --git a/net/base/network_delegate_impl.cc b/net/base/network_delegate_impl.cc index 7548f616..5e94543b 100644 --- a/net/base/network_delegate_impl.cc +++ b/net/base/network_delegate_impl.cc
@@ -106,6 +106,10 @@ return false; } +bool NetworkDelegateImpl::OnAreStrictSecureCookiesEnabled() const { + return false; +} + bool NetworkDelegateImpl::OnCancelURLRequestWithPolicyViolatingReferrerHeader( const URLRequest& request, const GURL& target_url,
diff --git a/net/base/network_delegate_impl.h b/net/base/network_delegate_impl.h index 7e9db65..8a0b007f 100644 --- a/net/base/network_delegate_impl.h +++ b/net/base/network_delegate_impl.h
@@ -205,6 +205,7 @@ // first-party cookies and cookie prefixes. https://crbug.com/459154, // https://crbug.com/541511 bool OnAreExperimentalCookieFeaturesEnabled() const override; + bool OnAreStrictSecureCookiesEnabled() const override; // Called when the |referrer_url| for requesting |target_url| during handling // of the |request| is does not comply with the referrer policy (e.g. a
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc index 5c4ddd1..bf9f63b 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc
@@ -746,11 +746,17 @@ CookieOptions options; options.set_include_httponly(); options.set_server_time(response_date_); + if (network_delegate() && network_delegate()->AreExperimentalCookieFeaturesEnabled()) { options.set_enforce_prefixes(); } + if (network_delegate() && + network_delegate()->AreStrictSecureCookiesEnabled()) { + options.set_enforce_strict_secure(); + } + CookieStore::SetCookiesCallback callback(base::Bind( &URLRequestHttpJob::OnCookieSaved, weak_factory_.GetWeakPtr(), save_next_cookie_running, callback_pending));
diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc index 31450c1..3bd6ece3 100644 --- a/net/url_request/url_request_test_util.cc +++ b/net/url_request/url_request_test_util.cc
@@ -626,6 +626,10 @@ return experimental_cookie_features_enabled_; } +bool TestNetworkDelegate::OnAreStrictSecureCookiesEnabled() const { + return experimental_cookie_features_enabled_; +} + bool TestNetworkDelegate::OnCancelURLRequestWithPolicyViolatingReferrerHeader( const URLRequest& request, const GURL& target_url,
diff --git a/net/url_request/url_request_test_util.h b/net/url_request/url_request_test_util.h index 07728cbd..3369c881 100644 --- a/net/url_request/url_request_test_util.h +++ b/net/url_request/url_request_test_util.h
@@ -340,6 +340,7 @@ bool OnCanAccessFile(const URLRequest& request, const base::FilePath& path) const override; bool OnAreExperimentalCookieFeaturesEnabled() const override; + bool OnAreStrictSecureCookiesEnabled() const override; bool OnCancelURLRequestWithPolicyViolatingReferrerHeader( const URLRequest& request, const GURL& target_url,
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index 939a6c61..6567c6d 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc
@@ -669,6 +669,7 @@ class TestExperimentalFeaturesNetworkDelegate : public TestNetworkDelegate { public: bool OnAreExperimentalCookieFeaturesEnabled() const override { return true; } + bool OnAreStrictSecureCookiesEnabled() const override { return true; } }; } // namespace @@ -2725,8 +2726,8 @@ req->Start(); base::RunLoop().Run(); - EXPECT_TRUE(d.data_received().find("FirstPartyCookieToSet=1") != - std::string::npos); + EXPECT_NE(d.data_received().find("FirstPartyCookieToSet=1"), + std::string::npos); EXPECT_EQ(0, network_delegate.blocked_get_cookies_count()); EXPECT_EQ(0, network_delegate.blocked_set_cookie_count()); } @@ -2769,8 +2770,8 @@ req->Start(); base::RunLoop().Run(); - EXPECT_TRUE(d.data_received().find("__Secure-nonsecure-origin=1") == - std::string::npos); + EXPECT_EQ(d.data_received().find("__Secure-nonsecure-origin=1"), + std::string::npos); EXPECT_EQ(0, network_delegate.blocked_get_cookies_count()); EXPECT_EQ(0, network_delegate.blocked_set_cookie_count()); } @@ -2825,11 +2826,10 @@ req->Start(); base::RunLoop().Run(); - EXPECT_TRUE(d.data_received().find("__Secure-secure-not-experimental=1") != - std::string::npos); - EXPECT_TRUE( - d.data_received().find("__Secure-nonsecure-not-experimental=1") != - std::string::npos); + EXPECT_NE(d.data_received().find("__Secure-secure-not-experimental=1"), + std::string::npos); + EXPECT_NE(d.data_received().find("__Secure-nonsecure-not-experimental=1"), + std::string::npos); EXPECT_EQ(0, network_delegate.blocked_get_cookies_count()); EXPECT_EQ(0, network_delegate.blocked_set_cookie_count()); } @@ -2867,7 +2867,7 @@ req->Start(); base::RunLoop().Run(); - EXPECT_TRUE(d.data_received().find("__Secure-foo=1") == std::string::npos); + EXPECT_EQ(d.data_received().find("__Secure-foo=1"), std::string::npos); EXPECT_EQ(0, network_delegate.blocked_get_cookies_count()); EXPECT_EQ(0, network_delegate.blocked_set_cookie_count()); } @@ -2905,7 +2905,89 @@ req->Start(); base::RunLoop().Run(); - EXPECT_TRUE(d.data_received().find("__Secure-bar=1") != std::string::npos); + EXPECT_NE(d.data_received().find("__Secure-bar=1"), std::string::npos); + EXPECT_EQ(0, network_delegate.blocked_get_cookies_count()); + EXPECT_EQ(0, network_delegate.blocked_set_cookie_count()); + } +} + +// Tests that secure cookies can't be set on non-secure origins if strict secure +// cookies are enabled. +TEST_F(URLRequestTest, StrictSecureCookiesOnNonsecureOrigin) { + EmbeddedTestServer http_server; + http_server.AddDefaultHandlers( + base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + EmbeddedTestServer https_server(EmbeddedTestServer::TYPE_HTTPS); + https_server.AddDefaultHandlers( + base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + ASSERT_TRUE(http_server.Start()); + ASSERT_TRUE(https_server.Start()); + + TestExperimentalFeaturesNetworkDelegate network_delegate; + TestURLRequestContext context(true); + context.set_network_delegate(&network_delegate); + context.Init(); + + // Try to set a Secure cookie, with experimental features enabled. + { + TestDelegate d; + scoped_ptr<URLRequest> req(context.CreateRequest( + http_server.GetURL("/set-cookie?nonsecure-origin=1;Secure"), + DEFAULT_PRIORITY, &d)); + req->Start(); + base::RunLoop().Run(); + EXPECT_EQ(0, network_delegate.blocked_get_cookies_count()); + EXPECT_EQ(0, network_delegate.blocked_set_cookie_count()); + } + + // Verify that the cookie is not set. + { + TestDelegate d; + scoped_ptr<URLRequest> req(context.CreateRequest( + https_server.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &d)); + req->Start(); + base::RunLoop().Run(); + + EXPECT_EQ(d.data_received().find("nonsecure-origin=1"), std::string::npos); + EXPECT_EQ(0, network_delegate.blocked_get_cookies_count()); + EXPECT_EQ(0, network_delegate.blocked_set_cookie_count()); + } +} + +// Tests that secure cookies can be set on secure origins even if strict secure +// cookies are enabled. +TEST_F(URLRequestTest, StrictSecureCookiesOnSecureOrigin) { + EmbeddedTestServer https_server(EmbeddedTestServer::TYPE_HTTPS); + https_server.AddDefaultHandlers( + base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + ASSERT_TRUE(https_server.Start()); + + TestExperimentalFeaturesNetworkDelegate network_delegate; + TestURLRequestContext context(true); + context.set_network_delegate(&network_delegate); + context.Init(); + + // Try to set a Secure cookie, with experimental features enabled. + { + TestDelegate d; + scoped_ptr<URLRequest> req(context.CreateRequest( + https_server.GetURL("/set-cookie?secure-origin=1;Secure"), + DEFAULT_PRIORITY, &d)); + req->Start(); + base::RunLoop().Run(); + EXPECT_EQ(0, network_delegate.blocked_get_cookies_count()); + EXPECT_EQ(0, network_delegate.blocked_set_cookie_count()); + } + + // Verify that the cookie is not set. + { + TestDelegate d; + scoped_ptr<URLRequest> req(context.CreateRequest( + https_server.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &d)); + req->Start(); + base::RunLoop().Run(); + + EXPECT_NE(d.data_received().find("secure-origin=1"), std::string::npos); EXPECT_EQ(0, network_delegate.blocked_get_cookies_count()); EXPECT_EQ(0, network_delegate.blocked_set_cookie_count()); }
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/containing-block-change-compositing-expected.html b/third_party/WebKit/LayoutTests/fast/block/float/containing-block-change-compositing-expected.html new file mode 100644 index 0000000..02acf717 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/block/float/containing-block-change-compositing-expected.html
@@ -0,0 +1,7 @@ +<!DOCTYPE html> +<body style="margin: 0"> + <div style="height: 100px"> + Tests layout and repaint of floating descendants of a container changing 3D transform. Passes if there is no red. + </div> + <div style="position: absolute; top: 100px; left: 100px; width: 100px; height: 100px; background-color: green"></div> +</body>
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/containing-block-change-compositing.html b/third_party/WebKit/LayoutTests/fast/block/float/containing-block-change-compositing.html new file mode 100644 index 0000000..ae00ac4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/block/float/containing-block-change-compositing.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> +<script> +runAfterLayoutAndPaint(function() { + document.getElementById('container').style.transform = 'translateZ(0) translateX(100px)'; +}, true); +</script> +<body style="margin: 0"> + <div style="height: 100px"> + Tests layout and repaint of floating descendants of a container changing 3D transform. Passes if there is no red. + </div> + <div id="indicator" style="position: absolute; top: 100px; left: 100px; width: 100px; height: 100px; background-color: red"></div> + <div> + <div id="container" style="width: 0; height: 0"> + <div style="float: left; width: 100px; height: 100px; background-color: green"></div> + </div> + </div> +</body>
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/content-into-overflow-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/content-into-overflow-expected.txt index c95c4459..88f27de 100644 --- a/third_party/WebKit/LayoutTests/fast/repaint/content-into-overflow-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/repaint/content-into-overflow-expected.txt
@@ -9,7 +9,6 @@ [111, 8, 3, 106], [61, 8, 53, 106], [8, 388, 100, 20], - [8, 388, 100, 20], [8, 308, 100, 100], [8, 261, 106, 3], [8, 211, 106, 53]
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/float-in-new-block-with-layout-delta-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/float-in-new-block-with-layout-delta-expected.txt index 2aa40ce..a52c833 100644 --- a/third_party/WebKit/LayoutTests/fast/repaint/float-in-new-block-with-layout-delta-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/repaint/float-in-new-block-with-layout-delta-expected.txt
@@ -6,7 +6,6 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [8, 108, 784, 100], [8, 108, 100, 100] ], "paintInvalidationClients": [
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/float-move-during-layout-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/float-move-during-layout-expected.txt index ac5ce61..f659019 100644 --- a/third_party/WebKit/LayoutTests/fast/repaint/float-move-during-layout-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/repaint/float-move-during-layout-expected.txt
@@ -6,10 +6,8 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [8, 204, 784, 100], [8, 204, 100, 100], [8, 104, 784, 100], - [8, 104, 784, 100], [8, 104, 100, 100] ], "paintInvalidationClients": [
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/float-new-in-block-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/float-new-in-block-expected.txt index 21fb5ba..94bc8dd 100644 --- a/third_party/WebKit/LayoutTests/fast/repaint/float-new-in-block-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/repaint/float-new-in-block-expected.txt
@@ -6,11 +6,9 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [8, 28, 784, 80], [8, 8, 100, 100] ], "paintInvalidationClients": [ - "LayoutBlockFlow DIV", "LayoutBlockFlow (floating) DIV id='target'" ] }
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/overflow-into-content-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/overflow-into-content-expected.txt index b31309c..f887412 100644 --- a/third_party/WebKit/LayoutTests/fast/repaint/overflow-into-content-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/repaint/overflow-into-content-expected.txt
@@ -9,7 +9,6 @@ [111, 8, 3, 106], [61, 8, 53, 106], [8, 388, 100, 20], - [8, 388, 100, 20], [8, 308, 100, 100], [8, 261, 106, 3], [8, 211, 106, 53]
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/overhanging-float-detach-repaint-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/overhanging-float-detach-repaint-expected.txt index e3825e6..72fda62 100644 --- a/third_party/WebKit/LayoutTests/fast/repaint/overhanging-float-detach-repaint-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/repaint/overhanging-float-detach-repaint-expected.txt
@@ -6,7 +6,6 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [8, 62, 784, 100], [8, 62, 100, 100] ], "paintInvalidationClients": [
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt b/third_party/WebKit/LayoutTests/platform/android/fast/repaint/inline-focus-expected.txt similarity index 83% copy from third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt copy to third_party/WebKit/LayoutTests/platform/android/fast/repaint/inline-focus-expected.txt index 278e4ab3..13b7752 100644 --- a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/android/fast/repaint/inline-focus-expected.txt
@@ -6,14 +6,14 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [0, 34, 800, 18], + [0, 36, 800, 19], [0, 0, 800, 232], [0, 0, 800, 232], [0, 0, 800, 232], - [-5, -5, 810, 242], - [-5, -5, 805, 237], - [-5, -5, 805, 237], - [-5, -5, 805, 237] + [-1, -1, 802, 234], + [-1, -1, 801, 233], + [-1, -1, 801, 233], + [-1, -1, 801, 233] ], "paintInvalidationClients": [ "InlineFlowBox",
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt b/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/fast/repaint/inline-focus-expected.txt similarity index 83% copy from third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt copy to third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/fast/repaint/inline-focus-expected.txt index 278e4ab3..13b7752 100644 --- a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/android/virtual/syncpaint/fast/repaint/inline-focus-expected.txt
@@ -6,14 +6,14 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [0, 34, 800, 18], + [0, 36, 800, 19], [0, 0, 800, 232], [0, 0, 800, 232], [0, 0, 800, 232], - [-5, -5, 810, 242], - [-5, -5, 805, 237], - [-5, -5, 805, 237], - [-5, -5, 805, 237] + [-1, -1, 802, 234], + [-1, -1, 801, 233], + [-1, -1, 801, 233], + [-1, -1, 801, 233] ], "paintInvalidationClients": [ "InlineFlowBox",
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/float-move-during-layout-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/float-move-during-layout-expected.txt index 50540ba3..90a8e14 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/float-move-during-layout-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/float-move-during-layout-expected.txt
@@ -6,10 +6,8 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [8, 210, 784, 100], [8, 210, 100, 100], [8, 110, 784, 100], - [8, 110, 784, 100], [8, 110, 100, 100] ], "paintInvalidationClients": [
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/inline-focus-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/inline-focus-expected.txt index 13b7752..c284e7fd 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/inline-focus-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/inline-focus-expected.txt
@@ -8,12 +8,12 @@ "repaintRects": [ [0, 36, 800, 19], [0, 0, 800, 232], - [0, 0, 800, 232], - [0, 0, 800, 232], + [0, 0, 800, 56], + [0, 0, 800, 20], [-1, -1, 802, 234], [-1, -1, 801, 233], - [-1, -1, 801, 233], - [-1, -1, 801, 233] + [-1, -1, 801, 57], + [-1, -1, 801, 21] ], "paintInvalidationClients": [ "InlineFlowBox",
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/overhanging-float-detach-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/overhanging-float-detach-repaint-expected.txt index 72fa722d8..ea81d43a 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/overhanging-float-detach-repaint-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/overhanging-float-detach-repaint-expected.txt
@@ -6,7 +6,6 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [8, 68, 784, 100], [8, 68, 100, 100] ], "paintInvalidationClients": [
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/inline-focus-expected.txt similarity index 77% copy from third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt copy to third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/inline-focus-expected.txt index 278e4ab3..c284e7fd 100644 --- a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/inline-focus-expected.txt
@@ -6,14 +6,14 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [0, 34, 800, 18], + [0, 36, 800, 19], [0, 0, 800, 232], - [0, 0, 800, 232], - [0, 0, 800, 232], - [-5, -5, 810, 242], - [-5, -5, 805, 237], - [-5, -5, 805, 237], - [-5, -5, 805, 237] + [0, 0, 800, 56], + [0, 0, 800, 20], + [-1, -1, 802, 234], + [-1, -1, 801, 233], + [-1, -1, 801, 57], + [-1, -1, 801, 21] ], "paintInvalidationClients": [ "InlineFlowBox",
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/inline-focus-expected.txt similarity index 87% rename from third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt rename to third_party/WebKit/LayoutTests/platform/mac/fast/repaint/inline-focus-expected.txt index 278e4ab3..80b72b5 100644 --- a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/inline-focus-expected.txt
@@ -8,12 +8,12 @@ "repaintRects": [ [0, 34, 800, 18], [0, 0, 800, 232], - [0, 0, 800, 232], - [0, 0, 800, 232], + [0, 0, 800, 52], + [0, 0, 800, 18], [-5, -5, 810, 242], [-5, -5, 805, 237], - [-5, -5, 805, 237], - [-5, -5, 805, 237] + [-5, -5, 805, 57], + [-5, -5, 805, 28] ], "paintInvalidationClients": [ "InlineFlowBox",
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/float-move-during-layout-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/float-move-during-layout-expected.txt index 50540ba3..90a8e14 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/float-move-during-layout-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/float-move-during-layout-expected.txt
@@ -6,10 +6,8 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [8, 210, 784, 100], [8, 210, 100, 100], [8, 110, 784, 100], - [8, 110, 784, 100], [8, 110, 100, 100] ], "paintInvalidationClients": [
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/inline-focus-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/inline-focus-expected.txt index 13b7752..c284e7fd 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/inline-focus-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/inline-focus-expected.txt
@@ -8,12 +8,12 @@ "repaintRects": [ [0, 36, 800, 19], [0, 0, 800, 232], - [0, 0, 800, 232], - [0, 0, 800, 232], + [0, 0, 800, 56], + [0, 0, 800, 20], [-1, -1, 802, 234], [-1, -1, 801, 233], - [-1, -1, 801, 233], - [-1, -1, 801, 233] + [-1, -1, 801, 57], + [-1, -1, 801, 21] ], "paintInvalidationClients": [ "InlineFlowBox",
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/overhanging-float-detach-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/overhanging-float-detach-repaint-expected.txt index 72fa722d8..ea81d43a 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/overhanging-float-detach-repaint-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/overhanging-float-detach-repaint-expected.txt
@@ -6,7 +6,6 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [8, 68, 784, 100], [8, 68, 100, 100] ], "paintInvalidationClients": [
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/fast/repaint/inline-focus-expected.txt similarity index 83% copy from third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt copy to third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/fast/repaint/inline-focus-expected.txt index 278e4ab3..13b7752 100644 --- a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/fast/repaint/inline-focus-expected.txt
@@ -6,14 +6,14 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [0, 34, 800, 18], + [0, 36, 800, 19], [0, 0, 800, 232], [0, 0, 800, 232], [0, 0, 800, 232], - [-5, -5, 810, 242], - [-5, -5, 805, 237], - [-5, -5, 805, 237], - [-5, -5, 805, 237] + [-1, -1, 802, 234], + [-1, -1, 801, 233], + [-1, -1, 801, 233], + [-1, -1, 801, 233] ], "paintInvalidationClients": [ "InlineFlowBox",
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/inline-focus-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/inline-focus-expected.txt index 566e953..5ce0844 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/inline-focus-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/inline-focus-expected.txt
@@ -8,12 +8,12 @@ "repaintRects": [ [0, 34, 800, 18], [0, 0, 800, 232], - [0, 0, 800, 232], - [0, 0, 800, 232], + [0, 0, 800, 52], + [0, 0, 800, 18], [-1, -1, 802, 234], [-1, -1, 801, 233], - [-1, -1, 801, 233], - [-1, -1, 801, 233] + [-1, -1, 801, 53], + [-1, -1, 801, 19] ], "paintInvalidationClients": [ "InlineFlowBox",
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/inline-focus-expected.txt similarity index 80% copy from third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt copy to third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/inline-focus-expected.txt index 278e4ab3..5ce0844 100644 --- a/third_party/WebKit/LayoutTests/fast/repaint/inline-focus-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/inline-focus-expected.txt
@@ -8,12 +8,12 @@ "repaintRects": [ [0, 34, 800, 18], [0, 0, 800, 232], - [0, 0, 800, 232], - [0, 0, 800, 232], - [-5, -5, 810, 242], - [-5, -5, 805, 237], - [-5, -5, 805, 237], - [-5, -5, 805, 237] + [0, 0, 800, 52], + [0, 0, 800, 18], + [-1, -1, 802, 234], + [-1, -1, 801, 233], + [-1, -1, 801, 53], + [-1, -1, 801, 19] ], "paintInvalidationClients": [ "InlineFlowBox",
diff --git a/third_party/WebKit/Source/core/css/CSSGridTemplateAreasValue.cpp b/third_party/WebKit/Source/core/css/CSSGridTemplateAreasValue.cpp index 0fefa43..cf311f0b 100644 --- a/third_party/WebKit/Source/core/css/CSSGridTemplateAreasValue.cpp +++ b/third_party/WebKit/Source/core/css/CSSGridTemplateAreasValue.cpp
@@ -51,13 +51,13 @@ for (const auto& item : gridAreaMap) { const GridCoordinate& coordinate = item.value; - if (row >= coordinate.rows.resolvedInitialPosition().toInt() && row < coordinate.rows.resolvedFinalPosition().toInt()) + if (row >= coordinate.rows.resolvedInitialPosition() && row < coordinate.rows.resolvedFinalPosition()) candidates.append(item.key); } for (const auto& item : gridAreaMap) { const GridCoordinate& coordinate = item.value; - if (column >= coordinate.columns.resolvedInitialPosition().toInt() && column < coordinate.columns.resolvedFinalPosition().toInt() && candidates.contains(item.key)) + if (column >= coordinate.columns.resolvedInitialPosition() && column < coordinate.columns.resolvedFinalPosition() && candidates.contains(item.key)) return item.key; }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp index 671cabf..9168952 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -2177,7 +2177,7 @@ return consumeLengthOrPercent(range, SVGAttributeMode, ValueRangeAll, UnitlessQuirk::Forbid); } -PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::consumeImageSet(CSSParserTokenRange& range) +static PassRefPtrWillBeRawPtr<CSSValue> consumeImageSet(CSSParserTokenRange& range, CSSParserContext context) { CSSParserTokenRange rangeCopy = range; CSSParserTokenRange args = consumeFunction(rangeCopy); @@ -2187,7 +2187,7 @@ if (urlValue.isNull()) return nullptr; - RefPtrWillBeRawPtr<CSSValue> image = createCSSImageValueWithReferrer(urlValue, completeURL(urlValue)); + RefPtrWillBeRawPtr<CSSValue> image = CSSPropertyParser::createCSSImageValueWithReferrer(urlValue, context); imageSet->append(image); const CSSParserToken& token = args.consumeIncludingWhitespace(); @@ -2207,16 +2207,16 @@ return imageSet.release(); } -PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::consumeCursor(CSSParserTokenRange& range) +static PassRefPtrWillBeRawPtr<CSSValue> consumeCursor(CSSParserTokenRange& range, CSSParserContext context, bool inQuirksMode) { RefPtrWillBeRawPtr<CSSValueList> list = nullptr; while (!range.atEnd()) { RefPtrWillBeRawPtr<CSSValue> image = nullptr; AtomicString uri(consumeUrl(range)); if (!uri.isNull()) { - image = createCSSImageValueWithReferrer(uri, completeURL(uri)); + image = CSSPropertyParser::createCSSImageValueWithReferrer(uri, context); } else if (range.peek().type() == FunctionToken && range.peek().functionId() == CSSValueWebkitImageSet) { - image = consumeImageSet(range); + image = consumeImageSet(range, context); if (!image) return nullptr; } else { @@ -2243,15 +2243,15 @@ } CSSValueID id = range.peek().id(); - if (!range.atEnd() && m_context.useCounter()) { + if (!range.atEnd() && context.useCounter()) { if (id == CSSValueWebkitZoomIn) - m_context.useCounter()->count(UseCounter::PrefixedCursorZoomIn); + context.useCounter()->count(UseCounter::PrefixedCursorZoomIn); else if (id == CSSValueWebkitZoomOut) - m_context.useCounter()->count(UseCounter::PrefixedCursorZoomOut); + context.useCounter()->count(UseCounter::PrefixedCursorZoomOut); } RefPtrWillBeRawPtr<CSSValue> cursorType = nullptr; if (id == CSSValueHand) { - if (inQuirksMode()) // Non-standard behavior + if (inQuirksMode) // Non-standard behavior cursorType = cssValuePool().createIdentifierValue(CSSValuePointer); range.consumeIncludingWhitespace(); } else if ((id >= CSSValueAuto && id <= CSSValueWebkitZoomOut) || id == CSSValueCopy || id == CSSValueNone) { @@ -2481,7 +2481,7 @@ case CSSPropertyRy: return consumeLengthOrPercent(m_range, SVGAttributeMode, ValueRangeAll, UnitlessQuirk::Forbid); case CSSPropertyCursor: - return consumeCursor(m_range); + return consumeCursor(m_range, m_context, inQuirksMode()); case CSSPropertyContain: return consumeContain(m_range); case CSSPropertyTransformOrigin: @@ -2515,7 +2515,7 @@ String url = consumeUrl(m_range); if (url.isNull()) return nullptr; - RefPtrWillBeRawPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create(completeURL(url), m_context.shouldCheckContentSecurityPolicy())); + RefPtrWillBeRawPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create(m_context.completeURL(url), m_context.shouldCheckContentSecurityPolicy())); uriValue->setReferrer(m_context.referrer()); if (m_range.peek().functionId() != CSSValueFormat)
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h index d815869..0b856039 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h +++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
@@ -92,6 +92,14 @@ static bool isColorKeyword(CSSValueID); static bool isValidNumericValue(double); + // TODO(rwlbuis): move to CSSPropertyParser.cpp once CSSParserToken conversion is done. + static PassRefPtrWillBeRawPtr<CSSValue> createCSSImageValueWithReferrer(const AtomicString& rawValue, const CSSParserContext& context) + { + RefPtrWillBeRawPtr<CSSValue> imageValue = CSSImageValue::create(rawValue, context.completeURL(rawValue)); + toCSSImageValue(imageValue.get())->setReferrer(context.referrer()); + return imageValue; + } + private: CSSPropertyParser(const CSSParserTokenRange&, const CSSParserContext&, WillBeHeapVector<CSSProperty, 256>&); @@ -109,8 +117,6 @@ bool parseViewportDescriptor(CSSPropertyID propId, bool important); bool parseFontFaceDescriptor(CSSPropertyID); - KURL completeURL(const String& url) const; - void addProperty(CSSPropertyID, PassRefPtrWillBeRawPtr<CSSValue>, bool important, bool implicit = false); void rollbackLastProperties(int num); void addExpandedPropertyForValue(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue>, bool); @@ -155,8 +161,6 @@ bool consumeColumns(bool important); - PassRefPtrWillBeRawPtr<CSSValue> consumeCursor(CSSParserTokenRange&); - PassRefPtrWillBeRawPtr<CSSValue> parseGridPosition(); bool parseIntegerOrCustomIdentFromGridPosition(RefPtrWillBeRawPtr<CSSPrimitiveValue>& numericValue, RefPtrWillBeRawPtr<CSSCustomIdentValue>& gridLineName); bool parseGridItemPositionShorthand(CSSPropertyID, bool important); @@ -230,7 +234,6 @@ bool parseCrossfade(CSSParserValueList*, RefPtrWillBeRawPtr<CSSValue>&); PassRefPtrWillBeRawPtr<CSSValue> parseImageSet(CSSParserValueList*); - PassRefPtrWillBeRawPtr<CSSValue> consumeImageSet(CSSParserTokenRange&); PassRefPtrWillBeRawPtr<CSSValueList> parseFilter(); PassRefPtrWillBeRawPtr<CSSFunctionValue> parseBuiltinFilterArguments(CSSParserValueList*, CSSValueID); @@ -243,14 +246,6 @@ PassRefPtrWillBeRawPtr<CSSStringValue> createPrimitiveStringValue(CSSParserValue*); PassRefPtrWillBeRawPtr<CSSCustomIdentValue> createPrimitiveCustomIdentValue(CSSParserValue*); - // TODO(rwlbuis): move to CSSPropertyParser.cpp once CSSParserToken conversion is done. - inline PassRefPtrWillBeRawPtr<CSSValue> createCSSImageValueWithReferrer(const AtomicString& rawValue, const KURL& url) - { - RefPtrWillBeRawPtr<CSSValue> imageValue = CSSImageValue::create(rawValue, url); - toCSSImageValue(imageValue.get())->setReferrer(m_context.referrer()); - return imageValue; - } - PassRefPtrWillBeRawPtr<CSSBasicShapeInsetValue> parseInsetRoundedCorners(PassRefPtrWillBeRawPtr<CSSBasicShapeInsetValue>, CSSParserValueList*); PassRefPtrWillBeRawPtr<CSSValue> consumeFontFaceSrcURI();
diff --git a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp index 033b23d..e0392a5 100644 --- a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
@@ -93,11 +93,6 @@ m_parsedProperties.shrink(m_parsedProperties.size() - num); } -KURL CSSPropertyParser::completeURL(const String& url) const -{ - return m_context.completeURL(url); -} - bool CSSPropertyParser::validCalculationUnit(CSSParserValue* value, Units unitflags, ReleaseParsedCalcValueCondition releaseCalc) { bool mustBeNonNegative = unitflags & (FNonNeg | FPositiveInteger); @@ -1305,7 +1300,7 @@ RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr; if (val->m_unit == CSSParserValue::URI) { // url - parsedValue = createCSSImageValueWithReferrer(val->string, completeURL(val->string)); + parsedValue = createCSSImageValueWithReferrer(val->string, m_context); } else if (val->m_unit == CSSParserValue::Function) { // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradient(...) CSSParserValueList* args = val->function->args.get(); @@ -1424,7 +1419,7 @@ return true; } if (valueList->current()->m_unit == CSSParserValue::URI) { - value = createCSSImageValueWithReferrer(valueList->current()->string, completeURL(valueList->current()->string)); + value = createCSSImageValueWithReferrer(valueList->current()->string, m_context); return true; } @@ -2720,18 +2715,18 @@ // The following checks test that the grid area is a single filled-in rectangle. // 1. The new row is adjacent to the previously parsed row. - if (rowCount != gridCoordinate.rows.resolvedFinalPosition().toInt()) + if (rowCount != gridCoordinate.rows.resolvedFinalPosition()) return false; // 2. The new area starts at the same position as the previously parsed area. - if (currentCol != gridCoordinate.columns.resolvedInitialPosition().toInt()) + if (currentCol != gridCoordinate.columns.resolvedInitialPosition()) return false; // 3. The new area ends at the same position as the previously parsed area. - if (lookAheadCol != gridCoordinate.columns.resolvedFinalPosition().toInt()) + if (lookAheadCol != gridCoordinate.columns.resolvedFinalPosition()) return false; - gridCoordinate.rows = GridSpan::definiteGridSpan(gridCoordinate.rows.resolvedInitialPosition(), gridCoordinate.rows.resolvedFinalPosition().next()); + gridCoordinate.rows = GridSpan::definiteGridSpan(gridCoordinate.rows.resolvedInitialPosition(), gridCoordinate.rows.resolvedFinalPosition() + 1); } currentCol = lookAheadCol - 1; } @@ -3767,7 +3762,7 @@ if (!context.canAdvance() && context.allowImage()) { if (val->m_unit == CSSParserValue::URI) { - context.commitImage(createCSSImageValueWithReferrer(val->string, m_context.completeURL(val->string))); + context.commitImage(createCSSImageValueWithReferrer(val->string, m_context)); } else if (val->m_unit == CSSParserValue::Function) { if (isGeneratedImageValue(val->function->id)) { RefPtrWillBeRawPtr<CSSValue> value = nullptr; @@ -4952,7 +4947,7 @@ if (arg->m_unit != CSSParserValue::URI) return nullptr; - RefPtrWillBeRawPtr<CSSValue> image = createCSSImageValueWithReferrer(arg->string, completeURL(arg->string)); + RefPtrWillBeRawPtr<CSSValue> image = createCSSImageValueWithReferrer(arg->string, m_context); imageSet->append(image); arg = functionArgs->next();
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp index 91cb9ea..4ed7a7c8 100644 --- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp +++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
@@ -521,12 +521,12 @@ GridSpan areaSpan = direction == ForRows ? namedGridAreaEntry.value.rows : namedGridAreaEntry.value.columns; { NamedGridLinesMap::AddResult startResult = namedGridLines.add(namedGridAreaEntry.key + "-start", Vector<size_t>()); - startResult.storedValue->value.append(areaSpan.resolvedInitialPosition().toInt()); + startResult.storedValue->value.append(areaSpan.resolvedInitialPosition()); std::sort(startResult.storedValue->value.begin(), startResult.storedValue->value.end()); } { NamedGridLinesMap::AddResult endResult = namedGridLines.add(namedGridAreaEntry.key + "-end", Vector<size_t>()); - endResult.storedValue->value.append(areaSpan.resolvedFinalPosition().toInt()); + endResult.storedValue->value.append(areaSpan.resolvedFinalPosition()); std::sort(endResult.storedValue->value.begin(), endResult.storedValue->value.end()); } }
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp index c4299e3..29128938 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
@@ -943,7 +943,7 @@ addOverflowFromBlockChildren(); } -void LayoutBlock::computeOverflow(LayoutUnit oldClientAfterEdge) +void LayoutBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool) { m_overflow.clear(); @@ -1109,7 +1109,7 @@ // computeOverflow expects the bottom edge before we clamp our height. Since this information isn't available during // simplifiedLayout, we cache the value in m_overflow. LayoutUnit oldClientAfterEdge = hasOverflowModel() ? m_overflow->layoutClientAfterEdge() : clientLogicalBottom(); - computeOverflow(oldClientAfterEdge); + computeOverflow(oldClientAfterEdge, true); } updateLayerTransformAfterLayout(); @@ -2844,7 +2844,7 @@ return false; LayoutUnit oldClientAfterEdge = hasOverflowModel() ? m_overflow->layoutClientAfterEdge() : clientLogicalBottom(); - computeOverflow(oldClientAfterEdge); + computeOverflow(oldClientAfterEdge, true); if (hasOverflowClip()) layer()->scrollableArea()->updateAfterOverflowRecalc();
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.h b/third_party/WebKit/Source/core/layout/LayoutBlock.h index d0e54ae..f3cfe100 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlock.h +++ b/third_party/WebKit/Source/core/layout/LayoutBlock.h
@@ -342,7 +342,7 @@ virtual void simplifiedNormalFlowLayout(); public: - virtual void computeOverflow(LayoutUnit oldClientAfterEdge); + virtual void computeOverflow(LayoutUnit oldClientAfterEdge, bool = false); protected: virtual void addOverflowFromChildren(); void addOverflowFromPositionedObjects();
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp index b83ced6..d819092 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -1723,10 +1723,11 @@ } } -void LayoutBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge) +void LayoutBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats) { - LayoutBlock::computeOverflow(oldClientAfterEdge); - addOverflowFromFloats(); + LayoutBlock::computeOverflow(oldClientAfterEdge, recomputeFloats); + if (recomputeFloats || createsNewFormattingContext() || hasSelfPaintingLayer()) + addOverflowFromFloats(); } RootInlineBox* LayoutBlockFlow::createAndAppendRootInlineBox()
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h index 61057fe8..3382e89 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h +++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
@@ -93,7 +93,7 @@ void layoutBlock(bool relayoutChildren) override; - void computeOverflow(LayoutUnit oldClientAfterEdge) override; + void computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats = false) override; void deleteLineBoxTree() final;
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp index e5cccec..d39d0b7 100644 --- a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
@@ -547,7 +547,7 @@ const GridSpan span = cachedGridSpan(*gridItem, direction); // Do not include already processed items. - if (i > 0 && span.resolvedInitialPosition().toInt() <= flexibleSizedTracksIndex[i - 1]) + if (i > 0 && span.resolvedInitialPosition() <= flexibleSizedTracksIndex[i - 1]) continue; flexFraction = std::max(flexFraction, findFlexFactorUnitSize(tracks, span, direction, maxContentForChild(*gridItem, direction, sizingData.columnTracks))); @@ -631,8 +631,7 @@ double flexFactorSum = 0; Vector<size_t, 8> flexibleTracksIndexes; - for (const auto& resolvedPosition : tracksSpan) { - size_t trackIndex = resolvedPosition.toInt(); + for (const auto& trackIndex : tracksSpan) { GridTrackSize trackSize = gridTrackSize(direction, trackIndex); if (!trackSize.maxTrackBreadth().isFlex()) { leftOverSpace -= tracks[trackIndex].baseSize(); @@ -785,7 +784,7 @@ bool LayoutGrid::spanningItemCrossesFlexibleSizedTracks(const GridSpan& span, GridTrackSizingDirection direction) const { for (const auto& trackPosition : span) { - const GridTrackSize& trackSize = gridTrackSize(direction, trackPosition.toInt()); + const GridTrackSize& trackSize = gridTrackSize(direction, trackPosition); if (trackSize.minTrackBreadth().isFlex() || trackSize.maxTrackBreadth().isFlex()) return true; } @@ -834,8 +833,8 @@ void LayoutGrid::resolveContentBasedTrackSizingFunctionsForNonSpanningItems(GridTrackSizingDirection direction, const GridSpan& span, LayoutBox& gridItem, GridTrack& track, Vector<GridTrack>& columnTracks) { - const GridResolvedPosition trackPosition = span.resolvedInitialPosition(); - GridTrackSize trackSize = gridTrackSize(direction, trackPosition.toInt()); + const size_t trackPosition = span.resolvedInitialPosition(); + GridTrackSize trackSize = gridTrackSize(direction, trackPosition); if (trackSize.hasMinContentMinTrackBreadth()) track.setBaseSize(std::max(track.baseSize(), minContentForChild(gridItem, direction, columnTracks))); @@ -993,8 +992,8 @@ sizingData.filteredTracks.shrink(0); LayoutUnit spanningTracksSize; for (const auto& trackPosition : itemSpan) { - GridTrackSize trackSize = gridTrackSize(direction, trackPosition.toInt()); - GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[trackPosition.toInt()] : sizingData.rowTracks[trackPosition.toInt()]; + GridTrackSize trackSize = gridTrackSize(direction, trackPosition); + GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[trackPosition] : sizingData.rowTracks[trackPosition]; spanningTracksSize += trackSizeForTrackSizeComputationPhase(phase, track, ForbidInfinity); if (!shouldProcessTrackForTrackSizeComputationPhase(phase, trackSize)) continue; @@ -1106,11 +1105,11 @@ void LayoutGrid::insertItemIntoGrid(LayoutBox& child, const GridCoordinate& coordinate) { RELEASE_ASSERT(coordinate.rows.isDefinite() && coordinate.columns.isDefinite()); - ensureGridSize(coordinate.rows.resolvedFinalPosition().toInt(), coordinate.columns.resolvedFinalPosition().toInt()); + ensureGridSize(coordinate.rows.resolvedFinalPosition(), coordinate.columns.resolvedFinalPosition()); - for (GridSpan::iterator row = coordinate.rows.begin(); row != coordinate.rows.end(); ++row) { - for (GridSpan::iterator column = coordinate.columns.begin(); column != coordinate.columns.end(); ++column) - m_grid[row.toInt()][column.toInt()].append(&child); + for (const auto& row : coordinate.rows) { + for (const auto& column: coordinate.columns) + m_grid[row][column].append(&child); } } @@ -1186,19 +1185,19 @@ // |positions| is 0 if we need to run the auto-placement algorithm. if (rowPositions.isDefinite()) { - maximumRowIndex = std::max<size_t>(maximumRowIndex, rowPositions.resolvedFinalPosition().toInt()); + maximumRowIndex = std::max<size_t>(maximumRowIndex, rowPositions.resolvedFinalPosition()); } else { // Grow the grid for items with a definite row span, getting the largest such span. - GridSpan positions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *child, ForRows, GridResolvedPosition(0)); - maximumRowIndex = std::max<size_t>(maximumRowIndex, positions.resolvedFinalPosition().toInt()); + GridSpan positions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *child, ForRows, 0); + maximumRowIndex = std::max<size_t>(maximumRowIndex, positions.resolvedFinalPosition()); } if (columnPositions.isDefinite()) { - maximumColumnIndex = std::max<size_t>(maximumColumnIndex, columnPositions.resolvedFinalPosition().toInt()); + maximumColumnIndex = std::max<size_t>(maximumColumnIndex, columnPositions.resolvedFinalPosition()); } else { // Grow the grid for items with a definite column span, getting the largest such span. - GridSpan positions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *child, ForColumns, GridResolvedPosition(0)); - maximumColumnIndex = std::max<size_t>(maximumColumnIndex, positions.resolvedFinalPosition().toInt()); + GridSpan positions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *child, ForColumns, 0); + maximumColumnIndex = std::max<size_t>(maximumColumnIndex, positions.resolvedFinalPosition()); } } @@ -1211,7 +1210,7 @@ { GridTrackSizingDirection crossDirection = specifiedDirection == ForColumns ? ForRows : ForColumns; const size_t endOfCrossDirection = crossDirection == ForColumns ? gridColumnCount() : gridRowCount(); - GridSpan crossDirectionPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), gridItem, crossDirection, GridResolvedPosition(endOfCrossDirection)); + GridSpan crossDirectionPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), gridItem, crossDirection, endOfCrossDirection); return adoptPtr(new GridCoordinate(specifiedDirection == ForColumns ? crossDirectionPositions : specifiedPositions, specifiedDirection == ForColumns ? specifiedPositions : crossDirectionPositions)); } @@ -1229,10 +1228,10 @@ GridSpan majorAxisPositions = cachedGridSpan(*autoGridItem, autoPlacementMajorAxisDirection()); ASSERT(majorAxisPositions.isDefinite()); ASSERT(!cachedGridSpan(*autoGridItem, autoPlacementMinorAxisDirection()).isDefinite()); - GridSpan minorAxisPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *autoGridItem, autoPlacementMinorAxisDirection(), GridResolvedPosition(0)); - unsigned majorAxisInitialPosition = majorAxisPositions.resolvedInitialPosition().toInt(); + GridSpan minorAxisPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *autoGridItem, autoPlacementMinorAxisDirection(), 0); + unsigned majorAxisInitialPosition = majorAxisPositions.resolvedInitialPosition(); - GridIterator iterator(m_grid, autoPlacementMajorAxisDirection(), majorAxisPositions.resolvedInitialPosition().toInt(), isGridAutoFlowDense ? 0 : minorAxisCursors.get(majorAxisInitialPosition)); + GridIterator iterator(m_grid, autoPlacementMajorAxisDirection(), majorAxisPositions.resolvedInitialPosition(), isGridAutoFlowDense ? 0 : minorAxisCursors.get(majorAxisInitialPosition)); OwnPtr<GridCoordinate> emptyGridArea = iterator.nextEmptyGridArea(majorAxisPositions.integerSpan(), minorAxisPositions.integerSpan()); if (!emptyGridArea) emptyGridArea = createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(*autoGridItem, autoPlacementMajorAxisDirection(), majorAxisPositions); @@ -1241,7 +1240,7 @@ insertItemIntoGrid(*autoGridItem, *emptyGridArea); if (!isGridAutoFlowDense) - minorAxisCursors.set(majorAxisInitialPosition, isForColumns ? emptyGridArea->rows.resolvedInitialPosition().toInt() : emptyGridArea->columns.resolvedInitialPosition().toInt()); + minorAxisCursors.set(majorAxisInitialPosition, isForColumns ? emptyGridArea->rows.resolvedInitialPosition() : emptyGridArea->columns.resolvedInitialPosition()); } } @@ -1265,7 +1264,7 @@ { GridSpan minorAxisPositions = cachedGridSpan(gridItem, autoPlacementMinorAxisDirection()); ASSERT(!cachedGridSpan(gridItem, autoPlacementMajorAxisDirection()).isDefinite()); - GridSpan majorAxisPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), gridItem, autoPlacementMajorAxisDirection(), GridResolvedPosition(0)); + GridSpan majorAxisPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), gridItem, autoPlacementMajorAxisDirection(), 0); const size_t endOfMajorAxis = (autoPlacementMajorAxisDirection() == ForColumns) ? gridColumnCount() : gridRowCount(); size_t majorAxisAutoPlacementCursor = autoPlacementMajorAxisDirection() == ForColumns ? autoPlacementCursor.second : autoPlacementCursor.first; @@ -1274,18 +1273,18 @@ OwnPtr<GridCoordinate> emptyGridArea; if (minorAxisPositions.isDefinite()) { // Move to the next track in major axis if initial position in minor axis is before auto-placement cursor. - if (minorAxisPositions.resolvedInitialPosition().toInt() < minorAxisAutoPlacementCursor) + if (minorAxisPositions.resolvedInitialPosition() < minorAxisAutoPlacementCursor) majorAxisAutoPlacementCursor++; if (majorAxisAutoPlacementCursor < endOfMajorAxis) { - GridIterator iterator(m_grid, autoPlacementMinorAxisDirection(), minorAxisPositions.resolvedInitialPosition().toInt(), majorAxisAutoPlacementCursor); + GridIterator iterator(m_grid, autoPlacementMinorAxisDirection(), minorAxisPositions.resolvedInitialPosition(), majorAxisAutoPlacementCursor); emptyGridArea = iterator.nextEmptyGridArea(minorAxisPositions.integerSpan(), majorAxisPositions.integerSpan()); } if (!emptyGridArea) emptyGridArea = createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(gridItem, autoPlacementMinorAxisDirection(), minorAxisPositions); } else { - GridSpan minorAxisPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), gridItem, autoPlacementMinorAxisDirection(), GridResolvedPosition(0)); + GridSpan minorAxisPositions = GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), gridItem, autoPlacementMinorAxisDirection(), 0); for (size_t majorAxisIndex = majorAxisAutoPlacementCursor; majorAxisIndex < endOfMajorAxis; ++majorAxisIndex) { GridIterator iterator(m_grid, autoPlacementMajorAxisDirection(), majorAxisIndex, minorAxisAutoPlacementCursor); @@ -1293,9 +1292,9 @@ if (emptyGridArea) { // Check that it fits in the minor axis direction, as we shouldn't grow in that direction here (it was already managed in populateExplicitGridAndOrderIterator()). - GridResolvedPosition minorAxisFinalPositionIndex = autoPlacementMinorAxisDirection() == ForColumns ? emptyGridArea->columns.resolvedFinalPosition() : emptyGridArea->rows.resolvedFinalPosition(); + size_t minorAxisFinalPositionIndex = autoPlacementMinorAxisDirection() == ForColumns ? emptyGridArea->columns.resolvedFinalPosition() : emptyGridArea->rows.resolvedFinalPosition(); const size_t endOfMinorAxis = autoPlacementMinorAxisDirection() == ForColumns ? gridColumnCount() : gridRowCount(); - if (minorAxisFinalPositionIndex.toInt() <= endOfMinorAxis) + if (minorAxisFinalPositionIndex <= endOfMinorAxis) break; // Discard empty grid area as it does not fit in the minor axis direction. @@ -1314,8 +1313,8 @@ m_gridItemCoordinate.set(&gridItem, *emptyGridArea); insertItemIntoGrid(gridItem, *emptyGridArea); // Move auto-placement cursor to the new position. - autoPlacementCursor.first = emptyGridArea->rows.resolvedInitialPosition().toInt(); - autoPlacementCursor.second = emptyGridArea->columns.resolvedInitialPosition().toInt(); + autoPlacementCursor.first = emptyGridArea->rows.resolvedInitialPosition(); + autoPlacementCursor.second = emptyGridArea->columns.resolvedInitialPosition(); } GridTrackSizingDirection LayoutGrid::autoPlacementMajorAxisDirection() const @@ -1418,8 +1417,8 @@ #if ENABLE(ASSERT) const GridCoordinate& coordinate = cachedGridCoordinate(*child); - ASSERT(coordinate.columns.resolvedInitialPosition().toInt() < sizingData.columnTracks.size()); - ASSERT(coordinate.rows.resolvedInitialPosition().toInt() < sizingData.rowTracks.size()); + ASSERT(coordinate.columns.resolvedInitialPosition() < sizingData.columnTracks.size()); + ASSERT(coordinate.rows.resolvedInitialPosition() < sizingData.rowTracks.size()); #endif child->setLogicalLocation(findChildLogicalPosition(*child, sizingData)); @@ -1488,22 +1487,22 @@ bool startIsAuto = startPosition.isAuto() || (startPosition.isNamedGridArea() && !GridResolvedPosition::isValidNamedLineOrArea(startPosition.namedGridLine(), styleRef(), GridResolvedPosition::initialPositionSide(direction))) - || (positions.resolvedInitialPosition().toInt() > lastTrackIndex); + || (positions.resolvedInitialPosition() > lastTrackIndex); bool endIsAuto = endPosition.isAuto() || (endPosition.isNamedGridArea() && !GridResolvedPosition::isValidNamedLineOrArea(endPosition.namedGridLine(), styleRef(), GridResolvedPosition::finalPositionSide(direction))) - || (positions.resolvedFinalPosition().prev().toInt() > lastTrackIndex); + || (positions.resolvedFinalPosition() - 1 > lastTrackIndex); - GridResolvedPosition firstPosition = GridResolvedPosition(0); - GridResolvedPosition initialPosition = startIsAuto ? firstPosition : positions.resolvedInitialPosition(); - GridResolvedPosition lastPosition = GridResolvedPosition(lastTrackIndex); - GridResolvedPosition finalPosition = endIsAuto ? lastPosition : positions.resolvedFinalPosition().prev(); + size_t firstPosition = 0; + size_t initialPosition = startIsAuto ? firstPosition : positions.resolvedInitialPosition(); + size_t lastPosition = lastTrackIndex; + size_t finalPosition = endIsAuto ? lastPosition : positions.resolvedFinalPosition() - 1; // Positioned children do not grow the grid, so we need to clamp the positions to avoid ending up outside of it. - initialPosition = std::min<GridResolvedPosition>(initialPosition, lastPosition); - finalPosition = std::min<GridResolvedPosition>(finalPosition, lastPosition); + initialPosition = std::min(initialPosition, lastPosition); + finalPosition = std::min(finalPosition, lastPosition); - LayoutUnit start = startIsAuto ? LayoutUnit() : (direction == ForColumns) ? m_columnPositions[initialPosition.toInt()] : m_rowPositions[initialPosition.toInt()]; - LayoutUnit end = endIsAuto ? (direction == ForColumns) ? logicalWidth() : logicalHeight() : (direction == ForColumns) ? m_columnPositions[finalPosition.next().toInt()] : m_rowPositions[finalPosition.next().toInt()]; + LayoutUnit start = startIsAuto ? LayoutUnit() : (direction == ForColumns) ? m_columnPositions[initialPosition] : m_rowPositions[initialPosition]; + LayoutUnit end = endIsAuto ? (direction == ForColumns) ? logicalWidth() : logicalHeight() : (direction == ForColumns) ? m_columnPositions[finalPosition + 1] : m_rowPositions[finalPosition + 1]; breadth = end - start; @@ -1545,8 +1544,8 @@ { const GridSpan& span = cachedGridSpan(child, direction); LayoutUnit gridAreaBreadth = 0; - for (GridSpan::iterator trackPosition = span.begin(); trackPosition != span.end(); ++trackPosition) - gridAreaBreadth += tracks[trackPosition.toInt()].baseSize(); + for (const auto& trackPosition : span) + gridAreaBreadth += tracks[trackPosition].baseSize(); gridAreaBreadth += guttersSize(direction, span.integerSpan()); @@ -1560,10 +1559,10 @@ const Vector<GridTrack>& tracks = (direction == ForColumns) ? sizingData.columnTracks : sizingData.rowTracks; const GridSpan& span = cachedGridSpan(child, direction); const Vector<LayoutUnit>& linePositions = (direction == ForColumns) ? m_columnPositions : m_rowPositions; - LayoutUnit initialTrackPosition = linePositions[span.resolvedInitialPosition().toInt()]; - LayoutUnit finalTrackPosition = linePositions[span.resolvedFinalPosition().prev().toInt()]; + LayoutUnit initialTrackPosition = linePositions[span.resolvedInitialPosition()]; + LayoutUnit finalTrackPosition = linePositions[span.resolvedFinalPosition() - 1]; // Track Positions vector stores the 'start' grid line of each track, so w have to add last track's baseSize. - return finalTrackPosition - initialTrackPosition + tracks[span.resolvedFinalPosition().prev().toInt()].baseSize(); + return finalTrackPosition - initialTrackPosition + tracks[span.resolvedFinalPosition() - 1].baseSize(); } void LayoutGrid::populateGridPositions(GridSizingData& sizingData) @@ -1870,7 +1869,7 @@ LayoutUnit LayoutGrid::columnAxisOffsetForChild(const LayoutBox& child) const { const GridSpan& rowsSpan = cachedGridSpan(child, ForRows); - size_t childStartLine = rowsSpan.resolvedInitialPosition().toInt(); + size_t childStartLine = rowsSpan.resolvedInitialPosition(); LayoutUnit startOfRow = m_rowPositions[childStartLine]; LayoutUnit startPosition = startOfRow + marginBeforeForChild(child); if (hasAutoMarginsInColumnAxis(child)) @@ -1881,7 +1880,7 @@ return startPosition; case GridAxisEnd: case GridAxisCenter: { - size_t childEndLine = rowsSpan.resolvedFinalPosition().toInt(); + size_t childEndLine = rowsSpan.resolvedFinalPosition(); LayoutUnit endOfRow = m_rowPositions[childEndLine]; // m_rowPositions include gutters so we need to substract them to get the actual end position for a given // row (this does not have to be done for the last track as there are no more m_rowPositions after it) @@ -1902,7 +1901,7 @@ LayoutUnit LayoutGrid::rowAxisOffsetForChild(const LayoutBox& child) const { const GridSpan& columnsSpan = cachedGridSpan(child, ForColumns); - size_t childStartLine = columnsSpan.resolvedInitialPosition().toInt(); + size_t childStartLine = columnsSpan.resolvedInitialPosition(); LayoutUnit startOfColumn = m_columnPositions[childStartLine]; LayoutUnit startPosition = startOfColumn + marginStartForChild(child); if (hasAutoMarginsInRowAxis(child)) @@ -1913,7 +1912,7 @@ return startPosition; case GridAxisEnd: case GridAxisCenter: { - size_t childEndLine = columnsSpan.resolvedFinalPosition().toInt(); + size_t childEndLine = columnsSpan.resolvedFinalPosition(); LayoutUnit endOfColumn = m_columnPositions[childEndLine]; // m_columnPositions include gutters so we need to substract them to get the actual end position for a given // column (this does not have to be done for the last track as there are no more m_columnPositions after it)
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp b/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp index 74b9964..4a9a6ab 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
@@ -1094,7 +1094,7 @@ if (oldLogicalHeight > rHeight) rowHeightIncreaseForPagination = std::max<int>(rowHeightIncreaseForPagination, oldLogicalHeight - rHeight); cell->setLogicalHeight(rHeight); - cell->computeOverflow(oldLogicalHeight); + cell->computeOverflow(oldLogicalHeight, false); } if (rowLayoutObject) @@ -1117,7 +1117,7 @@ for (size_t i = 0; i < cells.size(); ++i) { LayoutUnit oldLogicalHeight = cells[i]->logicalHeight(); cells[i]->setLogicalHeight(oldLogicalHeight + rowHeightIncreaseForPagination); - cells[i]->computeOverflow(oldLogicalHeight); + cells[i]->computeOverflow(oldLogicalHeight, false); } } }
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.h b/third_party/WebKit/Source/core/loader/EmptyClients.h index a0ae2774..9f4f7bd 100644 --- a/third_party/WebKit/Source/core/loader/EmptyClients.h +++ b/third_party/WebKit/Source/core/loader/EmptyClients.h
@@ -234,8 +234,6 @@ void didRunInsecureContent(SecurityOrigin*, const KURL&) override {} void didDetectXSS(const KURL&, bool) override {} void didDispatchPingLoader(const KURL&) override {} - void didDisplayContentWithCertificateErrors(const KURL&, const CString&, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) override {} - void didRunContentWithCertificateErrors(const KURL&, const CString&, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) override {} void selectorMatchChanged(const Vector<String>&, const Vector<String>&) override {} PassRefPtrWillBeRawPtr<LocalFrame> createFrame(const FrameLoadRequest&, const AtomicString&, HTMLFrameOwnerElement*) override; PassRefPtrWillBeRawPtr<Widget> createPlugin(HTMLPlugInElement*, const KURL&, const Vector<String>&, const Vector<String>&, const String&, bool, DetachedPluginPolicy) override;
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp index 41bed10..6be16e9e 100644 --- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp +++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -34,7 +34,6 @@ #include "bindings/core/v8/ScriptController.h" #include "core/dom/Document.h" #include "core/fetch/ClientHintsPreferences.h" -#include "core/fetch/ResourceLoader.h" #include "core/fetch/UniqueIdentifier.h" #include "core/frame/FrameConsole.h" #include "core/frame/FrameHost.h" @@ -240,9 +239,6 @@ m_documentLoader->clientHintsPreferences().updateFromAcceptClientHintsHeader(response.httpHeaderField("accept-ch"), fetcher); } - if (response.hasMajorCertificateErrors() && resourceLoader) - MixedContentChecker::handleCertificateError(frame(), resourceLoader->originalRequest(), response); - frame()->loader().progress().incrementProgress(identifier, response); frame()->loader().client()->dispatchDidReceiveResponse(m_documentLoader, identifier, response); TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceReceiveResponse", TRACE_EVENT_SCOPE_THREAD, "data", InspectorReceiveResponseEvent::data(identifier, frame(), response));
diff --git a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h index 42e507db..b492489 100644 --- a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h +++ b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
@@ -129,13 +129,6 @@ virtual void didDetectXSS(const KURL&, bool didBlockEntirePage) = 0; virtual void didDispatchPingLoader(const KURL&) = 0; - // The given main resource displayed content with certificate errors - // with the given URL and security info. - virtual void didDisplayContentWithCertificateErrors(const KURL&, const CString& securityInfo, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) = 0; - // The given main resource ran content with certificate errors with - // the given URL and security info. - virtual void didRunContentWithCertificateErrors(const KURL&, const CString& securityInfo, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) = 0; - // Will be called when |PerformanceTiming| events are updated virtual void didChangePerformanceTiming() { }
diff --git a/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp b/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp index f525cda..fdcc09b 100644 --- a/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp +++ b/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp
@@ -458,27 +458,6 @@ return effectiveFrame; } -void MixedContentChecker::handleCertificateError(LocalFrame* frame, const ResourceRequest& request, const ResourceResponse& response) -{ - WebURLRequest::FrameType frameType = request.frameType(); - LocalFrame* effectiveFrame = effectiveFrameForFrameType(frame, frameType); - if (frameType == WebURLRequest::FrameTypeTopLevel || !effectiveFrame) - return; - - FrameLoaderClient* client = effectiveFrame->loader().client(); - WebURLRequest::RequestContext requestContext = request.requestContext(); - ContextType contextType = MixedContentChecker::contextTypeFromContext(requestContext, frame); - if (contextType == ContextTypeBlockable) { - client->didRunContentWithCertificateErrors(response.url(), response.getSecurityInfo(), effectiveFrame->document()->url(), effectiveFrame->loader().documentLoader()->response().getSecurityInfo()); - } else { - // contextTypeFromContext() never returns NotMixedContent (it - // computes the type of mixed content, given that the content is - // mixed). - ASSERT(contextType != ContextTypeNotMixedContent); - client->didDisplayContentWithCertificateErrors(response.url(), response.getSecurityInfo(), effectiveFrame->document()->url(), effectiveFrame->loader().documentLoader()->response().getSecurityInfo()); - } -} - MixedContentChecker::ContextType MixedContentChecker::contextTypeForInspector(LocalFrame* frame, const ResourceRequest& request) { LocalFrame* effectiveFrame = effectiveFrameForFrameType(frame, request.frameType());
diff --git a/third_party/WebKit/Source/core/loader/MixedContentChecker.h b/third_party/WebKit/Source/core/loader/MixedContentChecker.h index e2e50c4..d88780bd 100644 --- a/third_party/WebKit/Source/core/loader/MixedContentChecker.h +++ b/third_party/WebKit/Source/core/loader/MixedContentChecker.h
@@ -31,7 +31,6 @@ #ifndef MixedContentChecker_h #define MixedContentChecker_h -#include "base/gtest_prod_util.h" #include "core/CoreExport.h" #include "platform/heap/Handle.h" #include "platform/network/ResourceRequest.h" @@ -43,7 +42,6 @@ class FrameLoaderClient; class LocalFrame; class KURL; -class ResourceResponse; class SecurityOrigin; class CORE_EXPORT MixedContentChecker final { @@ -77,10 +75,7 @@ // for a mixed content check for the given frame type. static LocalFrame* effectiveFrameForFrameType(LocalFrame*, WebURLRequest::FrameType); - static void handleCertificateError(LocalFrame*, const ResourceRequest&, const ResourceResponse&); - private: - FRIEND_TEST_ALL_PREFIXES(MixedContentCheckerTest, HandleCertificateError); enum MixedContentType { Display, Execution,
diff --git a/third_party/WebKit/Source/core/loader/MixedContentCheckerTest.cpp b/third_party/WebKit/Source/core/loader/MixedContentCheckerTest.cpp index 8b4cb217..4291c0a 100644 --- a/third_party/WebKit/Source/core/loader/MixedContentCheckerTest.cpp +++ b/third_party/WebKit/Source/core/loader/MixedContentCheckerTest.cpp
@@ -5,12 +5,9 @@ #include "config.h" #include "core/loader/MixedContentChecker.h" -#include "core/loader/EmptyClients.h" #include "core/testing/DummyPageHolder.h" -#include "platform/network/ResourceResponse.h" #include "platform/weborigin/KURL.h" #include "platform/weborigin/SecurityOrigin.h" -#include "testing/gmock/include/gmock/gmock-generated-function-mockers.h" #include "testing/gtest/include/gtest/gtest.h" #include "wtf/RefPtr.h" #include <base/macros.h> @@ -70,48 +67,4 @@ EXPECT_EQ(MixedContentChecker::ContextTypeOptionallyBlockable, MixedContentChecker::contextTypeForInspector(&dummyPageHolder->frame(), blockableMixedContent)); } -namespace { - - class MockFrameLoaderClient : public EmptyFrameLoaderClient { - public: - MockFrameLoaderClient() - : EmptyFrameLoaderClient() - { - } - MOCK_METHOD4(didDisplayContentWithCertificateErrors, void(const KURL&, const CString&, const WebURL&, const CString&)); - MOCK_METHOD4(didRunContentWithCertificateErrors, void(const KURL&, const CString&, const WebURL&, const CString&)); - }; - -} // namespace - -TEST(MixedContentCheckerTest, HandleCertificateError) -{ - MockFrameLoaderClient* client = new MockFrameLoaderClient; - OwnPtr<DummyPageHolder> dummyPageHolder = DummyPageHolder::create(IntSize(1, 1), nullptr, adoptPtrWillBeNoop(client)); - - KURL mainResourceUrl(KURL(), "https://example.test"); - KURL displayedUrl(KURL(), "https://example-displayed.test"); - KURL ranUrl(KURL(), "https://example-ran.test"); - - dummyPageHolder->frame().document()->setURL(mainResourceUrl); - ResourceRequest request1(ranUrl); - request1.setRequestContext(WebURLRequest::RequestContextScript); - request1.setFrameType(WebURLRequest::FrameTypeNone); - ResourceResponse response1; - response1.setURL(ranUrl); - response1.setSecurityInfo("security info1"); - EXPECT_CALL(*client, didRunContentWithCertificateErrors(ranUrl, response1.getSecurityInfo(), WebURL(mainResourceUrl), CString())); - MixedContentChecker::handleCertificateError(&dummyPageHolder->frame(), request1, response1); - - ResourceRequest request2(displayedUrl); - request2.setRequestContext(WebURLRequest::RequestContextImage); - request2.setFrameType(WebURLRequest::FrameTypeNone); - ResourceResponse response2; - ASSERT_EQ(MixedContentChecker::ContextTypeOptionallyBlockable, MixedContentChecker::contextTypeFromContext(request2.requestContext(), &dummyPageHolder->frame())); - response2.setURL(displayedUrl); - response2.setSecurityInfo("security info2"); - EXPECT_CALL(*client, didDisplayContentWithCertificateErrors(displayedUrl, response2.getSecurityInfo(), WebURL(mainResourceUrl), CString())); - MixedContentChecker::handleCertificateError(&dummyPageHolder->frame(), request2, response2); -} - } // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/GridPainter.cpp b/third_party/WebKit/Source/core/paint/GridPainter.cpp index 3fa13c8..d25a196 100644 --- a/third_party/WebKit/Source/core/paint/GridPainter.cpp +++ b/third_party/WebKit/Source/core/paint/GridPainter.cpp
@@ -51,9 +51,9 @@ Vector<std::pair<LayoutBox*, size_t>> gridItemsToBePainted; - for (GridSpan::iterator row = dirtiedRows.begin(); row != dirtiedRows.end(); ++row) { - for (GridSpan::iterator column = dirtiedColumns.begin(); column != dirtiedColumns.end(); ++column) { - const Vector<LayoutBox*, 1>& children = m_layoutGrid.gridCell(row.toInt(), column.toInt()); + for (const auto& row : dirtiedRows) { + for (const auto& column : dirtiedColumns) { + const Vector<LayoutBox*, 1>& children = m_layoutGrid.gridCell(row, column); for (auto* child : children) gridItemsToBePainted.append(std::make_pair(child, m_layoutGrid.paintIndexForGridItem(child))); }
diff --git a/third_party/WebKit/Source/core/style/GridCoordinate.h b/third_party/WebKit/Source/core/style/GridCoordinate.h index 9287de3..bd1592f 100644 --- a/third_party/WebKit/Source/core/style/GridCoordinate.h +++ b/third_party/WebKit/Source/core/style/GridCoordinate.h
@@ -50,7 +50,7 @@ USING_FAST_MALLOC(GridSpan); public: - static GridSpan definiteGridSpan(const GridResolvedPosition& resolvedInitialPosition, const GridResolvedPosition& resolvedFinalPosition) + static GridSpan definiteGridSpan(size_t resolvedInitialPosition, size_t resolvedFinalPosition) { return GridSpan(resolvedInitialPosition, resolvedFinalPosition, Definite); } @@ -68,30 +68,40 @@ size_t integerSpan() const { ASSERT(isDefinite()); - return m_resolvedFinalPosition.toInt() - m_resolvedInitialPosition.toInt(); + ASSERT(m_resolvedFinalPosition > m_resolvedInitialPosition); + return m_resolvedFinalPosition - m_resolvedInitialPosition; } - const GridResolvedPosition& resolvedInitialPosition() const + size_t resolvedInitialPosition() const { ASSERT(isDefinite()); return m_resolvedInitialPosition; } - const GridResolvedPosition& resolvedFinalPosition() const + size_t resolvedFinalPosition() const { ASSERT(isDefinite()); + ASSERT(m_resolvedFinalPosition); return m_resolvedFinalPosition; } - typedef GridResolvedPosition iterator; + struct GridSpanIterator { + GridSpanIterator(size_t v) : value(v) {} - iterator begin() const + size_t operator*() const { return value; } + size_t operator++() { return value++; } + bool operator!=(GridSpanIterator other) const { return value != other.value; } + + size_t value; + }; + + GridSpanIterator begin() const { ASSERT(isDefinite()); return m_resolvedInitialPosition; } - iterator end() const + GridSpanIterator end() const { ASSERT(isDefinite()); return m_resolvedFinalPosition; @@ -106,16 +116,16 @@ enum GridSpanType {Definite, Indefinite}; - GridSpan(const GridResolvedPosition& resolvedInitialPosition, const GridResolvedPosition& resolvedFinalPosition, GridSpanType type) - : m_resolvedInitialPosition(std::min(resolvedInitialPosition.toInt(), kGridMaxTracks - 1)) - , m_resolvedFinalPosition(std::min(resolvedFinalPosition.toInt(), kGridMaxTracks)) + GridSpan(size_t resolvedInitialPosition, size_t resolvedFinalPosition, GridSpanType type) + : m_resolvedInitialPosition(std::min(resolvedInitialPosition, kGridMaxTracks - 1)) + , m_resolvedFinalPosition(std::min(resolvedFinalPosition, kGridMaxTracks)) , m_type(type) { ASSERT(resolvedInitialPosition < resolvedFinalPosition); } - GridResolvedPosition m_resolvedInitialPosition; - GridResolvedPosition m_resolvedFinalPosition; + size_t m_resolvedInitialPosition; + size_t m_resolvedFinalPosition; GridSpanType m_type; };
diff --git a/third_party/WebKit/Source/core/style/GridResolvedPosition.cpp b/third_party/WebKit/Source/core/style/GridResolvedPosition.cpp index 6b8dc94..b80e5fa 100644 --- a/third_party/WebKit/Source/core/style/GridResolvedPosition.cpp +++ b/third_party/WebKit/Source/core/style/GridResolvedPosition.cpp
@@ -62,37 +62,38 @@ initialPosition.setSpanPosition(1, String()); } -static GridSpan definiteGridSpanWithInitialNamedSpanAgainstOpposite(const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, const Vector<size_t>& gridLines) +static GridSpan definiteGridSpanWithInitialNamedSpanAgainstOpposite(size_t resolvedOppositePosition, const GridPosition& position, const Vector<size_t>& gridLines) { if (resolvedOppositePosition == 0) - return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition.next()); + return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition + 1); size_t firstLineBeforeOppositePositionIndex = 0; - const size_t* firstLineBeforeOppositePosition = std::lower_bound(gridLines.begin(), gridLines.end(), resolvedOppositePosition.toInt()); + const size_t* firstLineBeforeOppositePosition = std::lower_bound(gridLines.begin(), gridLines.end(), resolvedOppositePosition); if (firstLineBeforeOppositePosition != gridLines.end()) firstLineBeforeOppositePositionIndex = firstLineBeforeOppositePosition - gridLines.begin(); size_t gridLineIndex = std::max<int>(0, firstLineBeforeOppositePositionIndex - position.spanPosition()); - GridResolvedPosition resolvedGridLinePosition = GridResolvedPosition(gridLines[gridLineIndex]); + size_t resolvedGridLinePosition = gridLines[gridLineIndex]; if (resolvedGridLinePosition >= resolvedOppositePosition) - resolvedGridLinePosition = resolvedOppositePosition.prev(); + resolvedGridLinePosition = resolvedOppositePosition - 1; return GridSpan::definiteGridSpan(resolvedGridLinePosition, resolvedOppositePosition); } -static GridSpan definiteGridSpanWithFinalNamedSpanAgainstOpposite(const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, const Vector<size_t>& gridLines) +static GridSpan definiteGridSpanWithFinalNamedSpanAgainstOpposite(size_t resolvedOppositePosition, const GridPosition& position, const Vector<size_t>& gridLines) { + ASSERT(gridLines.size()); size_t firstLineAfterOppositePositionIndex = gridLines.size() - 1; - const size_t* firstLineAfterOppositePosition = std::upper_bound(gridLines.begin(), gridLines.end(), resolvedOppositePosition.toInt()); + const size_t* firstLineAfterOppositePosition = std::upper_bound(gridLines.begin(), gridLines.end(), resolvedOppositePosition); if (firstLineAfterOppositePosition != gridLines.end()) firstLineAfterOppositePositionIndex = firstLineAfterOppositePosition - gridLines.begin(); size_t gridLineIndex = std::min(gridLines.size() - 1, firstLineAfterOppositePositionIndex + position.spanPosition() - 1); - GridResolvedPosition resolvedGridLinePosition = gridLines[gridLineIndex]; + size_t resolvedGridLinePosition = gridLines[gridLineIndex]; if (resolvedGridLinePosition <= resolvedOppositePosition) - resolvedGridLinePosition = resolvedOppositePosition.next(); + resolvedGridLinePosition = resolvedOppositePosition + 1; return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedGridLinePosition); } -static GridSpan definiteGridSpanWithNamedSpanAgainstOpposite(const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, GridPositionSide side, const Vector<size_t>& gridLines) +static GridSpan definiteGridSpanWithNamedSpanAgainstOpposite(size_t resolvedOppositePosition, const GridPosition& position, GridPositionSide side, const Vector<size_t>& gridLines) { if (side == RowStartSide || side == ColumnStartSide) return definiteGridSpanWithInitialNamedSpanAgainstOpposite(resolvedOppositePosition, position, gridLines); @@ -100,7 +101,7 @@ return definiteGridSpanWithFinalNamedSpanAgainstOpposite(resolvedOppositePosition, position, gridLines); } -static GridSpan resolveNamedGridLinePositionAgainstOppositePosition(const ComputedStyle& gridContainerStyle, const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, GridPositionSide side) +static GridSpan resolveNamedGridLinePositionAgainstOppositePosition(const ComputedStyle& gridContainerStyle, size_t resolvedOppositePosition, const GridPosition& position, GridPositionSide side) { ASSERT(position.isSpan()); ASSERT(!position.namedGridLine().isNull()); @@ -113,34 +114,34 @@ // If there is no named grid line of that name, we resolve the position to 'auto' (which is equivalent to 'span 1' in this case). // See http://lists.w3.org/Archives/Public/www-style/2013Jun/0394.html. if (it == gridLinesNames.end()) { - if ((side == ColumnStartSide || side == RowStartSide) && resolvedOppositePosition.toInt()) - return GridSpan::definiteGridSpan(resolvedOppositePosition.prev(), resolvedOppositePosition); - return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition.next()); + if ((side == ColumnStartSide || side == RowStartSide) && resolvedOppositePosition) + return GridSpan::definiteGridSpan(resolvedOppositePosition - 1, resolvedOppositePosition); + return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition + 1); } return definiteGridSpanWithNamedSpanAgainstOpposite(resolvedOppositePosition, position, side, it->value); } -static GridSpan definiteGridSpanWithSpanAgainstOpposite(const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, GridPositionSide side) +static GridSpan definiteGridSpanWithSpanAgainstOpposite(size_t resolvedOppositePosition, const GridPosition& position, GridPositionSide side) { size_t positionOffset = position.spanPosition(); if (side == ColumnStartSide || side == RowStartSide) { if (resolvedOppositePosition == 0) - return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition.next()); + return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition + 1); - GridResolvedPosition initialResolvedPosition = GridResolvedPosition(std::max<int>(0, resolvedOppositePosition.toInt() - positionOffset)); + size_t initialResolvedPosition = std::max<int>(0, resolvedOppositePosition - positionOffset); return GridSpan::definiteGridSpan(initialResolvedPosition, resolvedOppositePosition); } - return GridSpan::definiteGridSpan(resolvedOppositePosition, GridResolvedPosition(resolvedOppositePosition.toInt() + positionOffset)); + return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition + positionOffset); } -static GridSpan resolveGridPositionAgainstOppositePosition(const ComputedStyle& gridContainerStyle, const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, GridPositionSide side) +static GridSpan resolveGridPositionAgainstOppositePosition(const ComputedStyle& gridContainerStyle, size_t resolvedOppositePosition, const GridPosition& position, GridPositionSide side) { if (position.isAuto()) { - if ((side == ColumnStartSide || side == RowStartSide) && resolvedOppositePosition.toInt()) - return GridSpan::definiteGridSpan(resolvedOppositePosition.prev(), resolvedOppositePosition); - return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition.next()); + if ((side == ColumnStartSide || side == RowStartSide) && resolvedOppositePosition) + return GridSpan::definiteGridSpan(resolvedOppositePosition - 1, resolvedOppositePosition); + return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition + 1); } ASSERT(position.isSpan()); @@ -154,7 +155,7 @@ return definiteGridSpanWithSpanAgainstOpposite(resolvedOppositePosition, position, side); } -GridSpan GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(const ComputedStyle& gridContainerStyle, const LayoutBox& gridItem, GridTrackSizingDirection direction, const GridResolvedPosition& resolvedInitialPosition) +GridSpan GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(const ComputedStyle& gridContainerStyle, const LayoutBox& gridItem, GridTrackSizingDirection direction, size_t resolvedInitialPosition) { GridPosition initialPosition, finalPosition; initialAndFinalPositionsFromStyle(gridContainerStyle, gridItem, direction, initialPosition, finalPosition); @@ -164,7 +165,7 @@ // This method will only be used when both positions need to be resolved against the opposite one. ASSERT(initialPosition.shouldBeResolvedAgainstOppositePosition() && finalPosition.shouldBeResolvedAgainstOppositePosition()); - GridResolvedPosition resolvedFinalPosition = resolvedInitialPosition.next(); + size_t resolvedFinalPosition = resolvedInitialPosition + 1; if (initialPosition.isSpan()) return resolveGridPositionAgainstOppositePosition(gridContainerStyle, resolvedInitialPosition, initialPosition, finalSide); @@ -189,7 +190,7 @@ return (side == ColumnStartSide || side == ColumnEndSide) ? GridResolvedPosition::explicitGridColumnCount(gridContainerStyle) : GridResolvedPosition::explicitGridRowCount(gridContainerStyle); } -static GridResolvedPosition resolveNamedGridLinePositionFromStyle(const ComputedStyle& gridContainerStyle, const GridPosition& position, GridPositionSide side) +static size_t resolveNamedGridLinePositionFromStyle(const ComputedStyle& gridContainerStyle, const GridPosition& position, GridPositionSide side) { ASSERT(!position.namedGridLine().isNull()); @@ -197,8 +198,8 @@ NamedGridLinesMap::const_iterator it = gridLinesNames.find(position.namedGridLine()); if (it == gridLinesNames.end()) { if (position.isPositive()) - return GridResolvedPosition(0); - const size_t lastLine = explicitGridSizeForSide(gridContainerStyle, side); + return 0; + size_t lastLine = explicitGridSizeForSide(gridContainerStyle, side); return lastLine; } @@ -210,7 +211,7 @@ return it->value[namedGridLineIndex]; } -static GridResolvedPosition resolveGridPositionFromStyle(const ComputedStyle& gridContainerStyle, const GridPosition& position, GridPositionSide side) +static size_t resolveGridPositionFromStyle(const ComputedStyle& gridContainerStyle, const GridPosition& position, GridPositionSide side) { switch (position.type()) { case ExplicitPosition: { @@ -224,11 +225,11 @@ return position.integerPosition() - 1; size_t resolvedPosition = abs(position.integerPosition()) - 1; - const size_t endOfTrack = explicitGridSizeForSide(gridContainerStyle, side); + size_t endOfTrack = explicitGridSizeForSide(gridContainerStyle, side); // Per http://lists.w3.org/Archives/Public/www-style/2013Mar/0589.html, we clamp negative value to the first line. if (endOfTrack < resolvedPosition) - return GridResolvedPosition(0); + return 0; return endOfTrack - resolvedPosition; } @@ -255,16 +256,16 @@ // this function in GridResolvedPosition::resolveGridPositionsFromStyle(). We should be also covered by the // ASSERT at the beginning of this block. ASSERT_NOT_REACHED(); - return GridResolvedPosition(0); + return 0; } case AutoPosition: case SpanPosition: // 'auto' and span depend on the opposite position for resolution (e.g. grid-row: auto / 1 or grid-column: span 3 / "myHeader"). ASSERT_NOT_REACHED(); - return GridResolvedPosition(0); + return 0; } ASSERT_NOT_REACHED(); - return GridResolvedPosition(0); + return 0; } GridSpan GridResolvedPosition::resolveGridPositionsFromStyle(const ComputedStyle& gridContainerStyle, const LayoutBox& gridItem, GridTrackSizingDirection direction) @@ -282,23 +283,23 @@ if (initialPosition.shouldBeResolvedAgainstOppositePosition()) { // Infer the position from the final position ('auto / 1' or 'span 2 / 3' case). - GridResolvedPosition finalResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalSide); + size_t finalResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalSide); return resolveGridPositionAgainstOppositePosition(gridContainerStyle, finalResolvedPosition, initialPosition, initialSide); } if (finalPosition.shouldBeResolvedAgainstOppositePosition()) { // Infer our position from the initial position ('1 / auto' or '3 / span 2' case). - GridResolvedPosition initialResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialSide); + size_t initialResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialSide); return resolveGridPositionAgainstOppositePosition(gridContainerStyle, initialResolvedPosition, finalPosition, finalSide); } - GridResolvedPosition resolvedInitialPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialSide); - GridResolvedPosition resolvedFinalPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalSide); + size_t resolvedInitialPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialSide); + size_t resolvedFinalPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalSide); if (resolvedFinalPosition < resolvedInitialPosition) std::swap(resolvedFinalPosition, resolvedInitialPosition); else if (resolvedFinalPosition == resolvedInitialPosition) - resolvedFinalPosition = resolvedInitialPosition.next(); + resolvedFinalPosition = resolvedInitialPosition + 1; return GridSpan::definiteGridSpan(resolvedInitialPosition, resolvedFinalPosition); }
diff --git a/third_party/WebKit/Source/core/style/GridResolvedPosition.h b/third_party/WebKit/Source/core/style/GridResolvedPosition.h index add326d..6d4a77e 100644 --- a/third_party/WebKit/Source/core/style/GridResolvedPosition.h +++ b/third_party/WebKit/Source/core/style/GridResolvedPosition.h
@@ -26,73 +26,12 @@ ForRows }; -// This class represents a line index into one of the dimensions of the grid array. -// Wraps a size_t integer just for the purpose of knowing what we manipulate in the grid code. +// This is a utility class with all the code related to grid items positions resolution. +// TODO(rego): Rename class to GridPositionsResolver. class GridResolvedPosition { DISALLOW_NEW(); public: - GridResolvedPosition(size_t position) - : m_integerPosition(position) - { - } - - GridResolvedPosition& operator*() - { - return *this; - } - - GridResolvedPosition& operator++() - { - m_integerPosition++; - return *this; - } - - bool operator==(const GridResolvedPosition& other) const - { - return m_integerPosition == other.m_integerPosition; - } - - bool operator!=(const GridResolvedPosition& other) const - { - return m_integerPosition != other.m_integerPosition; - } - - bool operator<(const GridResolvedPosition& other) const - { - return m_integerPosition < other.m_integerPosition; - } - - bool operator>(const GridResolvedPosition& other) const - { - return m_integerPosition > other.m_integerPosition; - } - - bool operator<=(const GridResolvedPosition& other) const - { - return m_integerPosition <= other.m_integerPosition; - } - - bool operator>=(const GridResolvedPosition& other) const - { - return m_integerPosition >= other.m_integerPosition; - } - - size_t toInt() const - { - return m_integerPosition; - } - - GridResolvedPosition next() const - { - return GridResolvedPosition(m_integerPosition + 1); - } - - GridResolvedPosition prev() const - { - return GridResolvedPosition(m_integerPosition > 0 ? m_integerPosition - 1 : 0); - } - static size_t explicitGridColumnCount(const ComputedStyle&); static size_t explicitGridRowCount(const ComputedStyle&); @@ -101,12 +40,9 @@ static GridPositionSide initialPositionSide(GridTrackSizingDirection); static GridPositionSide finalPositionSide(GridTrackSizingDirection); - static GridSpan resolveGridPositionsFromAutoPlacementPosition(const ComputedStyle&, const LayoutBox&, GridTrackSizingDirection, const GridResolvedPosition&); + static GridSpan resolveGridPositionsFromAutoPlacementPosition(const ComputedStyle&, const LayoutBox&, GridTrackSizingDirection, size_t resolvedInitialPosition); static GridSpan resolveGridPositionsFromStyle(const ComputedStyle&, const LayoutBox&, GridTrackSizingDirection); -private: - - size_t m_integerPosition; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGElement.cpp b/third_party/WebKit/Source/core/svg/SVGElement.cpp index be63df4..f98217d3 100644 --- a/third_party/WebKit/Source/core/svg/SVGElement.cpp +++ b/third_party/WebKit/Source/core/svg/SVGElement.cpp
@@ -989,9 +989,6 @@ } svgRareData()->elementInstances().clear(); - - if (inDocument()) - document().updateLayoutTreeIfNeeded(); } SVGElement::InstanceUpdateBlocker::InstanceUpdateBlocker(SVGElement* targetElement)
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineEventOverview.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineEventOverview.js index 6280071..bbafd2e6 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineEventOverview.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineEventOverview.js
@@ -40,10 +40,8 @@ WebInspector.TimelineOverviewBase.call(this); this.element.id = "timeline-overview-" + id; this.element.classList.add("overview-strip"); - if (title) { - this._placeholder = this.element.createChild("div", "timeline-overview-strip-placeholder"); - this._placeholder.textContent = title; - } + if (title) + this.element.createChild("div", "timeline-overview-strip-title").textContent = title; this._model = model; } @@ -442,11 +440,13 @@ */ WebInspector.TimelineFilmStripOverview = function(model, tracingModel) { - WebInspector.TimelineEventOverview.call(this, "filmstrip", "Screenshots", model); + WebInspector.TimelineEventOverview.call(this, "filmstrip", null, model); this._tracingModel = tracingModel; this.reset(); } +WebInspector.TimelineFilmStripOverview.Padding = 2; + WebInspector.TimelineFilmStripOverview.prototype = { /** * @override @@ -479,8 +479,8 @@ if (!naturalHeight) return; var naturalWidth = image.naturalWidth; - this._imageHeight = this._canvas.height - 10 - this._imageWidth = Math.floor(this._imageHeight * naturalWidth / naturalHeight); + this._imageHeight = this._canvas.height - 2 * WebInspector.TimelineFilmStripOverview.Padding; + this._imageWidth = Math.ceil(this._imageHeight * naturalWidth / naturalHeight); } }, @@ -516,7 +516,10 @@ return; if (!this._filmStripModel.frames().length) return; + var padding = WebInspector.TimelineFilmStripOverview.Padding; var width = this._canvas.width; + var imageWidth = this._imageWidth; + var imageHeight = this._imageHeight; var zeroTime = this._tracingModel.minimumRecordTime(); var spanTime = this._tracingModel.maximumRecordTime() - zeroTime; var scale = spanTime / width; @@ -525,28 +528,26 @@ this._lastDrawGeneration = currentDrawGeneration; context.beginPath(); - for (var x = 0; x < width; x += this._imageWidth + 5) { - var time = zeroTime + (x + this._imageWidth / 2) * scale; + for (var x = padding; x < width; x += imageWidth + 2 * padding) { + var time = zeroTime + (x + imageWidth / 2) * scale; var frame = this._frameByTime(time); - context.rect(x + 0.5, 3.5, this._imageWidth + 1, this._imageHeight + 1); - this._imageByFrame(frame).then(drawFrameImage.bind(this, x, this._imageWidth, this._imageHeight)); + context.rect(x - 0.5, 0.5, imageWidth + 1, imageHeight + 1); + this._imageByFrame(frame).then(drawFrameImage.bind(this, x)); } context.strokeStyle = "#ddd"; context.stroke(); /** * @param {number} x - * @param {number} width - * @param {number} height * @param {!HTMLImageElement} image * @this {WebInspector.TimelineFilmStripOverview} */ - function drawFrameImage(x, width, height, image) + function drawFrameImage(x, image) { // Ignore draws deferred from a previous update call. if (this._lastDrawGeneration !== currentDrawGeneration) return; - context.drawImage(image, x + 1, 4, width, height); + context.drawImage(image, x, 1, imageWidth, imageHeight); } }, @@ -691,7 +692,7 @@ */ WebInspector.TimelineEventOverview.Memory = function(model) { - WebInspector.TimelineEventOverview.call(this, "memory", "Memory", model); + WebInspector.TimelineEventOverview.call(this, "memory", WebInspector.UIString("HEAP"), model); this._heapSizeLabel = this.element.createChild("div", "memory-graph-label"); }
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js index 1c35c2e..4d078be7 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js
@@ -300,7 +300,7 @@ this._detailsView.element.removeChildren(); if (!selectedNode || !this._showDetailsForNode(selectedNode)) { var banner = this._detailsView.element.createChild("div", "banner"); - banner.createTextChild(WebInspector.UIString("No details are available for current selection.")); + banner.createTextChild(WebInspector.UIString("Select item for details.")); } },
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js index fd8ece2..465a300 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
@@ -740,6 +740,9 @@ case recordTypes.CancelIdleCallback: contentHelper.appendTextRow(WebInspector.UIString("Callback ID"), eventData["id"]); break; + case recordTypes.EventDispatch: + contentHelper.appendTextRow(WebInspector.UIString("Type"), eventData["type"]); + break; default: var detailsNode = WebInspector.TimelineUIUtils.buildDetailsNodeForTraceEvent(event, model.target(), linkifier);
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css b/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css index 0c70f73..1641e3e8 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css +++ b/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
@@ -41,7 +41,6 @@ .panel.layers .banner { color: #777; background-color: white; - font-size: 14px; display: flex; justify-content: center; align-items: center; @@ -287,15 +286,15 @@ justify-content: center; } -#timeline-overview-panel .overview-strip .timeline-overview-strip-placeholder { +#timeline-overview-panel .overview-strip .timeline-overview-strip-title { color: #666; font-size: 10px; font-weight: bold; z-index: 100; background-color: rgba(255, 255, 255, 0.7); - padding: 1px 4px; + padding: 0 4px; position: absolute; - top: 0px; + top: 0; right: 0; } @@ -304,26 +303,24 @@ } #timeline-overview-network, -#timeline-overview-framerate, -#timeline-overview-memory { +#timeline-overview-framerate { flex-basis: 20px; } #timeline-overview-filmstrip { - flex-basis: 81px; + flex-basis: 40px; +} + +#timeline-overview-memory { + flex-basis: 22px; } .overview-strip::before { content: ""; position: absolute; - right: 0; - top: 0; - bottom: 0; left: 0; - color: #888; - text-align: right; - padding: 1px 4px; - font-size: 9px; + right: 0; + bottom: 0; border-bottom: 1px solid hsla(0, 0%, 0%, 0.06); z-index: -200; } @@ -332,10 +329,6 @@ display: none; } -#timeline-overview-cpu-activity .background { - z-index: -10; -} - #timeline-overview-responsiveness { flex-basis: 6px; margin-top: 1px !important; @@ -441,7 +434,7 @@ .memory-graph-label { position: absolute; right: 0; - top: 0; + bottom: 0; font-size: 9px; color: #888; white-space: nowrap; @@ -676,14 +669,15 @@ .timeline-details-view-row { display: flex; - border-bottom: 1px solid #e1e1e1; + box-shadow: #ccc 1px 1px 3px; + flex-direction: column; + background-color: white; + margin: 4px 4px 5px 4px; } .timeline-details-view-row-title { - font-weight: bold; - color: rgb(48, 57, 66); - width: 170px; - line-height: 24px; + color: rgb(152, 152, 152); + line-height: 21px; padding-left: 10px; flex: none; position: relative; @@ -708,11 +702,14 @@ } .timeline-details-view-row-value { - padding-left: 10px; - border-left: 1px solid #e1e1e1; + padding-left: 30px; min-height: 24px; line-height: 24px; -webkit-user-select: text; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + margin-right: 5px; } .timeline-details-view-row-value .stack-preview-container { @@ -731,7 +728,6 @@ .timeline-details-view-pie-chart-wrapper { margin: 8px 10px 8px 0; - min-height: 144px; } .timeline-details-view-pie-chart { @@ -1018,6 +1014,7 @@ text-align: right; overflow: hidden; text-overflow: ellipsis; + margin-left: 5px; } .timeline-tree-view .data-grid .background-bar-container { @@ -1045,3 +1042,16 @@ .timeline-details #filter-input-field { width: 120px; } + +.timeline-tree-view .data-grid .header-container { + height: 21px; +} + +.timeline-tree-view .data-grid .data-container { + top: 21px; +} + +.timeline-tree-view .data-grid th { + border-bottom: 1px solid #ddd; + background-color: #f3f3f3 +}
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js b/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js index 68aff2e..85d1212 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
@@ -1368,8 +1368,10 @@ */ function toggleCheckbox(event) { - if (event.target !== checkboxElement && event.target !== this) + if (event.target !== checkboxElement && event.target !== this) { + event.consume(); checkboxElement.click(); + } } this._root.createChild("content");
diff --git a/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp b/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp index 6998d9a..46f5dbf 100644 --- a/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp +++ b/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp
@@ -305,11 +305,6 @@ m_private->m_resourceResponse->setSecurityInfo(securityInfo); } -void WebURLResponse::setHasMajorCertificateErrors(bool value) -{ - m_private->m_resourceResponse->setHasMajorCertificateErrors(value); -} - WebURLResponse::SecurityStyle WebURLResponse::securityStyle() const { return static_cast<SecurityStyle>(m_private->m_resourceResponse->securityStyle());
diff --git a/third_party/WebKit/Source/platform/network/ResourceResponse.cpp b/third_party/WebKit/Source/platform/network/ResourceResponse.cpp index 1ba750e5..37de0b6 100644 --- a/third_party/WebKit/Source/platform/network/ResourceResponse.cpp +++ b/third_party/WebKit/Source/platform/network/ResourceResponse.cpp
@@ -48,7 +48,6 @@ , m_date(0.0) , m_expires(0.0) , m_lastModified(0.0) - , m_hasMajorCertificateErrors(false) , m_securityStyle(SecurityStyleUnknown) , m_httpVersion(HTTPVersionUnknown) , m_appCacheID(0) @@ -85,7 +84,6 @@ , m_date(0.0) , m_expires(0.0) , m_lastModified(0.0) - , m_hasMajorCertificateErrors(false) , m_securityStyle(SecurityStyleUnknown) , m_httpVersion(HTTPVersionUnknown) , m_appCacheID(0) @@ -118,7 +116,6 @@ response->setLastModifiedDate(data->m_lastModifiedDate); response->setResourceLoadTiming(data->m_resourceLoadTiming.release()); response->m_securityInfo = data->m_securityInfo; - response->m_hasMajorCertificateErrors = data->m_hasMajorCertificateErrors; response->m_securityStyle = data->m_securityStyle; response->m_securityDetails.protocol = data->m_securityDetails.protocol; response->m_securityDetails.cipher = data->m_securityDetails.cipher; @@ -164,7 +161,6 @@ if (m_resourceLoadTiming) data->m_resourceLoadTiming = m_resourceLoadTiming->deepCopy(); data->m_securityInfo = CString(m_securityInfo.data(), m_securityInfo.length()); - data->m_hasMajorCertificateErrors = m_hasMajorCertificateErrors; data->m_securityStyle = m_securityStyle; data->m_securityDetails.protocol = m_securityDetails.protocol.isolatedCopy(); data->m_securityDetails.cipher = m_securityDetails.cipher.isolatedCopy();
diff --git a/third_party/WebKit/Source/platform/network/ResourceResponse.h b/third_party/WebKit/Source/platform/network/ResourceResponse.h index 9c19606..58080de3 100644 --- a/third_party/WebKit/Source/platform/network/ResourceResponse.h +++ b/third_party/WebKit/Source/platform/network/ResourceResponse.h
@@ -160,9 +160,6 @@ const CString& getSecurityInfo() const { return m_securityInfo; } void setSecurityInfo(const CString& securityInfo) { m_securityInfo = securityInfo; } - bool hasMajorCertificateErrors() const { return m_hasMajorCertificateErrors; } - void setHasMajorCertificateErrors(bool hasMajorCertificateErrors) { m_hasMajorCertificateErrors = hasMajorCertificateErrors; } - SecurityStyle securityStyle() const { return m_securityStyle; } void setSecurityStyle(SecurityStyle securityStyle) { m_securityStyle = securityStyle; } @@ -271,10 +268,6 @@ // string if not over HTTPS). CString m_securityInfo; - // True if the resource was retrieved by the embedder in spite of - // certificate errors. - bool m_hasMajorCertificateErrors; - // The security style of the resource. // This only contains a valid value when the DevTools Network domain is // enabled. (Otherwise, it contains a default value of Unknown.) @@ -364,7 +357,6 @@ time_t m_lastModifiedDate; RefPtr<ResourceLoadTiming> m_resourceLoadTiming; CString m_securityInfo; - bool m_hasMajorCertificateErrors; ResourceResponse::SecurityStyle m_securityStyle; ResourceResponse::SecurityDetails m_securityDetails; ResourceResponse::HTTPVersion m_httpVersion;
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp index 19de8ca..df4026a 100644 --- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp +++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
@@ -677,18 +677,6 @@ m_webFrame->client()->didDispatchPingLoader(m_webFrame, url); } -void FrameLoaderClientImpl::didDisplayContentWithCertificateErrors(const KURL& url, const CString& securityInfo, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) -{ - if (m_webFrame->client()) - m_webFrame->client()->didDisplayContentWithCertificateErrors(url, securityInfo, mainResourceUrl, mainResourceSecurityInfo); -} - -void FrameLoaderClientImpl::didRunContentWithCertificateErrors(const KURL& url, const CString& securityInfo, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) -{ - if (m_webFrame->client()) - m_webFrame->client()->didRunContentWithCertificateErrors(url, securityInfo, mainResourceUrl, mainResourceSecurityInfo); -} - void FrameLoaderClientImpl::didChangePerformanceTiming() { if (m_webFrame->client())
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h index 360f5b00..518325b 100644 --- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h +++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
@@ -113,8 +113,6 @@ void didRunInsecureContent(SecurityOrigin*, const KURL& insecureURL) override; void didDetectXSS(const KURL&, bool didBlockEntirePage) override; void didDispatchPingLoader(const KURL&) override; - void didDisplayContentWithCertificateErrors(const KURL&, const CString& securityInfo, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) override; - void didRunContentWithCertificateErrors(const KURL&, const CString& securityInfo, const WebURL& mainResourceUrl, const CString& mainResourceSecurityInfo) override; void didChangePerformanceTiming() override; void selectorMatchChanged(const Vector<String>& addedSelectors, const Vector<String>& removedSelectors) override; PassRefPtrWillBeRawPtr<DocumentLoader> createDocumentLoader(LocalFrame*, const ResourceRequest&, const SubstituteData&) override;
diff --git a/third_party/WebKit/public/platform/WebURLResponse.h b/third_party/WebKit/public/platform/WebURLResponse.h index 3a64468..c7a5b0b 100644 --- a/third_party/WebKit/public/platform/WebURLResponse.h +++ b/third_party/WebKit/public/platform/WebURLResponse.h
@@ -146,8 +146,6 @@ BLINK_PLATFORM_EXPORT WebCString securityInfo() const; BLINK_PLATFORM_EXPORT void setSecurityInfo(const WebCString&); - BLINK_PLATFORM_EXPORT void setHasMajorCertificateErrors(bool); - BLINK_PLATFORM_EXPORT SecurityStyle securityStyle() const; BLINK_PLATFORM_EXPORT void setSecurityStyle(SecurityStyle);
diff --git a/third_party/WebKit/public/web/WebFrameClient.h b/third_party/WebKit/public/web/WebFrameClient.h index 89f2cef..e603a05 100644 --- a/third_party/WebKit/public/web/WebFrameClient.h +++ b/third_party/WebKit/public/web/WebFrameClient.h
@@ -67,7 +67,6 @@ class WebColorChooserClient; class WebContentDecryptionModule; class WebCookieJar; -class WebCString; class WebDataSource; class WebEncryptedMediaClient; class WebExternalPopupMenu; @@ -450,13 +449,6 @@ // A PingLoader was created, and a request dispatched to a URL. virtual void didDispatchPingLoader(WebLocalFrame*, const WebURL&) { } - // This frame has displayed inactive content (such as an image) from - // a connection with certificate errors. - virtual void didDisplayContentWithCertificateErrors(const WebURL& url, const WebCString& securityInfo, const WebURL& mainResourceUrl, const WebCString& mainResourceSecurityInfo) {} - // This frame has run active content (such as a script) from a - // connection with certificate errors. - virtual void didRunContentWithCertificateErrors(const WebURL& url, const WebCString& securityInfo, const WebURL& mainResourceUrl, const WebCString& mainResourceSecurityInfo) {} - // A performance timing event (e.g. first paint) occurred virtual void didChangePerformanceTiming() { }
diff --git a/third_party/mojo/src/mojo/edk/embedder/embedder.cc b/third_party/mojo/src/mojo/edk/embedder/embedder.cc index 692547ac..00c48ea 100644 --- a/third_party/mojo/src/mojo/edk/embedder/embedder.cc +++ b/third_party/mojo/src/mojo/edk/embedder/embedder.cc
@@ -65,6 +65,7 @@ void OnShutdownComplete() { passed_in_delegate_->OnShutdownComplete(); + delete this; } private: @@ -248,6 +249,8 @@ internal::g_ipc_support->ShutdownOnIOThread(); delete internal::g_ipc_support; internal::g_ipc_support = nullptr; + delete g_wrapper_process_delegate; + g_wrapper_process_delegate = nullptr; } void ShutdownIPCSupport() {
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 5ea6df9..389e013 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -367,16 +367,6 @@ </summary> </histogram> -<histogram name="AppBanners.MinutesFromFirstVisitToBannerShown" units="minutes"> - <owner>dominickn@chromium.org</owner> - <summary> - App banners promote an application related to the current website, and are - requested specifically through the current page's HTML. This stat tracks - the number of minutes between the first recorded visit to an origin and the - time when the banner is actually shown. - </summary> -</histogram> - <histogram name="AppBanners.UserResponse" enum="AppBannersUserResponse"> <owner>dominickn@chromium.org</owner> <summary> @@ -79775,6 +79765,9 @@ <suffix name="ContentLength_Image_WEBP" label="for each carrier, number of WebP image responses whose Content-Length header has been tampered with"/> + <suffix name="ContentLength_Video" + label="for each carrier, number of video responses whose Content-Length + header has been tampered with"/> <suffix name="CompressionRatio_Image" label="the histogram of compression ratio of images"/> <suffix name="CompressionRatio_Image_GIF" @@ -79785,6 +79778,8 @@ label="the histogram of compression ratio of PNG images"/> <suffix name="CompressionRatio_Image_WEBP" label="the histogram of compression ratio of WEBP images"/> + <suffix name="CompressionRatio_Video" + label="the histogram of compression ratio of videos"/> <suffix name="CompressionRatio_Image_0_10KB" label="the histogram of compression ratio of images whose sizes are in the range of 0-10KB"/> @@ -79838,6 +79833,8 @@ <affected-histogram name="DataReductionProxy.HeaderTamperDetectionHTTP_Image_WEBP"/> <affected-histogram name="DataReductionProxy.HeaderTamperDetectionHTTP_JS"/> + <affected-histogram + name="DataReductionProxy.HeaderTamperDetectionHTTP_Video"/> <affected-histogram name="DataReductionProxy.HeaderTamperDetectionHTTPS"/> <affected-histogram name="DataReductionProxy.HeaderTamperDetectionHTTPS_CSS"/> <affected-histogram @@ -79859,6 +79856,8 @@ <affected-histogram name="DataReductionProxy.HeaderTamperDetectionHTTPS_Image_WEBP"/> <affected-histogram name="DataReductionProxy.HeaderTamperDetectionHTTPS_JS"/> + <affected-histogram + name="DataReductionProxy.HeaderTamperDetectionHTTPS_Video"/> <affected-histogram name="DataReductionProxy.HeaderTamperDetectionPassHTTP"/> <affected-histogram name="DataReductionProxy.HeaderTamperDetectionPassHTTPS"/> <affected-histogram name="DataReductionProxy.HeaderTamperedHTTP_ChromeProxy"/> @@ -79903,6 +79902,7 @@ <suffix name="Image_JPG" label="JPG image count"/> <suffix name="Image_PNG" label="PNG image count"/> <suffix name="Image_WEBP" label="WEBP image count"/> + <suffix name="Video" label="Video count"/> <suffix name="Image_0_10KB" label="image counts of 0-10KB"/> <suffix name="Image_10_100KB" label="image counts of 10-100KB"/> <suffix name="Image_100_500KB" label="image counts of 100-500KB"/>
diff --git a/tools/telemetry/telemetry/record_wpr.py b/tools/telemetry/telemetry/record_wpr.py index 0cd8241..c53f35a 100644 --- a/tools/telemetry/telemetry/record_wpr.py +++ b/tools/telemetry/telemetry/record_wpr.py
@@ -17,6 +17,8 @@ from telemetry.internal.util import command_line from telemetry.page import page_test from telemetry.util import wpr_modes +from telemetry.web_perf import timeline_based_measurement +from telemetry.web_perf import timeline_based_page_test class RecorderPageTest(page_test.PageTest): @@ -128,9 +130,11 @@ self._ParseArgs(args) self._ProcessCommandLineArgs() if self._benchmark is not None: + test = self._benchmark.CreatePageTest(self.options) + if isinstance(test, timeline_based_measurement.TimelineBasedMeasurement): + test = timeline_based_page_test.TimelineBasedPageTest(test) # This must be called after the command line args are added. - self._record_page_test.page_test = self._benchmark.CreatePageTest( - self.options) + self._record_page_test.page_test = test self._page_set_base_dir = ( self._options.page_set_base_dir if self._options.page_set_base_dir
diff --git a/tools/telemetry/telemetry/record_wpr_unittest.py b/tools/telemetry/telemetry/record_wpr_unittest.py index e313679..471584f 100644 --- a/tools/telemetry/telemetry/record_wpr_unittest.py +++ b/tools/telemetry/telemetry/record_wpr_unittest.py
@@ -67,7 +67,28 @@ class MockBenchmark(benchmark.Benchmark): test = MockPageTest - mock_story_set = None + + def __init__(self): + super(MockBenchmark, self).__init__() + self.mock_story_set = None + + @classmethod + def AddBenchmarkCommandLineArgs(cls, group): + group.add_option('', '--mock-benchmark-url', action='store', type='string') + + def CreateStorySet(self, options): + kwargs = {} + if options.mock_benchmark_url: + kwargs['url'] = options.mock_benchmark_url + self.mock_story_set = MockStorySet(**kwargs) + return self.mock_story_set + + +class MockTimelineBasedMeasurementBenchmark(benchmark.Benchmark): + + def __init__(self): + super(MockTimelineBasedMeasurementBenchmark, self).__init__() + self.mock_story_set = None @classmethod def AddBenchmarkCommandLineArgs(cls, group): @@ -148,6 +169,17 @@ self.assertEqual(set(mock_benchmark.mock_story_set.stories), results.pages_that_succeeded) + def testWprRecorderWithTimelineBasedMeasurementBenchmark(self): + flags = self.GetBrowserDeviceFlags() + flags.extend(['--mock-benchmark-url', self._url]) + mock_benchmark = MockTimelineBasedMeasurementBenchmark() + wpr_recorder = record_wpr.WprRecorder(self._test_data_dir, mock_benchmark, + flags) + results = wpr_recorder.CreateResults() + wpr_recorder.Record(results) + self.assertEqual(set(mock_benchmark.mock_story_set.stories), + results.pages_that_succeeded) + def testPageSetBaseDirFlag(self): flags = self.GetBrowserDeviceFlags() flags.extend(['--page-set-base-dir', self._test_data_dir,