1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // This file tests that Web Workers (a Content feature) work in the Chromium
8 #include "base/containers/contains.h"
9 #include "base/feature_list.h"
10 #include "base/functional/bind.h"
11 #include "base/functional/callback.h"
12 #include "base/run_loop.h"
13 #include "base/strings/strcat.h"
14 #include "base/test/bind.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/test/base/in_process_browser_test.h"
18 #include "chrome/test/base/ui_test_utils.h"
19 #include "components/content_settings/core/browser/cookie_settings.h"
20 #include "components/content_settings/core/common/pref_names.h"
21 #include "components/prefs/pref_service.h"
22 #include "content/public/browser/browser_context.h"
23 #include "content/public/test/browser_test.h"
24 #include "content/public/test/browser_test_utils.h"
25 #include "content/public/test/url_loader_interceptor.h"
26 #include "net/test/embedded_test_server/embedded_test_server.h"
27 #include "net/test/embedded_test_server/http_request.h"
28 #include "net/test/embedded_test_server/http_response.h"
29 #include "third_party/blink/public/common/features.h"
30 #include "third_party/re2/src/re2/re2.h"
32 // A simple fixture used for testing dedicated workers and shared workers. The
33 // fixture stashes the HTTP request to the worker script for inspecting the
36 // This is in //chrome instead of //content since the tests exercise the
37 // |kBlockThirdPartyCookies| preference which is not a //content concept.
38 class ChromeWorkerBrowserTest : public InProcessBrowserTest {
40 void SetUp() override {
41 embedded_test_server()->RegisterRequestHandler(
42 base::BindRepeating(&ChromeWorkerBrowserTest::CaptureHeaderHandler,
43 base::Unretained(this), "/capture"));
44 ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
45 InProcessBrowserTest::SetUp();
48 void SetUpOnMainThread() override {
49 embedded_test_server()->StartAcceptingConnections();
53 // Tests worker script fetch (always same-origin) is not affected by the
54 // third-party cookie blocking configuration.
55 // This is the regression test for https://crbug.com/933287.
56 void TestWorkerScriptFetchWithThirdPartyCookieBlocking(
57 content_settings::CookieControlsMode cookie_controls_mode,
58 const std::string& test_url) {
59 const std::string kCookie = "foo=bar";
61 // Set up third-party cookie blocking.
62 browser()->profile()->GetPrefs()->SetInteger(
63 prefs::kCookieControlsMode, static_cast<int>(cookie_controls_mode));
65 // Make sure cookies are not set.
67 GetCookies(browser()->profile(), embedded_test_server()->base_url())
70 // Request for the worker script should not send cookies.
72 base::RunLoop run_loop;
73 quit_closure_ = run_loop.QuitClosure();
74 ASSERT_TRUE(ui_test_utils::NavigateToURL(
75 browser(), embedded_test_server()->GetURL(test_url)));
77 EXPECT_FALSE(base::Contains(header_map_, "Cookie"));
81 ASSERT_TRUE(SetCookie(browser()->profile(),
82 embedded_test_server()->base_url(), kCookie));
84 // Request for the worker script should send the cookie regardless of the
85 // third-party cookie blocking configuration.
87 base::RunLoop run_loop;
88 quit_closure_ = run_loop.QuitClosure();
89 ASSERT_TRUE(ui_test_utils::NavigateToURL(
90 browser(), embedded_test_server()->GetURL(test_url)));
92 EXPECT_TRUE(base::Contains(header_map_, "Cookie"));
93 EXPECT_EQ(kCookie, header_map_["Cookie"]);
97 // TODO(nhiroki): Add tests for creating workers from third-party iframes
98 // while third-party cookie blocking is enabled. This expects that cookies are
102 std::unique_ptr<net::test_server::HttpResponse> CaptureHeaderHandler(
103 const std::string& path,
104 const net::test_server::HttpRequest& request) {
105 if (request.GetURL().path() != path)
107 // Stash the HTTP request headers.
108 header_map_ = request.headers;
109 std::move(quit_closure_).Run();
110 return std::make_unique<net::test_server::BasicHttpResponse>();
113 net::test_server::HttpRequest::HeaderMap header_map_;
114 base::OnceClosure quit_closure_;
117 IN_PROC_BROWSER_TEST_F(ChromeWorkerBrowserTest,
118 DedicatedWorkerScriptFetchWithThirdPartyBlocking) {
119 TestWorkerScriptFetchWithThirdPartyCookieBlocking(
120 content_settings::CookieControlsMode::kBlockThirdParty,
121 "/workers/create_dedicated_worker.html?worker_url=/capture");
124 IN_PROC_BROWSER_TEST_F(ChromeWorkerBrowserTest,
125 DedicatedWorkerScriptFetchWithoutThirdPartyBlocking) {
126 TestWorkerScriptFetchWithThirdPartyCookieBlocking(
127 content_settings::CookieControlsMode::kOff,
128 "/workers/create_dedicated_worker.html?worker_url=/capture");
131 IN_PROC_BROWSER_TEST_F(ChromeWorkerBrowserTest,
132 SharedWorkerScriptFetchWithThirdPartyBlocking) {
133 TestWorkerScriptFetchWithThirdPartyCookieBlocking(
134 content_settings::CookieControlsMode::kBlockThirdParty,
135 "/workers/create_shared_worker.html?worker_url=/capture");
138 IN_PROC_BROWSER_TEST_F(ChromeWorkerBrowserTest,
139 SharedWorkerScriptFetchWithoutThirdPartyBlocking) {
140 TestWorkerScriptFetchWithThirdPartyCookieBlocking(
141 content_settings::CookieControlsMode::kOff,
142 "/workers/create_shared_worker.html?worker_url=/capture");
145 // A test fixture used for testing that dedicated and shared workers have the
146 // correct user agent value, it should always be the reduced user agent string.
147 class ChromeWorkerUserAgentBrowserTest : public InProcessBrowserTest {
149 ChromeWorkerUserAgentBrowserTest() = default;
151 // The URL that was used to test user-agent.
152 static constexpr char kOriginUrl[] = "https://127.0.0.1:44444";
154 // We use a URLLoaderInterceptor, rather than the EmbeddedTestServer, since
155 // EmbeddedTestServer serves content on a random port.
156 std::unique_ptr<content::URLLoaderInterceptor> CreateUrlLoaderInterceptor() {
157 return std::make_unique<content::URLLoaderInterceptor>(
158 base::BindLambdaForTesting(
159 [&](content::URLLoaderInterceptor::RequestParams* params) {
160 if (expected_request_urls_.find(params->url_request.url) ==
161 expected_request_urls_.end())
164 std::string path = "chrome/test/data/workers";
165 path.append(std::string(params->url_request.url.path_piece()));
167 std::string headers = "HTTP/1.1 200 OK\n";
170 {"Content-Type: text/",
171 base::EndsWith(params->url_request.url.path_piece(), ".js")
175 content::URLLoaderInterceptor::WriteResponse(
176 path, params->client.get(), &headers);
182 void SetExpectedRequestURLs(const std::set<GURL>& expected_request_urls) {
183 expected_request_urls_ = expected_request_urls;
186 // Check whether the user agent minor version matches "0.0.0" and we expect
187 // the user agent always to be reduced.
188 void CheckUserAgentString(const std::string& user_agent_value) {
189 // A regular expression that matches Chrome/{major_version}.{minor_version}
190 // in the User-Agent string, where the {minor_version} is captured.
191 static constexpr char kChromeVersionRegex[] =
192 "Chrome/[0-9]+\\.([0-9]+\\.[0-9]+\\.[0-9]+)";
193 // The minor version in the reduced UA string is always "0.0.0".
194 static constexpr char kReducedMinorVersion[] = "0.0.0";
196 std::string minor_version;
197 EXPECT_TRUE(re2::RE2::PartialMatch(user_agent_value, kChromeVersionRegex,
200 EXPECT_EQ(minor_version, kReducedMinorVersion);
204 std::set<GURL> expected_request_urls_;
207 constexpr char ChromeWorkerUserAgentBrowserTest::kOriginUrl[];
209 IN_PROC_BROWSER_TEST_F(ChromeWorkerUserAgentBrowserTest, SharedWorker) {
210 const GURL main_page_url = GURL(base::StrCat(
212 "/create_shared_worker.html?worker_url=onconnect_user_agent.js"}));
213 const GURL worker_url =
214 GURL(base::StrCat({kOriginUrl, "/onconnect_user_agent.js"}));
215 SetExpectedRequestURLs({main_page_url, worker_url});
217 std::unique_ptr<content::URLLoaderInterceptor> interceptor =
218 CreateUrlLoaderInterceptor();
220 // Navigate to the page that has the scripts for registering the worker.
221 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_page_url));
223 // Check the result of navigator.userAgent called from the worker.
224 CheckUserAgentString(
225 EvalJs(browser()->tab_strip_model()->GetActiveWebContents(),
230 IN_PROC_BROWSER_TEST_F(ChromeWorkerUserAgentBrowserTest,
231 DedicatedWorkerCreatedFromFrame) {
232 const GURL main_page_url = GURL(base::StrCat(
233 {kOriginUrl, "/create_dedicated_worker.html?worker_url=user_agent.js"}));
234 const GURL worker_url = GURL(base::StrCat({kOriginUrl, "/user_agent.js"}));
235 SetExpectedRequestURLs({main_page_url, worker_url});
237 std::unique_ptr<content::URLLoaderInterceptor> interceptor =
238 CreateUrlLoaderInterceptor();
240 // Navigate to the page that has the scripts for registering the worker.
241 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_page_url));
243 // Check the result of navigator.userAgent called from the worker.
244 CheckUserAgentString(
245 EvalJs(browser()->tab_strip_model()->GetActiveWebContents(),
250 IN_PROC_BROWSER_TEST_F(ChromeWorkerUserAgentBrowserTest,
251 DedicatedWorkerCreatedFromDedicatedWorker) {
252 const GURL main_page_url =
253 GURL(base::StrCat({kOriginUrl,
254 "/create_dedicated_worker.html?worker_url=parent_"
255 "worker_user_agent.js"}));
256 const GURL worker_url =
257 GURL(base::StrCat({kOriginUrl, "/parent_worker_user_agent.js"}));
258 const GURL user_agent_url =
259 GURL(base::StrCat({kOriginUrl, "/user_agent.js"}));
260 SetExpectedRequestURLs({main_page_url, worker_url, user_agent_url});
262 std::unique_ptr<content::URLLoaderInterceptor> interceptor =
263 CreateUrlLoaderInterceptor();
265 // Navigate to the page that has the scripts for registering the worker.
266 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), main_page_url));
268 // Check the result of navigator.userAgent called from the worker.
269 CheckUserAgentString(
270 EvalJs(browser()->tab_strip_model()->GetActiveWebContents(),