Allow client hints only for secure or local origins

Currently, the non-persistent client hints may be sent on non-secure
URLs. This CL changes it so that client hints (persistent or
non-persistent) are sent only on secure or local origins.

Bug: 782381
Change-Id: I50a184d7aa19813eacc59e4d9fca5e74ec8855f2
Reviewed-on: https://chromium-review.googlesource.com/758464
Commit-Queue: Tarun Bansal <[email protected]>
Reviewed-by: Ryan Sturm <[email protected]>
Reviewed-by: Kinuko Yasuda <[email protected]>
Cr-Commit-Position: refs/heads/master@{#515229}
diff --git a/chrome/browser/client_hints/client_hints_browsertest.cc b/chrome/browser/client_hints/client_hints_browsertest.cc
index ef72324..6a1346a 100644
--- a/chrome/browser/client_hints/client_hints_browsertest.cc
+++ b/chrome/browser/client_hints/client_hints_browsertest.cc
@@ -29,19 +29,31 @@
 class ClientHintsBrowserTest : public InProcessBrowserTest {
  public:
   ClientHintsBrowserTest()
-      : https_server_(net::EmbeddedTestServer::TYPE_HTTPS),
+      : http_server_(net::EmbeddedTestServer::TYPE_HTTP),
+        https_server_(net::EmbeddedTestServer::TYPE_HTTPS),
         expect_client_hints_(false),
         expect_client_hints_on_main_frame_only_(false),
         count_client_hints_headers_seen_(0) {
+    http_server_.ServeFilesFromSourceDirectory("chrome/test/data/client_hints");
     https_server_.ServeFilesFromSourceDirectory(
         "chrome/test/data/client_hints");
 
+    http_server_.RegisterRequestMonitor(
+        base::Bind(&ClientHintsBrowserTest::MonitorResourceRequest,
+                   base::Unretained(this)));
     https_server_.RegisterRequestMonitor(
         base::Bind(&ClientHintsBrowserTest::MonitorResourceRequest,
                    base::Unretained(this)));
 
+    EXPECT_TRUE(http_server_.Start());
     EXPECT_TRUE(https_server_.Start());
 
+    accept_ch_with_lifetime_http_local_url_ =
+        http_server_.GetURL("/accept_ch_with_lifetime.html");
+    EXPECT_TRUE(accept_ch_with_lifetime_http_local_url_.SchemeIsHTTPOrHTTPS());
+    EXPECT_FALSE(
+        accept_ch_with_lifetime_http_local_url_.SchemeIsCryptographic());
+
     accept_ch_with_lifetime_url_ =
         https_server_.GetURL("/accept_ch_with_lifetime.html");
     EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsHTTPOrHTTPS());
@@ -57,6 +69,13 @@
     EXPECT_TRUE(without_accept_ch_without_lifetime_url_.SchemeIsHTTPOrHTTPS());
     EXPECT_TRUE(
         without_accept_ch_without_lifetime_url_.SchemeIsCryptographic());
+
+    without_accept_ch_without_lifetime_local_url_ =
+        http_server_.GetURL("/without_accept_ch_without_lifetime.html");
+    EXPECT_TRUE(
+        without_accept_ch_without_lifetime_local_url_.SchemeIsHTTPOrHTTPS());
+    EXPECT_FALSE(
+        without_accept_ch_without_lifetime_local_url_.SchemeIsCryptographic());
   }
 
   ~ClientHintsBrowserTest() override {}
@@ -79,6 +98,10 @@
     expect_client_hints_on_main_frame_only_ = expect_client_hints;
   }
 
+  const GURL& accept_ch_with_lifetime_http_local_url() const {
+    return accept_ch_with_lifetime_http_local_url_;
+  }
+
   // A URL whose response headers include Accept-CH and Accept-CH-Lifetime
   // headers.
   const GURL& accept_ch_with_lifetime_url() const {
@@ -96,6 +119,12 @@
     return without_accept_ch_without_lifetime_url_;
   }
 
+  // A URL whose response headers do not include either Accept-CH or
+  // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image.
+  const GURL& without_accept_ch_without_lifetime_local_url() const {
+    return without_accept_ch_without_lifetime_local_url_;
+  }
+
   size_t count_client_hints_headers_seen() const {
     return count_client_hints_headers_seen_;
   }
@@ -138,10 +167,13 @@
       count_client_hints_headers_seen_++;
   }
 
+  net::EmbeddedTestServer http_server_;
   net::EmbeddedTestServer https_server_;
+  GURL accept_ch_with_lifetime_http_local_url_;
   GURL accept_ch_with_lifetime_url_;
   GURL accept_ch_without_lifetime_url_;
   GURL without_accept_ch_without_lifetime_url_;
+  GURL without_accept_ch_without_lifetime_local_url_;
 
   bool expect_client_hints_;
   // Expect client hints only on the main frame request, and not on
@@ -172,6 +204,59 @@
                                       3600 * 1000, 1);
 }
 
+// Loads a HTTP local webpage (which qualifies as a secure context) that
+// requests persisting of client hints. Verifies that the browser receives the
+// mojo notification from the renderer and persists the client hints to the
+// disk.
+IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
+                       ClientHintsLifetimeFollowedByNoClientHintHttpLocal) {
+  base::HistogramTester histogram_tester;
+  ContentSettingsForOneType host_settings;
+
+  HostContentSettingsMapFactory::GetForProfile(browser()->profile())
+      ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
+                              &host_settings);
+  EXPECT_EQ(0u, host_settings.size());
+
+  ui_test_utils::NavigateToURL(browser(),
+                               accept_ch_with_lifetime_http_local_url());
+
+  histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
+
+  content::FetchHistogramsFromChildProcesses();
+  SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
+
+  // client_hints_url() sets two client hints.
+  histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 2, 1);
+  // accept_ch_with_lifetime_http_local_url() sets client hints persist duration
+  // to 3600 seconds.
+  histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
+                                      3600 * 1000, 1);
+
+  base::RunLoop().RunUntilIdle();
+
+  // Clients hints preferences for one origin should be persisted.
+  HostContentSettingsMapFactory::GetForProfile(browser()->profile())
+      ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
+                              &host_settings);
+  EXPECT_EQ(1u, host_settings.size());
+
+  SetClientHintExpectations(true);
+  ui_test_utils::NavigateToURL(browser(),
+                               without_accept_ch_without_lifetime_local_url());
+
+  if (content::IsBrowserSideNavigationEnabled()) {
+    // When browser side navigation is enabled, two client hints are attached to
+    // the image request, and the device-memory header is attached to the main
+    // frame request.
+    EXPECT_EQ(3u, count_client_hints_headers_seen());
+  } else {
+    // When browser side navigation is not enabled, two client hints are
+    // attached to each of the HTML and the image requests.
+    EXPECT_EQ(4u, count_client_hints_headers_seen());
+  }
+}
+
 // Loads a webpage that does not request persisting of client hints.
 IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, NoClientHintsHttps) {
   base::HistogramTester histogram_tester;