blob: 56a6659e627af6f67f3e49283c16fd2c840d4250 [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2015 The Chromium Authors
nick5f3d76072015-06-09 00:24:002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Arthur Sonzognic686e8f2024-01-11 08:36:375#include <optional>
nick5f3d76072015-06-09 00:24:006#include <string>
7
nick5f3d76072015-06-09 00:24:008#include "base/command_line.h"
9#include "base/files/file_path.h"
Ari Chivukula0be980cd2025-01-30 03:32:4110#include "base/files/file_util.h"
Avi Drissmanadac21992023-01-11 23:46:3911#include "base/functional/bind.h"
12#include "base/functional/callback_helpers.h"
Daniel Cheng3a350ed2024-09-05 00:29:3913#include "base/strings/strcat.h"
Guido Urdanetaef4e91942020-11-09 15:06:2414#include "base/test/bind.h"
Chris Fredricksonb4cf8402022-09-23 22:59:5915#include "base/test/scoped_feature_list.h"
Olivier Li140ade52025-02-06 20:36:0716#include "base/threading/platform_thread.h"
17#include "base/time/time.h"
nick462f92832015-12-04 18:47:4518#include "content/browser/bad_message.h"
danakjc492bf82020-09-09 20:02:4419#include "content/browser/renderer_host/frame_tree.h"
nick5f3d76072015-06-09 00:24:0020#include "content/browser/web_contents/web_contents_impl.h"
Maks Orlovich710d5e32019-07-09 20:16:4521#include "content/public/browser/browser_context.h"
Eric Seckler8652dcd52018-09-20 10:42:2822#include "content/public/browser/browser_task_traits.h"
Gabriel Charette790754c2018-03-16 21:32:5923#include "content/public/browser/browser_thread.h"
nick5f3d76072015-06-09 00:24:0024#include "content/public/browser/render_process_host.h"
W. James MacLean693869ee2024-06-25 17:23:5825#include "content/public/browser/site_isolation_policy.h"
Maks Orlovich710d5e32019-07-09 20:16:4526#include "content/public/browser/storage_partition.h"
Hans Wennborg5ffd1392019-10-16 11:00:0227#include "content/public/common/content_client.h"
nick5f3d76072015-06-09 00:24:0028#include "content/public/common/content_switches.h"
Peter Kasting919ce652020-05-07 10:22:3629#include "content/public/test/browser_test.h"
nick5f3d76072015-06-09 00:24:0030#include "content/public/test/browser_test_utils.h"
31#include "content/public/test/content_browser_test.h"
Scott Violet99861992023-02-08 01:20:1232#include "content/public/test/content_browser_test_content_browser_client.h"
nick5f3d76072015-06-09 00:24:0033#include "content/public/test/content_browser_test_utils.h"
Joshua Thomas14008362025-03-26 14:06:4734#include "content/public/test/test_devtools_protocol_client.h"
carlosk15fb0f02015-07-29 17:07:5135#include "content/public/test/test_utils.h"
nick5f3d76072015-06-09 00:24:0036#include "content/shell/browser/shell.h"
37#include "content/test/content_browser_test_utils_internal.h"
38#include "ipc/ipc_security_test_util.h"
Chris Fredricksonb4cf8402022-09-23 22:59:5939#include "net/base/features.h"
Ari Chivukula0be980cd2025-01-30 03:32:4140#include "net/base/filename_util.h"
Maks Orlovich710d5e32019-07-09 20:16:4541#include "net/cookies/canonical_cookie.h"
Chris Fredrickson34237ce2025-05-13 16:36:1442#include "net/cookies/canonical_cookie_test_helpers.h"
Ayu Ishiif3966ca2020-07-08 17:35:1243#include "net/cookies/cookie_access_result.h"
Lily Chenf068a762019-08-21 21:10:5044#include "net/cookies/cookie_util.h"
nick5f3d76072015-06-09 00:24:0045#include "net/dns/mock_host_resolver.h"
Aaron Tagliaboschi6ed3c0692022-02-27 18:54:0046#include "net/http/alternative_service.h"
Chris Fredrickson9ffdf5b2024-07-09 20:05:0947#include "net/storage_access_api/status.h"
nick5f3d76072015-06-09 00:24:0048#include "net/test/embedded_test_server/embedded_test_server.h"
Aldo Culquicondorcfb369e2025-03-18 19:19:0449#include "services/network/public/cpp/features.h"
Chris Fredricksonf9de3452022-09-12 21:46:5650#include "services/network/public/cpp/network_switches.h"
Maks Orlovich710d5e32019-07-09 20:16:4551#include "services/network/public/mojom/restricted_cookie_manager.mojom-test-utils.h"
52#include "services/network/public/mojom/restricted_cookie_manager.mojom.h"
53#include "services/service_manager/public/cpp/interface_provider.h"
nick462f92832015-12-04 18:47:4554#include "testing/gmock/include/gmock/gmock.h"
nick5f3d76072015-06-09 00:24:0055#include "testing/gtest/include/gtest/gtest.h"
Aldo Culquicondor5bf8bc232025-03-20 14:51:3956#include "third_party/blink/public/common/features_generated.h"
mkwstdf1821c62016-02-24 13:07:2057#include "url/gurl.h"
nick5f3d76072015-06-09 00:24:0058
Chris Fredrickson34237ce2025-05-13 16:36:1459using testing::IsEmpty;
60using testing::Key;
61using testing::UnorderedElementsAre;
62
nick5f3d76072015-06-09 00:24:0063namespace content {
64
65namespace {
66
Joshua Thomas14008362025-03-26 14:06:4767void EnableDevtoolsThirdPartyCookieRestriction(
68 TestDevToolsProtocolClient& frame_devtools_client) {
69 base::Value::Dict command_params;
70 frame_devtools_client.SendCommandSync("Network.enable");
71 command_params.Set("enableThirdPartyCookieRestriction", true);
72 command_params.Set("disableThirdPartyCookieMetadata", false);
73 command_params.Set("disableThirdPartyCookieHeuristics", false);
74 frame_devtools_client.SendCommandAsync("Network.setCookieControls",
75 std::move(command_params));
76}
77
Maks Orlovich710d5e32019-07-09 20:16:4578void SetCookieFromJS(RenderFrameHost* frame, std::string cookie) {
79 EvalJsResult result = EvalJs(frame, "document.cookie = '" + cookie + "'");
80 EXPECT_TRUE(result.error.empty()) << result.error;
81}
82
nick5f3d76072015-06-09 00:24:0083std::string GetCookieFromJS(RenderFrameHost* frame) {
Avi Drissman49ecc702021-04-15 20:37:4184 return EvalJs(frame, "document.cookie;").ExtractString();
nick5f3d76072015-06-09 00:24:0085}
86
Maks Orlovich710d5e32019-07-09 20:16:4587void SetCookieDirect(WebContentsImpl* tab,
88 const GURL& url,
89 const std::string& cookie_line) {
Lily Chene1d272a52019-08-12 17:00:5690 net::CookieOptions options;
91 // Allow setting SameSite cookies.
92 options.set_same_site_cookie_context(
Steven Bingler8d76c2a42020-03-24 17:13:3293 net::CookieOptions::SameSiteCookieContext::MakeInclusive());
Lily Chene1d272a52019-08-12 17:00:5694
Ari Chivukula92851c32024-04-09 12:37:4495 auto cookie_obj = net::CanonicalCookie::CreateForTesting(url, cookie_line,
96 base::Time::Now());
Maks Orlovich710d5e32019-07-09 20:16:4597
98 base::RunLoop run_loop;
Lukasz Anforowiczb9a969a2021-04-29 15:26:2599 tab->GetBrowserContext()
100 ->GetDefaultStoragePartition()
Maks Orlovich710d5e32019-07-09 20:16:45101 ->GetCookieManagerForBrowserProcess()
102 ->SetCanonicalCookie(
Lily Chen96f29a132020-04-15 17:59:36103 *cookie_obj, url, options,
Maks Orlovich710d5e32019-07-09 20:16:45104 base::BindLambdaForTesting(
Ayu Ishiif3966ca2020-07-08 17:35:12105 [&](net::CookieAccessResult status) { run_loop.Quit(); }));
Maks Orlovich710d5e32019-07-09 20:16:45106 run_loop.Run();
107}
108
109std::string GetCookiesDirect(WebContentsImpl* tab, const GURL& url) {
Lily Chene1d272a52019-08-12 17:00:56110 net::CookieOptions options;
111 // Allow setting SameSite cookies.
112 options.set_same_site_cookie_context(
Steven Bingler8d76c2a42020-03-24 17:13:32113 net::CookieOptions::SameSiteCookieContext::MakeInclusive());
Maks Orlovich710d5e32019-07-09 20:16:45114 net::CookieList result;
115 base::RunLoop run_loop;
Lukasz Anforowiczb9a969a2021-04-29 15:26:25116 tab->GetBrowserContext()
117 ->GetDefaultStoragePartition()
Maks Orlovich710d5e32019-07-09 20:16:45118 ->GetCookieManagerForBrowserProcess()
Ayu Ishiibc6fdb0a2020-06-08 22:59:19119 ->GetCookieList(
Aykut Bulut244341e2021-12-09 15:57:25120 url, options, net::CookiePartitionKeyCollection(),
Ayu Ishiibc6fdb0a2020-06-08 22:59:19121 base::BindLambdaForTesting(
122 [&](const net::CookieAccessResultList& cookie_list,
123 const net::CookieAccessResultList& excluded_cookies) {
124 result = net::cookie_util::StripAccessResults(cookie_list);
125 run_loop.Quit();
126 }));
Maks Orlovich710d5e32019-07-09 20:16:45127 run_loop.Run();
128 return net::CanonicalCookie::BuildCookieLine(result);
rockot6a2d66a2016-08-04 00:15:25129}
130
nick5f3d76072015-06-09 00:24:00131} // namespace
132
Aldo Culquicondor5bf8bc232025-03-20 14:51:39133class CookieBrowserTest
134 : public ContentBrowserTest,
135 public ::testing::WithParamInterface<std::tuple<bool, bool>> {
Aldo Culquicondorcfb369e2025-03-18 19:19:04136 public:
Chris Fredrickson34237ce2025-05-13 16:36:14137 CookieBrowserTest()
138 : https_server_(net::test_server::EmbeddedTestServer::TYPE_HTTPS) {
Aldo Culquicondor5bf8bc232025-03-20 14:51:39139 scoped_feature_list_.InitWithFeatureStates(
140 {{network::features::kGetCookiesOnSet, GetCookiesOnSetEnabled()},
141 {blink::features::kAsyncSetCookie, AsyncSetCookieEnabled()}});
Aldo Culquicondorcfb369e2025-03-18 19:19:04142 }
143 ~CookieBrowserTest() override = default;
144
mkwstf71d0bd2016-03-21 14:15:24145 protected:
Andrew Williams748874612023-07-24 19:55:17146 void SetUpCommandLine(base::CommandLine* command_line) override {
147 command_line->AppendSwitch(
mkwstf71d0bd2016-03-21 14:15:24148 switches::kEnableExperimentalWebPlatformFeatures);
mkwstf71d0bd2016-03-21 14:15:24149 }
jam8f34ea72017-04-26 17:48:55150
151 void SetUpOnMainThread() override {
152 // Support multiple sites on the test server.
153 host_resolver()->AddRule("*", "127.0.0.1");
Chris Fredrickson34237ce2025-05-13 16:36:14154 https_server_.AddDefaultHandlers(GetTestDataFilePath());
155 https_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
156 SetupCrossSiteRedirector(&https_server_);
157 ASSERT_TRUE(https_server_.Start());
jam8f34ea72017-04-26 17:48:55158 }
Aldo Culquicondorcfb369e2025-03-18 19:19:04159
Aldo Culquicondor5bf8bc232025-03-20 14:51:39160 bool GetCookiesOnSetEnabled() { return std::get<0>(GetParam()); }
161
162 bool AsyncSetCookieEnabled() { return std::get<1>(GetParam()); }
163
Chris Fredrickson34237ce2025-05-13 16:36:14164 net::test_server::EmbeddedTestServer https_server_;
Aldo Culquicondorcfb369e2025-03-18 19:19:04165 base::test::ScopedFeatureList scoped_feature_list_;
mkwstf71d0bd2016-03-21 14:15:24166};
nick5f3d76072015-06-09 00:24:00167
Aldo Culquicondor5bf8bc232025-03-20 14:51:39168INSTANTIATE_TEST_SUITE_P(
169 ,
170 CookieBrowserTest,
171 testing::Combine(testing::Bool(), testing::Bool()),
172 [](const testing::TestParamInfo<std::tuple<bool, bool>>& info) {
173 std::string name =
174 std::get<0>(info.param) ? "GetOnSetEnabled" : "GetOnSetDisabled";
175 name += "_";
176 name += std::get<1>(info.param) ? "Async" : "Sync";
177 return name;
178 });
Aldo Culquicondorcfb369e2025-03-18 19:19:04179
nick5f3d76072015-06-09 00:24:00180// Exercises basic cookie operations via javascript, including an http page
181// interacting with secure cookies.
Aldo Culquicondorcfb369e2025-03-18 19:19:04182IN_PROC_BROWSER_TEST_P(CookieBrowserTest, Cookies) {
nick5f3d76072015-06-09 00:24:00183 SetupCrossSiteRedirector(embedded_test_server());
martijn12d2dad2016-11-11 10:59:27184 ASSERT_TRUE(embedded_test_server()->Start());
nick5f3d76072015-06-09 00:24:00185
Lily Chen15b3ff882021-05-21 01:27:41186 // The server sends a HttpOnly cookie. The RestrictedCookieManager should
nick462f92832015-12-04 18:47:45187 // never allow this to be sent to any renderer process.
Maks Orlovichbd04d782020-11-17 21:23:34188 GURL https_url =
Chris Fredrickson34237ce2025-05-13 16:36:14189 https_server_.GetURL("a.test", "/set-cookie?notforjs=1;HttpOnly");
Maks Orlovichbd04d782020-11-17 21:23:34190 GURL http_url =
191 embedded_test_server()->GetURL("a.test", "/frame_with_load_event.html");
nick5f3d76072015-06-09 00:24:00192
193 Shell* shell2 = CreateBrowser();
Alex Moshchukaa95adf52019-08-13 00:02:02194 EXPECT_TRUE(NavigateToURL(shell(), http_url));
195 EXPECT_TRUE(NavigateToURL(shell2, https_url));
nick5f3d76072015-06-09 00:24:00196
197 WebContentsImpl* web_contents_https =
198 static_cast<WebContentsImpl*>(shell2->web_contents());
199 WebContentsImpl* web_contents_http =
200 static_cast<WebContentsImpl*>(shell()->web_contents());
Sharon Yang02279222025-01-15 19:09:19201 if (AreAllSitesIsolatedForTesting()) {
Maks Orlovichbd04d782020-11-17 21:23:34202 EXPECT_EQ("http://a.test/",
Aaron Colwelle953e562019-07-24 16:47:36203 web_contents_http->GetSiteInstance()->GetSiteURL().spec());
W. James MacLean03da92242024-06-14 13:46:04204 // Create expected site url, including port if origin isolation is enabled.
205 std::string expected_site_url =
W. James MacLean693869ee2024-06-25 17:23:58206 SiteIsolationPolicy::AreOriginKeyedProcessesEnabledByDefault()
W. James MacLean03da92242024-06-14 13:46:04207 ? url::Origin::Create(https_url).GetURL().spec()
208 : std::string("https://a.test/");
209 EXPECT_EQ(expected_site_url,
Aaron Colwelle953e562019-07-24 16:47:36210 web_contents_https->GetSiteInstance()->GetSiteURL().spec());
Sharon Yang02279222025-01-15 19:09:19211 } else {
212 // Note: Both use the default SiteInstance because the URLs don't require
213 // a dedicated process, but these default SiteInstances are not the same
214 // object because they come from different BrowsingInstances.
215 EXPECT_TRUE(web_contents_http->GetSiteInstance()->IsDefaultSiteInstance());
216 EXPECT_TRUE(web_contents_https->GetSiteInstance()->IsDefaultSiteInstance());
217 EXPECT_NE(web_contents_http->GetSiteInstance(),
218 web_contents_https->GetSiteInstance());
219 EXPECT_FALSE(web_contents_http->GetSiteInstance()->IsRelatedSiteInstance(
220 web_contents_https->GetSiteInstance()));
Aaron Colwelle953e562019-07-24 16:47:36221 }
nick5f3d76072015-06-09 00:24:00222
223 EXPECT_NE(web_contents_http->GetSiteInstance()->GetProcess(),
224 web_contents_https->GetSiteInstance()->GetProcess());
225
Dave Tapuska327c06c92022-06-13 20:31:51226 EXPECT_EQ("", GetCookieFromJS(web_contents_https->GetPrimaryMainFrame()));
227 EXPECT_EQ("", GetCookieFromJS(web_contents_http->GetPrimaryMainFrame()));
nick5f3d76072015-06-09 00:24:00228
229 // Non-TLS page writes secure cookie.
Dave Tapuska327c06c92022-06-13 20:31:51230 EXPECT_TRUE(ExecJs(web_contents_http->GetPrimaryMainFrame(),
Avi Drissman49ecc702021-04-15 20:37:41231 "document.cookie = 'A=1; secure;';"));
Dave Tapuska327c06c92022-06-13 20:31:51232 EXPECT_EQ("", GetCookieFromJS(web_contents_https->GetPrimaryMainFrame()));
233 EXPECT_EQ("", GetCookieFromJS(web_contents_http->GetPrimaryMainFrame()));
nick5f3d76072015-06-09 00:24:00234
Joshua Hoodf54ef852022-02-23 17:33:58235 // Non-TLS page writes not-secure cookie.
Dave Tapuska327c06c92022-06-13 20:31:51236 EXPECT_TRUE(ExecJs(web_contents_http->GetPrimaryMainFrame(),
237 "document.cookie = 'B=2';"));
Dave Tapuska327c06c92022-06-13 20:31:51238 EXPECT_EQ("B=2", GetCookieFromJS(web_contents_http->GetPrimaryMainFrame()));
Aldo Culquicondorcfb369e2025-03-18 19:19:04239 EXPECT_EQ("B=2", GetCookieFromJS(web_contents_https->GetPrimaryMainFrame()));
nick5f3d76072015-06-09 00:24:00240
mkwstf71d0bd2016-03-21 14:15:24241 // TLS page writes secure cookie.
Dave Tapuska327c06c92022-06-13 20:31:51242 EXPECT_TRUE(ExecJs(web_contents_https->GetPrimaryMainFrame(),
Avi Drissman49ecc702021-04-15 20:37:41243 "document.cookie = 'C=3;secure;';"));
Dave Tapuska327c06c92022-06-13 20:31:51244 EXPECT_EQ("B=2; C=3",
245 GetCookieFromJS(web_contents_https->GetPrimaryMainFrame()));
246 EXPECT_EQ("B=2", GetCookieFromJS(web_contents_http->GetPrimaryMainFrame()));
nick5f3d76072015-06-09 00:24:00247
248 // TLS page writes not-secure cookie.
Dave Tapuska327c06c92022-06-13 20:31:51249 EXPECT_TRUE(ExecJs(web_contents_https->GetPrimaryMainFrame(),
250 "document.cookie = 'D=4';"));
mkwstf71d0bd2016-03-21 14:15:24251 EXPECT_EQ("B=2; C=3; D=4",
Dave Tapuska327c06c92022-06-13 20:31:51252 GetCookieFromJS(web_contents_https->GetPrimaryMainFrame()));
253 EXPECT_EQ("B=2; D=4",
254 GetCookieFromJS(web_contents_http->GetPrimaryMainFrame()));
nick5f3d76072015-06-09 00:24:00255}
256
Joshua Bell1d432be2018-06-27 19:59:48257// Ensure "priority" cookie option is settable via document.cookie.
Aldo Culquicondorcfb369e2025-03-18 19:19:04258IN_PROC_BROWSER_TEST_P(CookieBrowserTest, CookiePriority) {
Joshua Bell1d432be2018-06-27 19:59:48259 ASSERT_TRUE(embedded_test_server()->Start());
260
261 struct {
262 std::string param;
263 net::CookiePriority priority;
264 } cases[] = {{"name=value", net::COOKIE_PRIORITY_DEFAULT},
265 {"name=value;priority=Low", net::COOKIE_PRIORITY_LOW},
266 {"name=value;priority=Medium", net::COOKIE_PRIORITY_MEDIUM},
267 {"name=value;priority=High", net::COOKIE_PRIORITY_HIGH}};
268
269 for (auto test_case : cases) {
270 GURL url = embedded_test_server()->GetURL("/set_document_cookie.html?" +
271 test_case.param);
Alex Moshchukaa95adf52019-08-13 00:02:02272 EXPECT_TRUE(NavigateToURL(shell(), url));
Joshua Bell1d432be2018-06-27 19:59:48273 std::vector<net::CanonicalCookie> cookies =
274 GetCanonicalCookies(shell()->web_contents()->GetBrowserContext(), url);
275
276 EXPECT_EQ(1u, cookies.size());
277 EXPECT_EQ("name", cookies[0].Name());
278 EXPECT_EQ("value", cookies[0].Value());
279 EXPECT_EQ(test_case.priority, cookies[0].Priority());
280 }
281}
282
mkwstdf1821c62016-02-24 13:07:20283// SameSite cookies (that aren't marked as http-only) should be available to
284// JavaScript.
Aldo Culquicondorcfb369e2025-03-18 19:19:04285IN_PROC_BROWSER_TEST_P(CookieBrowserTest, SameSiteCookies) {
Lily Chene1d272a52019-08-12 17:00:56286 // Must use HTTPS because SameSite=None cookies must be Secure.
mkwstdf1821c62016-02-24 13:07:20287
David Benjaminddf9671c32019-12-03 16:54:12288 // The server sets eight cookies on 'a.test' and on 'b.test', then loads
289 // a page that frames both 'a.test' and 'b.test' under 'a.test'.
mkwstf71d0bd2016-03-21 14:15:24290 std::string cookies_to_set =
Lily Chene1d272a52019-08-12 17:00:56291 "/set-cookie?none=1;SameSite=None;Secure" // SameSite=None must be
292 // Secure.
293 "&none-insecure=1;SameSite=None"
mkwstf71d0bd2016-03-21 14:15:24294 "&strict=1;SameSite=Strict"
Lily Chene1d272a52019-08-12 17:00:56295 "&unspecified=1" // unspecified SameSite should be treated as Lax.
mkwstf71d0bd2016-03-21 14:15:24296 "&lax=1;SameSite=Lax"
Lily Chene1d272a52019-08-12 17:00:56297 "&none-http=1;SameSite=None;Secure;httponly"
mkwstf71d0bd2016-03-21 14:15:24298 "&strict-http=1;SameSite=Strict;httponly"
Lily Chene1d272a52019-08-12 17:00:56299 "&unspecified-http=1;httponly"
mkwstf71d0bd2016-03-21 14:15:24300 "&lax-http=1;SameSite=Lax;httponly";
301
Chris Fredrickson34237ce2025-05-13 16:36:14302 GURL url = https_server_.GetURL("a.test", cookies_to_set);
Alex Moshchukaeb20fe32019-09-25 17:40:01303 EXPECT_TRUE(NavigateToURL(shell(), url));
Chris Fredrickson34237ce2025-05-13 16:36:14304 url = https_server_.GetURL("b.test", cookies_to_set);
Alex Moshchukaeb20fe32019-09-25 17:40:01305 EXPECT_TRUE(NavigateToURL(shell(), url));
Chris Fredrickson34237ce2025-05-13 16:36:14306 url = https_server_.GetURL(
David Benjaminddf9671c32019-12-03 16:54:12307 "a.test", "/cross_site_iframe_factory.html?a.test(a.test(),b.test())");
Alex Moshchukaa95adf52019-08-13 00:02:02308 EXPECT_TRUE(NavigateToURL(shell(), url));
mkwstdf1821c62016-02-24 13:07:20309
310 WebContentsImpl* web_contents =
311 static_cast<WebContentsImpl*>(shell()->web_contents());
Dave Tapuska327c06c92022-06-13 20:31:51312 RenderFrameHost* main_frame = web_contents->GetPrimaryMainFrame();
Carlos Caballero15caeeb2021-10-27 09:57:55313 RenderFrameHost* a_iframe = web_contents->GetPrimaryFrameTree()
314 .root()
315 ->child_at(0)
316 ->current_frame_host();
317 RenderFrameHost* b_iframe = web_contents->GetPrimaryFrameTree()
318 .root()
319 ->child_at(1)
320 ->current_frame_host();
mkwstdf1821c62016-02-24 13:07:20321
Lily Chene1d272a52019-08-12 17:00:56322 // The top-level frame should get all same-site cookies.
323 EXPECT_EQ("none=1; strict=1; unspecified=1; lax=1",
324 GetCookieFromJS(main_frame));
mkwstf71d0bd2016-03-21 14:15:24325
326 // Same-site cookies will be delievered to the 'a.com' frame, as it is same-
327 // site with its ancestors.
Lily Chene1d272a52019-08-12 17:00:56328 EXPECT_EQ("none=1; strict=1; unspecified=1; lax=1",
329 GetCookieFromJS(a_iframe));
mkwstf71d0bd2016-03-21 14:15:24330
331 // Same-site cookies should not be delievered to the 'b.com' frame, as it
Lily Chene1d272a52019-08-12 17:00:56332 // isn't same-site with its ancestors. The SameSite=None but insecure cookie
333 // is rejected.
334 EXPECT_EQ("none=1", GetCookieFromJS(b_iframe));
mkwstdf1821c62016-02-24 13:07:20335}
336
Chris Fredrickson34237ce2025-05-13 16:36:14337// Prefixed cookies (that aren't marked as http-only) should be available to
338// JavaScript.
339IN_PROC_BROWSER_TEST_P(CookieBrowserTest, PrefixedCookies_Read) {
340 // Must use HTTPS because prefixed cookies must be Secure.
341
342 ASSERT_TRUE(SetCookie(shell()->web_contents()->GetBrowserContext(),
343 https_server_.GetURL("a.test", "/"),
344 "__Host-cookie=1;Secure;Path=/"));
345 ASSERT_TRUE(SetCookie(shell()->web_contents()->GetBrowserContext(),
346 https_server_.GetURL("a.test", "/"),
347 "__Secure-cookie=1;Secure"));
348 ASSERT_TRUE(SetCookie(shell()->web_contents()->GetBrowserContext(),
349 https_server_.GetURL("a.test", "/"),
350 "__Secure-http-cookie=1;Secure;HttpOnly"));
351
352 EXPECT_TRUE(
353 NavigateToURL(shell(), https_server_.GetURL("a.test", "/empty.html")));
354
355 EXPECT_THAT(EvalJs(shell(), "document.cookie").ExtractString(),
356 net::CookieStringIs(UnorderedElementsAre(
357 Key("__Host-cookie"), Key("__Secure-cookie"))));
358}
359
360IN_PROC_BROWSER_TEST_P(CookieBrowserTest, PrefixedCookies_Read_Insecure) {
361 ASSERT_TRUE(embedded_test_server()->Start());
362 ASSERT_TRUE(SetCookie(shell()->web_contents()->GetBrowserContext(),
363 https_server_.GetURL("a.test", "/"),
364 "__Host-cookie=1;Secure;Path=/"));
365 ASSERT_TRUE(SetCookie(shell()->web_contents()->GetBrowserContext(),
366 https_server_.GetURL("a.test", "/"),
367 "__Secure-cookie=1;Secure"));
368 ASSERT_TRUE(SetCookie(shell()->web_contents()->GetBrowserContext(),
369 https_server_.GetURL("a.test", "/"),
370 "__Secure-http-cookie=1;Secure;HttpOnly"));
371
372 EXPECT_TRUE(NavigateToURL(
373 shell(), embedded_test_server()->GetURL("a.test", "/empty.html")));
374
375 EXPECT_EQ(EvalJs(shell(), "document.cookie"), "");
376}
377
378// Prefixed cookies should be writable by JavaScript.
379IN_PROC_BROWSER_TEST_P(CookieBrowserTest, PrefixedCookies_Write) {
380 // Must use HTTPS because prefixed cookies must be Secure.
381
382 EXPECT_TRUE(
383 NavigateToURL(shell(), https_server_.GetURL("a.test", "/empty.html")));
384
385 EXPECT_TRUE(ExecJs(shell(), R"js(
386 // Valid cookies:
387 document.cookie = "__Host-cookie=1;Secure;Path=/";
388 document.cookie = "__Secure-cookie=1;Secure";
389 // Invalid cookies:
390 document.cookie = "__Secure-http-cookie=1;Secure;HttpOnly";
391 document.cookie = "__Secure-missing-attr=1";
392 document.cookie = "__Host-wrong-path=1;Secure;";
393 document.cookie = "__Host-wrong-domain=1;Secure;Domain=a.test";
394 document.cookie = "__Host-wrong-secure=1;Path=/";
395 )js"));
396
397 EXPECT_THAT(GetCanonicalCookies(shell()->web_contents()->GetBrowserContext(),
398 https_server_.GetURL("a.test", "/")),
399 UnorderedElementsAre(
400 net::MatchesCookieNameValue("__Host-cookie", "1"),
401 net::MatchesCookieNameValue("__Secure-cookie", "1")));
402}
403
404IN_PROC_BROWSER_TEST_P(CookieBrowserTest, PrefixedCookies_Write_Insecure) {
405 ASSERT_TRUE(embedded_test_server()->Start());
406 EXPECT_TRUE(NavigateToURL(
407 shell(), embedded_test_server()->GetURL("a.test", "/empty.html")));
408
409 EXPECT_TRUE(ExecJs(shell(), R"js(
410 document.cookie = "__Host-cookie=1;Secure;Path=/";
411 document.cookie = "__Secure-cookie=1;Secure";
412 document.cookie = "__Secure-http-cookie=1;Secure;HttpOnly";
413 document.cookie = "__Secure-missing-attr=1";
414 document.cookie = "__Host-wrong-path=1;Secure;";
415 document.cookie = "__Host-wrong-domain=1;Secure;Domain=a.test";
416 document.cookie = "__Host-wrong-secure=1;Path=/";
417 )js"));
418
419 EXPECT_THAT(
420 GetCanonicalCookies(shell()->web_contents()->GetBrowserContext(),
421 embedded_test_server()->GetURL("a.test", "/")),
422 IsEmpty());
423}
424
Joshua Thomas14008362025-03-26 14:06:47425IN_PROC_BROWSER_TEST_P(CookieBrowserTest,
426 CookieJarInvalidatesCacheWithNewDevtoolsControls) {
427 // Must use HTTPS because SameSite=None cookies must be Secure.
Joshua Thomas14008362025-03-26 14:06:47428
429 // Set a single cookie that we'll access from a third-party context
430 std::string cookies_to_set =
431 "/set-cookie?none=1;SameSite=None;Secure"; // SameSite=None must be
432 // Secure
433
Chris Fredrickson34237ce2025-05-13 16:36:14434 GURL url = https_server_.GetURL("b.test", cookies_to_set);
Joshua Thomas14008362025-03-26 14:06:47435 EXPECT_TRUE(NavigateToURL(shell(), url));
436
437 WebContentsImpl* web_contents =
438 static_cast<WebContentsImpl*>(shell()->web_contents());
439 // Turn on third-party cookie restriction from devtools. This needs to happen
440 // from a top level client
441 TestDevToolsProtocolClient devtools_client;
442 devtools_client.AttachToWebContents(web_contents);
443 EnableDevtoolsThirdPartyCookieRestriction(devtools_client);
444
Chris Fredrickson34237ce2025-05-13 16:36:14445 url = https_server_.GetURL(
446 "a.test", "/cross_site_iframe_factory.html?a.test(b.test())");
Joshua Thomas14008362025-03-26 14:06:47447 EXPECT_TRUE(NavigateToURL(shell(), url));
448
449 RenderFrameHost* oop_iframe = web_contents->GetPrimaryFrameTree()
450 .root()
451 ->child_at(0)
452 ->current_frame_host();
453
454 // Attach devtools client to the sub frame, but disable the controls at first
455 devtools_client.DetachProtocolClient();
456 devtools_client.AttachToFrameTreeHost(oop_iframe);
457 devtools_client.SendCommandSync("Network.disable");
458
459 // Check Get->Get
460 // Overrides should not apply after disabling the controls
461 EXPECT_EQ("none=1", GetCookieFromJS(oop_iframe));
462
463 // Confirm cache is invalidated by observing new value from document.cookie
464 // when re-enabling devtools
465 devtools_client.SendCommandSync("Network.enable");
466 EXPECT_EQ("", GetCookieFromJS(oop_iframe));
467
468 // Check Set->Get
469 // Set a cookie with devtools disabled
470 devtools_client.SendCommandSync("Network.disable");
471 SetCookieFromJS(oop_iframe, "none=2; SameSite=None; Secure");
472
473 // Confirm cache is invalidated by observing no cookie from document.cookie
474 // when re-enabling devtools
475 devtools_client.SendCommandSync("Network.enable");
476 EXPECT_EQ("", GetCookieFromJS(oop_iframe));
477
478 devtools_client.DetachProtocolClient();
479}
480
Aldo Culquicondorcfb369e2025-03-18 19:19:04481IN_PROC_BROWSER_TEST_P(CookieBrowserTest, CookieTruncatingCharFromJavascript) {
Andrew Williams748874612023-07-24 19:55:17482 ASSERT_TRUE(embedded_test_server()->Start());
483
484 ASSERT_TRUE(
485 NavigateToURL(shell(), embedded_test_server()->GetURL("/empty.html")));
486
487 WebContentsImpl* tab = static_cast<WebContentsImpl*>(shell()->web_contents());
488 RenderFrameHost* frame = tab->GetPrimaryMainFrame();
489
490 // Test scenarios where a control char may appear at start, middle and end of
491 // a cookie line. Control char array with NULL (\x0), CR (\xD), and LF (xA).
492 const std::string kTestChars[] = {"\\x00", "\\x0D", "\\x0A"};
493
494 for (const std::string& ctl_string : kTestChars) {
495 // Control char at the start of the string.
496 // Note that when truncation of this cookie string occurs, no histogram
497 // entries get recorded because the code bails out early on the resulting
498 // empty cookie string.
Daniel Cheng3a350ed2024-09-05 00:29:39499 std::string cookie_string = base::StrCat({ctl_string, "foo1=bar"});
Andrew Williams748874612023-07-24 19:55:17500 SetCookieFromJS(frame, cookie_string);
501
502 // Control char in the middle of the string.
Daniel Cheng3a350ed2024-09-05 00:29:39503 cookie_string = base::StrCat({"foo2=bar;", ctl_string, "httponly"});
Andrew Williams748874612023-07-24 19:55:17504 SetCookieFromJS(frame, cookie_string);
505
Daniel Cheng3a350ed2024-09-05 00:29:39506 cookie_string = base::StrCat({"foo3=ba", ctl_string, "r; httponly"});
Andrew Williams748874612023-07-24 19:55:17507 SetCookieFromJS(frame, cookie_string);
508
509 // Control char at the end of the string.
Daniel Cheng3a350ed2024-09-05 00:29:39510 cookie_string = base::StrCat({"foo4=bar;", ctl_string});
Andrew Williams748874612023-07-24 19:55:17511 SetCookieFromJS(frame, cookie_string);
512 }
513
Andrew Williamsb19527f2024-05-17 14:05:14514 EXPECT_EQ("", GetCookieFromJS(frame));
Andrew Williams748874612023-07-24 19:55:17515}
516
Aldo Culquicondorcfb369e2025-03-18 19:19:04517IN_PROC_BROWSER_TEST_P(CookieBrowserTest, CookieTruncatingCharFromHeaders) {
Aaron Tagliaboschi6ed3c0692022-02-27 18:54:00518 std::string cookie_string;
519 embedded_test_server()->RegisterRequestHandler(base::BindLambdaForTesting(
520 [&](const net::test_server::HttpRequest& request)
521 -> std::unique_ptr<net::test_server::HttpResponse> {
522 auto response = std::make_unique<net::test_server::BasicHttpResponse>();
523 response->AddCustomHeader("Set-Cookie", cookie_string);
524 return std::move(response);
525 }));
526
527 ASSERT_TRUE(embedded_test_server()->Start());
528
529 GURL http_url = embedded_test_server()->GetURL("/");
Aaron Tagliaboschi6ed3c0692022-02-27 18:54:00530
531 // Test scenarios where a control char may appear at start, middle and end of
532 // a cookie line. Control char array with NULL (\x0), CR (\xD), and LF (xA)
533 char kTestChars[] = {'\x0', '\xD', '\xA'};
534
535 for (const auto& test : kTestChars) {
536 std::string ctl_string(1, test);
537
538 // ctrl char at start of string
Daniel Cheng3a350ed2024-09-05 00:29:39539 cookie_string = base::StrCat({ctl_string, "foo=bar"});
Aaron Tagliaboschi6ed3c0692022-02-27 18:54:00540 EXPECT_TRUE(NavigateToURL(shell(), http_url));
541
542 // ctrl char at middle of string
Daniel Cheng3a350ed2024-09-05 00:29:39543 cookie_string = base::StrCat({"foo=bar;", ctl_string, "httponly"});
Aaron Tagliaboschi6ed3c0692022-02-27 18:54:00544 EXPECT_TRUE(NavigateToURL(shell(), http_url));
545
Daniel Cheng3a350ed2024-09-05 00:29:39546 cookie_string = base::StrCat({"foo=ba", ctl_string, "r; httponly"});
Andrew Williams748874612023-07-24 19:55:17547 EXPECT_TRUE(NavigateToURL(shell(), http_url));
548
Aaron Tagliaboschi6ed3c0692022-02-27 18:54:00549 // ctrl char at end of string
Daniel Cheng3a350ed2024-09-05 00:29:39550 cookie_string = base::StrCat({"foo=bar;", "httponly;", ctl_string});
Aaron Tagliaboschi6ed3c0692022-02-27 18:54:00551 EXPECT_TRUE(NavigateToURL(shell(), http_url));
552 }
553 // Test if there are multiple control characters that terminate.
Daniel Cheng3a350ed2024-09-05 00:29:39554 cookie_string = "foo=bar;\xA\xDhttponly";
Aaron Tagliaboschi6ed3c0692022-02-27 18:54:00555 EXPECT_TRUE(NavigateToURL(shell(), http_url));
Aaron Tagliaboschi6ed3c0692022-02-27 18:54:00556}
557
Maks Orlovich710d5e32019-07-09 20:16:45558class RestrictedCookieManagerInterceptor
559 : public network::mojom::RestrictedCookieManagerInterceptorForTesting {
560 public:
561 RestrictedCookieManagerInterceptor(
Julie Jeongeun Kimd20f64b2019-08-26 04:13:03562 mojo::PendingReceiver<network::mojom::RestrictedCookieManager> receiver,
Julie Jeongeun Kimf42b07c2019-08-27 15:38:36563 mojo::PendingRemote<network::mojom::RestrictedCookieManager> real_rcm)
Julie Jeongeun Kimd20f64b2019-08-26 04:13:03564 : receiver_(this, std::move(receiver)), real_rcm_(std::move(real_rcm)) {}
Maks Orlovich710d5e32019-07-09 20:16:45565
Arthur Sonzognic686e8f2024-01-11 08:36:37566 void set_override_url(std::optional<std::string> maybe_url) {
Maks Orlovich710d5e32019-07-09 20:16:45567 override_url_ = std::move(maybe_url);
568 }
569
Chris Fredrickson9ffdf5b2024-07-09 20:05:09570 void SetCookieFromString(
571 const GURL& url,
572 const net::SiteForCookies& site_for_cookies,
573 const url::Origin& top_frame_origin,
574 net::StorageAccessApiStatus storage_access_api_status,
Aldo Culquicondorcfb369e2025-03-18 19:19:04575 bool get_version_shared_memory,
Aldo Culquicondor262e9992025-03-24 16:02:24576 bool is_ad_tagged,
Joshua Thomasd362203f2025-01-21 18:15:57577 bool apply_devtools_overrides,
Chris Fredrickson9ffdf5b2024-07-09 20:05:09578 const std::string& cookie,
579 SetCookieFromStringCallback callback) override {
Maks Orlovich710d5e32019-07-09 20:16:45580 GetForwardingInterface()->SetCookieFromString(
Chris Fredrickson9ffdf5b2024-07-09 20:05:09581 URLToUse(url), site_for_cookies, top_frame_origin,
Aldo Culquicondor262e9992025-03-24 16:02:24582 storage_access_api_status, get_version_shared_memory, is_ad_tagged,
Aldo Culquicondorcfb369e2025-03-18 19:19:04583 apply_devtools_overrides, std::move(cookie), std::move(callback));
Maks Orlovich710d5e32019-07-09 20:16:45584 }
585
586 void GetCookiesString(const GURL& url,
Maks Orlovichab27e242020-01-07 18:10:39587 const net::SiteForCookies& site_for_cookies,
Christian Dullweber10d62c12019-08-19 12:08:19588 const url::Origin& top_frame_origin,
Chris Fredrickson9ffdf5b2024-07-09 20:05:09589 net::StorageAccessApiStatus storage_access_api_status,
Olivier Lic0c141022023-07-05 16:25:51590 bool get_version_shared_memory,
John Delaney637f6ea2023-11-06 17:14:27591 bool is_ad_tagged,
Rupert Ben Wiser5fbe73e2024-02-28 19:15:31592 bool force_disable_third_party_cookies,
Joshua Thomasd362203f2025-01-21 18:15:57593 bool apply_devtools_overrides,
Maks Orlovich710d5e32019-07-09 20:16:45594 GetCookiesStringCallback callback) override {
595 GetForwardingInterface()->GetCookiesString(
Chris Fredrickson9ffdf5b2024-07-09 20:05:09596 URLToUse(url), site_for_cookies, top_frame_origin,
597 storage_access_api_status, get_version_shared_memory, is_ad_tagged,
Joshua Thomasd362203f2025-01-21 18:15:57598 force_disable_third_party_cookies, apply_devtools_overrides,
599 std::move(callback));
Maks Orlovich710d5e32019-07-09 20:16:45600 }
601
602 private:
603 network::mojom::RestrictedCookieManager* GetForwardingInterface() override {
604 return real_rcm_.get();
605 }
606
607 GURL URLToUse(const GURL& url_in) {
608 return override_url_ ? GURL(override_url_.value()) : url_in;
609 }
610
Arthur Sonzognic686e8f2024-01-11 08:36:37611 std::optional<std::string> override_url_;
Maks Orlovich710d5e32019-07-09 20:16:45612
Julie Jeongeun Kimd20f64b2019-08-26 04:13:03613 mojo::Receiver<network::mojom::RestrictedCookieManager> receiver_;
Julie Jeongeun Kimf42b07c2019-08-27 15:38:36614 mojo::Remote<network::mojom::RestrictedCookieManager> real_rcm_;
Maks Orlovich710d5e32019-07-09 20:16:45615};
616
Scott Violet99861992023-02-08 01:20:12617class CookieStoreContentBrowserClient
618 : public ContentBrowserTestContentBrowserClient {
Maks Orlovich710d5e32019-07-09 20:16:45619 public:
Chris Fredrickson5d0cb4f2022-09-27 16:48:42620 ~CookieStoreContentBrowserClient() override = default;
Maks Orlovich710d5e32019-07-09 20:16:45621
622 bool WillCreateRestrictedCookieManager(
Maks Orloviche7db7a22019-07-25 01:47:46623 network::mojom::RestrictedCookieManagerRole role,
Maks Orlovich710d5e32019-07-09 20:16:45624 content::BrowserContext* browser_context,
Shuran Huangbd4d1692021-01-26 17:03:41625 const url::Origin& origin,
Shuran Huang92b415d72021-01-12 20:48:15626 const net::IsolationInfo& isolation_info,
Maks Orlovich710d5e32019-07-09 20:16:45627 bool is_service_worker,
628 int process_id,
629 int routing_id,
Julie Jeongeun Kimd20f64b2019-08-26 04:13:03630 mojo::PendingReceiver<network::mojom::RestrictedCookieManager>* receiver)
631 override {
632 mojo::PendingReceiver<network::mojom::RestrictedCookieManager>
633 orig_receiver = std::move(*receiver);
Maks Orlovich710d5e32019-07-09 20:16:45634
Julie Jeongeun Kimf42b07c2019-08-27 15:38:36635 mojo::PendingRemote<network::mojom::RestrictedCookieManager> real_rcm;
636 *receiver = real_rcm.InitWithNewPipeAndPassReceiver();
Maks Orlovich710d5e32019-07-09 20:16:45637
638 rcm_interceptor_ = std::make_unique<RestrictedCookieManagerInterceptor>(
Julie Jeongeun Kimd20f64b2019-08-26 04:13:03639 std::move(orig_receiver), std::move(real_rcm));
Maks Orlovich710d5e32019-07-09 20:16:45640 rcm_interceptor_->set_override_url(override_url_);
641
642 return false; // only made a proxy, still need the actual impl to be made.
643 }
644
Arthur Sonzognic686e8f2024-01-11 08:36:37645 void set_override_url(std::optional<std::string> maybe_url) {
Maks Orlovich710d5e32019-07-09 20:16:45646 override_url_ = maybe_url;
647 if (rcm_interceptor_)
648 rcm_interceptor_->set_override_url(override_url_);
649 }
650
651 private:
Arthur Sonzognic686e8f2024-01-11 08:36:37652 std::optional<std::string> override_url_;
Maks Orlovich710d5e32019-07-09 20:16:45653 std::unique_ptr<RestrictedCookieManagerInterceptor> rcm_interceptor_;
654};
655
656// Cookie access in loader is locked to a particular origin, so messages
657// for wrong URLs are rejected.
Alison Gale923a33e2024-04-22 23:34:28658// TODO(crbug.com/41453892): This should actually result in renderer
Maks Orlovich710d5e32019-07-09 20:16:45659// kills.
Aldo Culquicondorcfb369e2025-03-18 19:19:04660IN_PROC_BROWSER_TEST_P(CookieBrowserTest, CrossSiteCookieSecurityEnforcement) {
nick5f3d76072015-06-09 00:24:00661 // The code under test is only active under site isolation.
nickd30fd962015-07-27 21:51:08662 if (!AreAllSitesIsolatedForTesting()) {
nick5f3d76072015-06-09 00:24:00663 return;
664 }
665
nick5f3d76072015-06-09 00:24:00666 SetupCrossSiteRedirector(embedded_test_server());
martijn12d2dad2016-11-11 10:59:27667 ASSERT_TRUE(embedded_test_server()->Start());
Alex Moshchukaa95adf52019-08-13 00:02:02668 EXPECT_TRUE(NavigateToURL(
669 shell(), embedded_test_server()->GetURL("/frame_with_load_event.html")));
nick5f3d76072015-06-09 00:24:00670
671 WebContentsImpl* tab = static_cast<WebContentsImpl*>(shell()->web_contents());
672
673 // The iframe on the http page should get its own process.
674 FrameTreeVisualizer v;
675 EXPECT_EQ(
676 " Site A ------------ proxies for B\n"
677 " +--Site B ------- proxies for A\n"
678 "Where A = http://127.0.0.1/\n"
679 " B = http://baz.com/",
Carlos Caballero15caeeb2021-10-27 09:57:55680 v.DepictFrameTree(tab->GetPrimaryFrameTree().root()));
nick5f3d76072015-06-09 00:24:00681
Dave Tapuska327c06c92022-06-13 20:31:51682 RenderFrameHost* main_frame = tab->GetPrimaryMainFrame();
nick5f3d76072015-06-09 00:24:00683 RenderFrameHost* iframe =
Carlos Caballero15caeeb2021-10-27 09:57:55684 tab->GetPrimaryFrameTree().root()->child_at(0)->current_frame_host();
nick5f3d76072015-06-09 00:24:00685
686 EXPECT_NE(iframe->GetProcess(), main_frame->GetProcess());
687
Maks Orlovich710d5e32019-07-09 20:16:45688 SetCookieDirect(tab, GURL("http://127.0.0.1/"), "A_cookie = parent");
689 SetCookieDirect(tab, GURL("http://baz.com/"), "B_cookie = child");
690 EXPECT_EQ("A_cookie=parent",
691 GetCookiesDirect(tab, GURL("http://127.0.0.1/")));
692
693 EXPECT_EQ("B_cookie=child", GetCookiesDirect(tab, GURL("http://baz.com/")));
694
695 // Try to get cross-site cookies from the subframe's process.
Lukasz Anforowicz6f746282018-01-04 23:24:51696 {
Maks Orlovich710d5e32019-07-09 20:16:45697 CookieStoreContentBrowserClient browser_client;
Maks Orlovich710d5e32019-07-09 20:16:45698 browser_client.set_override_url("http://127.0.0.1/");
699 EXPECT_EQ("", GetCookieFromJS(iframe));
Lukasz Anforowicz6f746282018-01-04 23:24:51700 }
nick5f3d76072015-06-09 00:24:00701
702 EXPECT_EQ(
703 " Site A ------------ proxies for B\n"
704 " +--Site B ------- proxies for A\n"
705 "Where A = http://127.0.0.1/\n"
Maks Orlovich710d5e32019-07-09 20:16:45706 " B = http://baz.com/",
Carlos Caballero15caeeb2021-10-27 09:57:55707 v.DepictFrameTree(tab->GetPrimaryFrameTree().root()));
nick5f3d76072015-06-09 00:24:00708
Maks Orlovich710d5e32019-07-09 20:16:45709 // Now set a cross-site cookie from the main frame's process.
Lukasz Anforowicz6f746282018-01-04 23:24:51710 {
Maks Orlovich710d5e32019-07-09 20:16:45711 CookieStoreContentBrowserClient browser_client;
rockot1587e332016-07-27 17:44:14712
Maks Orlovich710d5e32019-07-09 20:16:45713 browser_client.set_override_url("https://baz.com/");
714 SetCookieFromJS(iframe, "pwn=ed");
nick5f3d76072015-06-09 00:24:00715
Maks Orlovich710d5e32019-07-09 20:16:45716 EXPECT_EQ("B_cookie=child", GetCookiesDirect(tab, GURL("http://baz.com/")));
Lukasz Anforowicz6f746282018-01-04 23:24:51717 }
nick5f3d76072015-06-09 00:24:00718
719 EXPECT_EQ(
Maks Orlovich710d5e32019-07-09 20:16:45720 " Site A ------------ proxies for B\n"
721 " +--Site B ------- proxies for A\n"
722 "Where A = http://127.0.0.1/\n"
723 " B = http://baz.com/",
Carlos Caballero15caeeb2021-10-27 09:57:55724 v.DepictFrameTree(tab->GetPrimaryFrameTree().root()));
nick5f3d76072015-06-09 00:24:00725}
726
Aldo Culquicondorcfb369e2025-03-18 19:19:04727IN_PROC_BROWSER_TEST_P(CookieBrowserTest, CookieNotReadableAfterExpiry) {
Olivier Li140ade52025-02-06 20:36:07728 ASSERT_TRUE(embedded_test_server()->Start());
729
730 GURL http_url = embedded_test_server()->GetURL("example.test", "/empty.html");
731 EXPECT_TRUE(NavigateToURL(shell(), http_url));
732
733 WebContentsImpl* web_contents_http =
734 static_cast<WebContentsImpl*>(shell()->web_contents());
735 RenderFrameHost* frame = web_contents_http->GetPrimaryMainFrame();
736
737 SetCookieFromJS(frame, "c=1;Max-Age=1");
738 SetCookieFromJS(frame, "d=1;Max-Age=7200");
739 EXPECT_EQ("c=1; d=1", GetCookieFromJS(frame));
740
741 // If cookies properly expire and become unavailable this test will terminate.
742 // If they do not the test will time out. The earliest expiry from the cookies
743 // is used so the short expiry from c is expected to be used.
744 std::string cookie;
745 do {
746 cookie = GetCookieFromJS(frame);
747 base::PlatformThread::Sleep(base::Milliseconds(100));
748 } while (cookie != "d=1");
749}
750
Dustin J. Mitchell1ef929a2023-03-20 15:11:36751// Cookies for an eTLD should be stored (via JS) if they match the URL host,
752// even if they begin with `.` or have non-canonical capitalization.
Aldo Culquicondorcfb369e2025-03-18 19:19:04753IN_PROC_BROWSER_TEST_P(CookieBrowserTest, ETldDomainCookies) {
Dustin J. Mitchell1ef929a2023-03-20 15:11:36754 ASSERT_TRUE(embedded_test_server()->Start());
755
756 // This test uses `gov.br` as an example of an eTLD.
757 GURL http_url = embedded_test_server()->GetURL("gov.br", "/empty.html");
758 EXPECT_TRUE(NavigateToURL(shell(), http_url));
759
760 WebContentsImpl* web_contents_http =
761 static_cast<WebContentsImpl*>(shell()->web_contents());
762 RenderFrameHost* frame = web_contents_http->GetPrimaryMainFrame();
763
764 const char* kCases[] = {
765 // A host cookie.
766 "c=1",
767 // A cookie for this domain.
768 "c=1; domain=gov.br",
769 // Same, but with a preceding dot. This dot should be ignored.
770 "c=1; domain=.gov.br",
771 // Same, but with non-canonical case. This should be canonicalized.
772 "c=1; domain=gOv.bR",
773 };
774
775 for (const char* set_cookie : kCases) {
776 SCOPED_TRACE(set_cookie);
777 SetCookieFromJS(frame, set_cookie);
778 EXPECT_EQ("c=1", GetCookieFromJS(frame));
779 SetCookieFromJS(frame, "c=;expires=Thu, 01 Jan 1970 00:00:00 GMT");
780 EXPECT_EQ("", GetCookieFromJS(frame));
781 }
782}
783
784// Cookies for an eTLD should be stored (via header) if they match the URL host,
785// even if they begin with `.` or have non-canonical capitalization.
Aldo Culquicondorcfb369e2025-03-18 19:19:04786IN_PROC_BROWSER_TEST_P(CookieBrowserTest, ETldDomainCookiesHeader) {
Dustin J. Mitchell1ef929a2023-03-20 15:11:36787 std::string got_cookie_on_request;
788 std::string set_cookie_on_response;
789 embedded_test_server()->RegisterRequestHandler(base::BindLambdaForTesting(
790 [&](const net::test_server::HttpRequest& request)
791 -> std::unique_ptr<net::test_server::HttpResponse> {
792 auto response = std::make_unique<net::test_server::BasicHttpResponse>();
793 if (request.headers.contains("Cookie")) {
794 got_cookie_on_request = request.headers.at("Cookie");
795 } else {
796 got_cookie_on_request = "";
797 }
798 if (set_cookie_on_response.size() != 0) {
799 response->AddCustomHeader("Set-Cookie", set_cookie_on_response);
800 set_cookie_on_response = "";
801 }
802 return std::move(response);
803 }));
804
805 ASSERT_TRUE(embedded_test_server()->Start());
806
807 // This test uses `gov.br` as an example of an eTLD.
808 GURL http_url = embedded_test_server()->GetURL("gov.br", "/empty.html");
809
810 const char* kCases[] = {
811 // A host cookie.
812 "c=1",
813 // A cookie for this domain.
814 "c=1; domain=gov.br",
815 // Same, but with a preceding dot. This dot should be ignored.
816 "c=1; domain=.gov.br",
817 // Same, but with non-canonical case. This should be canonicalized.
818 "c=1; domain=gOv.bR",
819 };
820
821 for (const char* set_cookie : kCases) {
822 SCOPED_TRACE(set_cookie);
823
824 set_cookie_on_response = set_cookie;
825 EXPECT_TRUE(NavigateToURL(shell(), http_url));
826
827 EXPECT_TRUE(NavigateToURL(shell(), http_url));
828 EXPECT_EQ("c=1", got_cookie_on_request);
829
830 set_cookie_on_response = "c=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
831 EXPECT_TRUE(NavigateToURL(shell(), http_url));
832
833 EXPECT_TRUE(NavigateToURL(shell(), http_url));
834 EXPECT_EQ("", got_cookie_on_request);
835 }
836}
837
Ari Chivukula0be980cd2025-01-30 03:32:41838enum class CookieFileMode { kDefault, kEnabled, kDisabled };
839
840class CookieFileBrowserTest
841 : public ContentBrowserTest,
842 public ::testing::WithParamInterface<CookieFileMode> {
843 protected:
844 void SetUpOnMainThread() override {
845 // Setup file url.
846 base::ScopedAllowBlockingForTesting allow_blocking;
847 EXPECT_TRUE(file_directory_.CreateUniqueTempDir());
848 base::FilePath file_path =
849 file_directory_.GetPath().AppendASCII("index.html");
850 EXPECT_TRUE(base::WriteFile(file_path, ""));
851 file_url_ = net::FilePathToFileURL(file_path);
852
853 // Setup cookie manager.
854 bool file_cookie_enabled;
855 switch (GetParam()) {
856 case CookieFileMode::kDefault:
857 // Nothing to do.
858 return;
859 case CookieFileMode::kEnabled:
860 file_cookie_enabled = true;
861 break;
862 case CookieFileMode::kDisabled:
863 file_cookie_enabled = false;
864 break;
865 }
866 base::RunLoop run_loop;
867 shell()
868 ->web_contents()
869 ->GetBrowserContext()
870 ->GetDefaultStoragePartition()
871 ->GetCookieManagerForBrowserProcess()
872 ->AllowFileSchemeCookies(file_cookie_enabled,
873 base::BindLambdaForTesting([&](bool success) {
874 EXPECT_TRUE(success);
875 run_loop.Quit();
876 }));
877 run_loop.Run();
878 }
879
880 GURL file_url_;
881
882 private:
883 base::ScopedTempDir file_directory_;
884};
885
886INSTANTIATE_TEST_SUITE_P(,
887 CookieFileBrowserTest,
888 ::testing::Values(CookieFileMode::kDefault,
889 CookieFileMode::kEnabled,
890 CookieFileMode::kDisabled));
891
892// Try to set and get cookies on a file URL.
893IN_PROC_BROWSER_TEST_P(CookieFileBrowserTest, SetAndGetCookie) {
894 // Navigate to file.
895 EXPECT_TRUE(NavigateToURL(shell(), file_url_));
896 RenderFrameHost* frame = shell()->web_contents()->GetPrimaryMainFrame();
897
898 // File cookies always appear to be writable.
899 EXPECT_TRUE(EvalJs(frame, "navigator.cookieEnabled").ExtractBool());
900
901 // File cookies can only be set if they are enabled.
902 bool can_set_cookies;
903 switch (GetParam()) {
904 case CookieFileMode::kDefault:
905 // TODO(crbug.com/378604901): Perhapse this should be allowed by default.
906 can_set_cookies = false;
907 return;
908 case CookieFileMode::kEnabled:
909 can_set_cookies = true;
910 break;
911 case CookieFileMode::kDisabled:
912 can_set_cookies = false;
913 break;
914 }
915 SetCookieFromJS(frame, "test=1");
916 EXPECT_EQ(can_set_cookies ? "test=1" : "", GetCookieFromJS(frame));
917}
918
nick5f3d76072015-06-09 00:24:00919} // namespace content