blob: a13fcdfb9639fb0bf122f5ddcb8cd589333da4e4 [file] [log] [blame]
[email protected]294bdb32014-05-30 07:01:541// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// This file tests that Service Workers (a Content feature) work in the Chromium
6// embedder.
7
8#include "base/bind.h"
horo61f3f4f2016-03-09 01:26:149#include "base/command_line.h"
[email protected]294bdb32014-05-30 07:01:5410#include "base/files/scoped_temp_dir.h"
11#include "base/numerics/safe_conversions.h"
Tsuyoshi Horo757835432018-11-15 00:21:3512#include "base/path_service.h"
[email protected]294bdb32014-05-30 07:01:5413#include "base/run_loop.h"
horo61f3f4f2016-03-09 01:26:1414#include "base/strings/stringprintf.h"
15#include "base/strings/utf_string_conversions.h"
Devlin Cronin626d80c2018-06-01 01:08:3616#include "base/test/metrics/histogram_tester.h"
Matt Falkenhagenc0d0bac2018-12-18 08:31:0817#include "base/test/scoped_feature_list.h"
jam3f2d3932017-04-26 20:28:5118#include "base/threading/thread_restrictions.h"
grt56c07a22016-07-19 11:52:2019#include "build/build_config.h"
shimazuce8af88122016-10-06 23:49:2120#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
[email protected]294bdb32014-05-30 07:01:5421#include "chrome/browser/profiles/profile.h"
22#include "chrome/browser/ui/browser.h"
falken41f4175162014-10-29 07:03:4123#include "chrome/browser/ui/browser_window.h"
[email protected]294bdb32014-05-30 07:01:5424#include "chrome/browser/ui/tabs/tab_strip_model.h"
Tsuyoshi Horo757835432018-11-15 00:21:3525#include "chrome/common/chrome_paths.h"
horo61f3f4f2016-03-09 01:26:1426#include "chrome/common/chrome_switches.h"
[email protected]294bdb32014-05-30 07:01:5427#include "chrome/test/base/in_process_browser_test.h"
Matt Falkenhagenea306042018-11-29 00:45:2528#include "chrome/test/base/test_chrome_web_ui_controller_factory.h"
falken41f4175162014-10-29 07:03:4129#include "chrome/test/base/ui_test_utils.h"
Carlos Caballerob4283202020-08-10 14:40:4630#include "components/content_settings/browser/page_specific_content_settings.h"
Christian Dullweber80e5f262020-08-25 13:25:2231#include "components/content_settings/core/browser/cookie_settings.h"
shimazuce8af88122016-10-06 23:49:2132#include "components/content_settings/core/browser/host_content_settings_map.h"
Matt Falkenhagenc0d0bac2018-12-18 08:31:0833#include "components/content_settings/core/common/pref_names.h"
Tsuyoshi Horo757835432018-11-15 00:21:3534#include "components/favicon/content/content_favicon_driver.h"
35#include "components/favicon/core/favicon_driver_observer.h"
Scott Violet9ae82892018-03-01 18:38:1236#include "components/nacl/common/buildflags.h"
[email protected]294bdb32014-05-30 07:01:5437#include "content/public/browser/browser_context.h"
Eric Seckler8652dcd52018-09-20 10:42:2838#include "content/public/browser/browser_task_traits.h"
Gabriel Charetteb2bbd482020-05-27 01:24:2139#include "content/public/browser/browser_thread.h"
horo61f3f4f2016-03-09 01:26:1440#include "content/public/browser/render_frame_host.h"
[email protected]294bdb32014-05-30 07:01:5441#include "content/public/browser/service_worker_context.h"
42#include "content/public/browser/storage_partition.h"
Matt Falkenhagenea306042018-11-29 00:45:2543#include "content/public/browser/url_data_source.h"
[email protected]294bdb32014-05-30 07:01:5444#include "content/public/browser/web_contents.h"
Matt Falkenhagenea306042018-11-29 00:45:2545#include "content/public/browser/web_ui_controller.h"
Peter Kasting919ce652020-05-07 10:22:3646#include "content/public/test/browser_test.h"
horo61f3f4f2016-03-09 01:26:1447#include "content/public/test/browser_test_utils.h"
Tsuyoshi Horo757835432018-11-15 00:21:3548#include "net/dns/mock_host_resolver.h"
[email protected]294bdb32014-05-30 07:01:5449#include "net/test/embedded_test_server/embedded_test_server.h"
Matt Falkenhagenc0d0bac2018-12-18 08:31:0850#include "net/test/embedded_test_server/http_request.h"
51#include "net/test/embedded_test_server/http_response.h"
horo61f3f4f2016-03-09 01:26:1452#include "ppapi/shared_impl/ppapi_switches.h"
Zhuoyu Qian47ed0fc52018-09-06 02:13:4053#include "third_party/blink/public/common/messaging/string_message_codec.h"
Leon Hand0da4722019-07-11 08:12:0454#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
[email protected]294bdb32014-05-30 07:01:5455
Matt Falkenhagenea306042018-11-29 00:45:2556namespace chrome_service_worker_browser_test {
[email protected]294bdb32014-05-30 07:01:5457
Nico Weberaf3b00b2017-09-11 17:58:1758const char kInstallAndWaitForActivatedPage[] =
Tsuyoshi Horoa1c6f542017-06-13 15:22:4159 "<script>"
60 "navigator.serviceWorker.register('./sw.js', {scope: './scope/'})"
61 " .then(function(reg) {"
62 " reg.addEventListener('updatefound', function() {"
63 " var worker = reg.installing;"
64 " worker.addEventListener('statechange', function() {"
65 " if (worker.state == 'activated')"
66 " document.title = 'READY';"
67 " });"
68 " });"
69 " });"
70 "</script>";
71
[email protected]294bdb32014-05-30 07:01:5472class ChromeServiceWorkerTest : public InProcessBrowserTest {
73 protected:
74 ChromeServiceWorkerTest() {
75 EXPECT_TRUE(service_worker_dir_.CreateUniqueTempDir());
shimazuce8af88122016-10-06 23:49:2176 EXPECT_TRUE(base::CreateDirectoryAndGetError(
77 service_worker_dir_.GetPath().Append(
78 FILE_PATH_LITERAL("scope")), nullptr));
[email protected]294bdb32014-05-30 07:01:5479 }
horo61f3f4f2016-03-09 01:26:1480 ~ChromeServiceWorkerTest() override {}
[email protected]294bdb32014-05-30 07:01:5481
82 void WriteFile(const base::FilePath::StringType& filename,
83 base::StringPiece contents) {
Francois Doraye6fb2d02017-10-18 21:29:1384 base::ScopedAllowBlockingForTesting allow_blocking;
[email protected]294bdb32014-05-30 07:01:5485 EXPECT_EQ(base::checked_cast<int>(contents.size()),
vabr96fd0c0f2016-09-13 14:21:3186 base::WriteFile(service_worker_dir_.GetPath().Append(filename),
87 contents.data(), contents.size()));
[email protected]294bdb32014-05-30 07:01:5488 }
89
Tsuyoshi Horoa1c6f542017-06-13 15:22:4190 void NavigateToPageAndWaitForReadyTitle(const std::string path) {
91 const base::string16 expected_title1 = base::ASCIIToUTF16("READY");
92 content::TitleWatcher title_watcher1(
93 browser()->tab_strip_model()->GetActiveWebContents(), expected_title1);
94 ui_test_utils::NavigateToURL(browser(),
95 embedded_test_server()->GetURL(path));
96 EXPECT_EQ(expected_title1, title_watcher1.WaitAndGetTitle());
97 }
98
99 void InitializeServer() {
100 embedded_test_server()->ServeFilesFromDirectory(
101 service_worker_dir_.GetPath());
102 ASSERT_TRUE(embedded_test_server()->Start());
103 }
104
105 content::ServiceWorkerContext* GetServiceWorkerContext() {
106 return content::BrowserContext::GetDefaultStoragePartition(
107 browser()->profile())
108 ->GetServiceWorkerContext();
109 }
110
[email protected]294bdb32014-05-30 07:01:54111 base::ScopedTempDir service_worker_dir_;
horo61f3f4f2016-03-09 01:26:14112
113 private:
114 DISALLOW_COPY_AND_ASSIGN(ChromeServiceWorkerTest);
[email protected]294bdb32014-05-30 07:01:54115};
116
Tsuyoshi Horoa1c6f542017-06-13 15:22:41117template <typename T>
118static void ExpectResultAndRun(T expected,
Alexander Cooperbc87af32020-07-15 15:59:45119 base::OnceClosure continuation,
Tsuyoshi Horoa1c6f542017-06-13 15:22:41120 T actual) {
[email protected]294bdb32014-05-30 07:01:54121 EXPECT_EQ(expected, actual);
Alexander Cooperbc87af32020-07-15 15:59:45122 std::move(continuation).Run();
[email protected]294bdb32014-05-30 07:01:54123}
124
125// http://crbug.com/368570
126IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerTest,
127 CanShutDownWithRegisteredServiceWorker) {
128 WriteFile(FILE_PATH_LITERAL("service_worker.js"), "");
[email protected]294bdb32014-05-30 07:01:54129
vabr96fd0c0f2016-09-13 14:21:31130 embedded_test_server()->ServeFilesFromDirectory(
131 service_worker_dir_.GetPath());
svaldeza01f7d92015-11-18 17:47:56132 ASSERT_TRUE(embedded_test_server()->Start());
[email protected]294bdb32014-05-30 07:01:54133
[email protected]294bdb32014-05-30 07:01:54134 base::RunLoop run_loop;
Emma Haruka Iwaobc302102017-12-05 02:33:08135 blink::mojom::ServiceWorkerRegistrationOptions options(
Asami Doi5de8dea2018-09-13 10:01:07136 embedded_test_server()->GetURL("/"), blink::mojom::ScriptType::kClassic,
Emma Haruka Iwaobc302102017-12-05 02:33:08137 blink::mojom::ServiceWorkerUpdateViaCache::kImports);
138 GetServiceWorkerContext()->RegisterServiceWorker(
139 embedded_test_server()->GetURL("/service_worker.js"), options,
Jan Wilken Dörrie8b2247e2020-04-20 10:04:40140 base::BindOnce(&ExpectResultAndRun<bool>, true, run_loop.QuitClosure()));
[email protected]294bdb32014-05-30 07:01:54141 run_loop.Run();
142
143 // Leave the Service Worker registered, and make sure that the browser can
144 // shut down without DCHECK'ing. It'd be nice to check here that the SW is
145 // actually occupying a process, but we don't yet have the public interface to
146 // do that.
147}
148
falken41f4175162014-10-29 07:03:41149// http://crbug.com/419290
150IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerTest,
151 CanCloseIncognitoWindowWithServiceWorkerController) {
152 WriteFile(FILE_PATH_LITERAL("service_worker.js"), "");
153 WriteFile(FILE_PATH_LITERAL("service_worker.js.mock-http-headers"),
zmo9528c9f42015-08-04 22:12:08154 "HTTP/1.1 200 OK\nContent-Type: text/javascript");
falken41f4175162014-10-29 07:03:41155 WriteFile(FILE_PATH_LITERAL("test.html"), "");
Tsuyoshi Horoa1c6f542017-06-13 15:22:41156 InitializeServer();
falken41f4175162014-10-29 07:03:41157
158 Browser* incognito = CreateIncognitoBrowser();
falken41f4175162014-10-29 07:03:41159
160 base::RunLoop run_loop;
Emma Haruka Iwaobc302102017-12-05 02:33:08161 blink::mojom::ServiceWorkerRegistrationOptions options(
Asami Doi5de8dea2018-09-13 10:01:07162 embedded_test_server()->GetURL("/"), blink::mojom::ScriptType::kClassic,
Emma Haruka Iwaobc302102017-12-05 02:33:08163 blink::mojom::ServiceWorkerUpdateViaCache::kImports);
164 GetServiceWorkerContext()->RegisterServiceWorker(
165 embedded_test_server()->GetURL("/service_worker.js"), options,
Jan Wilken Dörrie8b2247e2020-04-20 10:04:40166 base::BindOnce(&ExpectResultAndRun<bool>, true, run_loop.QuitClosure()));
falken41f4175162014-10-29 07:03:41167 run_loop.Run();
168
169 ui_test_utils::NavigateToURL(incognito,
170 embedded_test_server()->GetURL("/test.html"));
171
Qiang Xu2a41181f2018-04-11 22:38:32172 CloseBrowserSynchronously(incognito);
falken41f4175162014-10-29 07:03:41173
174 // Test passes if we don't crash.
175}
176
shimazuce8af88122016-10-06 23:49:21177IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerTest,
178 FailRegisterServiceWorkerWhenJSDisabled) {
179 WriteFile(FILE_PATH_LITERAL("service_worker.js"), "");
Tsuyoshi Horoa1c6f542017-06-13 15:22:41180 InitializeServer();
shimazuce8af88122016-10-06 23:49:21181
182 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:45183 ->SetDefaultContentSetting(ContentSettingsType::JAVASCRIPT,
shimazuce8af88122016-10-06 23:49:21184 CONTENT_SETTING_BLOCK);
185
shimazuce8af88122016-10-06 23:49:21186 base::RunLoop run_loop;
Emma Haruka Iwaobc302102017-12-05 02:33:08187 blink::mojom::ServiceWorkerRegistrationOptions options(
Asami Doi5de8dea2018-09-13 10:01:07188 embedded_test_server()->GetURL("/"), blink::mojom::ScriptType::kClassic,
Emma Haruka Iwaobc302102017-12-05 02:33:08189 blink::mojom::ServiceWorkerUpdateViaCache::kImports);
190 GetServiceWorkerContext()->RegisterServiceWorker(
191 embedded_test_server()->GetURL("/service_worker.js"), options,
Jan Wilken Dörrie8b2247e2020-04-20 10:04:40192 base::BindOnce(&ExpectResultAndRun<bool>, false, run_loop.QuitClosure()));
shimazuce8af88122016-10-06 23:49:21193 run_loop.Run();
194}
195
196IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerTest,
197 FallbackMainResourceRequestWhenJSDisabled) {
198 WriteFile(
199 FILE_PATH_LITERAL("sw.js"),
200 "self.onfetch = function(e) {"
201 " e.respondWith(new Response('<title>Fail</title>',"
202 " {headers: {'Content-Type': 'text/html'}}));"
203 "};");
204 WriteFile(FILE_PATH_LITERAL("scope/done.html"), "<title>Done</title>");
Tsuyoshi Horoa1c6f542017-06-13 15:22:41205 WriteFile(FILE_PATH_LITERAL("test.html"), kInstallAndWaitForActivatedPage);
206 InitializeServer();
207 NavigateToPageAndWaitForReadyTitle("/test.html");
shimazuce8af88122016-10-06 23:49:21208
Tsuyoshi Horoa1c6f542017-06-13 15:22:41209 GetServiceWorkerContext()->StopAllServiceWorkersForOrigin(
Nidhi Jajud00cc532020-09-25 07:06:24210 url::Origin::Create(embedded_test_server()->base_url()));
shimazuce8af88122016-10-06 23:49:21211 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:45212 ->SetDefaultContentSetting(ContentSettingsType::JAVASCRIPT,
shimazuce8af88122016-10-06 23:49:21213 CONTENT_SETTING_BLOCK);
214
215 const base::string16 expected_title2 = base::ASCIIToUTF16("Done");
216 content::TitleWatcher title_watcher2(
217 browser()->tab_strip_model()->GetActiveWebContents(), expected_title2);
218 ui_test_utils::NavigateToURL(
219 browser(),
220 embedded_test_server()->GetURL("/scope/done.html"));
221 EXPECT_EQ(expected_title2, title_watcher2.WaitAndGetTitle());
222
Carlos Caballerod7b759412020-07-31 18:00:08223 content::RenderFrameHost* main_frame =
224 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame();
225 EXPECT_TRUE(
Carlos Caballerob4283202020-08-10 14:40:46226 content_settings::PageSpecificContentSettings::GetForFrame(main_frame)
Carlos Caballerod7b759412020-07-31 18:00:08227 ->IsContentBlocked(ContentSettingsType::JAVASCRIPT));
shimazuce8af88122016-10-06 23:49:21228}
229
Jon Mannb528b402018-08-10 21:05:37230IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerTest,
Azeem Arshad336e5af2019-01-16 22:27:25231 StartServiceWorkerAndDispatchMessage) {
232 base::RunLoop run_loop;
233 blink::TransferableMessage msg;
234 const base::string16 message_data = base::UTF8ToUTF16("testMessage");
235
236 WriteFile(FILE_PATH_LITERAL("sw.js"), "self.onfetch = function(e) {};");
237 WriteFile(FILE_PATH_LITERAL("test.html"), kInstallAndWaitForActivatedPage);
238 InitializeServer();
239 NavigateToPageAndWaitForReadyTitle("/test.html");
240 msg.owned_encoded_message = blink::EncodeStringMessage(message_data);
241 msg.encoded_message = msg.owned_encoded_message;
242
Gabriel Charetteb2bbd482020-05-27 01:24:21243 content::GetIOThreadTaskRunner({})->PostTask(
244 FROM_HERE,
Azeem Arshad336e5af2019-01-16 22:27:25245 base::BindOnce(
246 &content::ServiceWorkerContext::StartServiceWorkerAndDispatchMessage,
247 base::Unretained(GetServiceWorkerContext()),
248 embedded_test_server()->GetURL("/scope/"), std::move(msg),
249 base::BindRepeating(&ExpectResultAndRun<bool>, true,
250 run_loop.QuitClosure())));
251
252 run_loop.Run();
253}
254
horo61f3f4f2016-03-09 01:26:14255class ChromeServiceWorkerFetchTest : public ChromeServiceWorkerTest {
256 protected:
257 ChromeServiceWorkerFetchTest() {}
258 ~ChromeServiceWorkerFetchTest() override {}
259
260 void SetUpOnMainThread() override {
261 WriteServiceWorkerFetchTestFiles();
vabr96fd0c0f2016-09-13 14:21:31262 embedded_test_server()->ServeFilesFromDirectory(
263 service_worker_dir_.GetPath());
horo61f3f4f2016-03-09 01:26:14264 ASSERT_TRUE(embedded_test_server()->Start());
265 InitializeServiceWorkerFetchTestPage();
266 }
267
268 std::string ExecuteScriptAndExtractString(const std::string& js) {
269 std::string result;
270 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
271 browser()->tab_strip_model()->GetActiveWebContents(), js, &result));
272 return result;
273 }
274
275 std::string RequestString(const std::string& url,
276 const std::string& mode,
277 const std::string& credentials) const {
278 return base::StringPrintf("url:%s, mode:%s, credentials:%s\n", url.c_str(),
279 mode.c_str(), credentials.c_str());
280 }
281
282 std::string GetURL(const std::string& relative_url) const {
283 return embedded_test_server()->GetURL(relative_url).spec();
284 }
285
286 private:
287 void WriteServiceWorkerFetchTestFiles() {
288 WriteFile(FILE_PATH_LITERAL("sw.js"),
289 "this.onactivate = function(event) {"
290 " event.waitUntil(self.clients.claim());"
291 "};"
292 "this.onfetch = function(event) {"
Tsuyoshi Horo49dd35bd2018-12-11 09:30:06293 // Ignore the default favicon request. The default favicon request
294 // is sent after the page loading is finished, and we can't
295 // control the timing of the request. If the request is sent after
296 // clients.claim() is called, fetch event for the default favicon
297 // request is triggered and the tests become flaky. See
298 // https://crbug.com/912543.
299 " if (event.request.url.endsWith('/favicon.ico')) {"
300 " return;"
301 " }"
horo61f3f4f2016-03-09 01:26:14302 " event.respondWith("
303 " self.clients.matchAll().then(function(clients) {"
304 " clients.forEach(function(client) {"
305 " client.postMessage("
306 " 'url:' + event.request.url + ', ' +"
307 " 'mode:' + event.request.mode + ', ' +"
308 " 'credentials:' + event.request.credentials"
309 " );"
310 " });"
311 " return fetch(event.request);"
312 " }));"
313 "};");
314 WriteFile(FILE_PATH_LITERAL("test.html"),
315 "<script>"
316 "navigator.serviceWorker.register('./sw.js', {scope: './'})"
317 " .then(function(reg) {"
318 " reg.addEventListener('updatefound', function() {"
319 " var worker = reg.installing;"
320 " worker.addEventListener('statechange', function() {"
321 " if (worker.state == 'activated')"
322 " document.title = 'READY';"
323 " });"
324 " });"
325 " });"
326 "var reportOnFetch = true;"
327 "var issuedRequests = [];"
328 "function reportRequests() {"
329 " var str = '';"
330 " issuedRequests.forEach(function(data) {"
331 " str += data + '\\n';"
332 " });"
horo61f3f4f2016-03-09 01:26:14333 " window.domAutomationController.send(str);"
334 "}"
335 "navigator.serviceWorker.addEventListener("
336 " 'message',"
337 " function(event) {"
338 " issuedRequests.push(event.data);"
339 " if (reportOnFetch) {"
340 " reportRequests();"
341 " }"
342 " }, false);"
343 "</script>");
344 }
345
346 void InitializeServiceWorkerFetchTestPage() {
347 // The message "READY" will be sent when the service worker is activated.
348 const base::string16 expected_title = base::ASCIIToUTF16("READY");
349 content::TitleWatcher title_watcher(
350 browser()->tab_strip_model()->GetActiveWebContents(), expected_title);
351 ui_test_utils::NavigateToURL(browser(),
352 embedded_test_server()->GetURL("/test.html"));
353 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
354 }
355
356 DISALLOW_COPY_AND_ASSIGN(ChromeServiceWorkerFetchTest);
357};
358
Tsuyoshi Horo757835432018-11-15 00:21:35359class FaviconUpdateWaiter : public favicon::FaviconDriverObserver {
360 public:
Evan Stade22e3f9b2019-10-01 21:12:17361 explicit FaviconUpdateWaiter(content::WebContents* web_contents) {
Tsuyoshi Horo757835432018-11-15 00:21:35362 scoped_observer_.Add(
363 favicon::ContentFaviconDriver::FromWebContents(web_contents));
364 }
Evan Stade22e3f9b2019-10-01 21:12:17365 ~FaviconUpdateWaiter() override = default;
horo61f3f4f2016-03-09 01:26:14366
Tsuyoshi Horo757835432018-11-15 00:21:35367 void Wait() {
368 if (updated_)
369 return;
370
371 base::RunLoop run_loop;
372 quit_closure_ = run_loop.QuitClosure();
373 run_loop.Run();
374 }
375
376 private:
377 void OnFaviconUpdated(favicon::FaviconDriver* favicon_driver,
378 NotificationIconType notification_icon_type,
379 const GURL& icon_url,
380 bool icon_url_changed,
381 const gfx::Image& image) override {
382 updated_ = true;
383 if (!quit_closure_.is_null())
384 std::move(quit_closure_).Run();
385 }
386
Evan Stade22e3f9b2019-10-01 21:12:17387 bool updated_ = false;
388 ScopedObserver<favicon::FaviconDriver, favicon::FaviconDriverObserver>
389 scoped_observer_{this};
Tsuyoshi Horo757835432018-11-15 00:21:35390 base::OnceClosure quit_closure_;
391
392 DISALLOW_COPY_AND_ASSIGN(FaviconUpdateWaiter);
393};
394
395class ChromeServiceWorkerLinkFetchTest : public ChromeServiceWorkerFetchTest {
396 protected:
397 ChromeServiceWorkerLinkFetchTest() {}
398 ~ChromeServiceWorkerLinkFetchTest() override {}
399 void SetUpOnMainThread() override {
400 // Map all hosts to localhost and setup the EmbeddedTestServer for
401 // redirects.
402 host_resolver()->AddRule("*", "127.0.0.1");
403 ChromeServiceWorkerFetchTest::SetUpOnMainThread();
404 }
horo61f3f4f2016-03-09 01:26:14405 std::string ExecuteManifestFetchTest(const std::string& url,
406 const std::string& cross_origin) {
407 std::string js(
408 base::StringPrintf("reportOnFetch = false;"
409 "var link = document.createElement('link');"
410 "link.rel = 'manifest';"
411 "link.href = '%s';",
412 url.c_str()));
413 if (!cross_origin.empty()) {
414 js +=
415 base::StringPrintf("link.crossOrigin = '%s';", cross_origin.c_str());
416 }
417 js += "document.head.appendChild(link);";
418 ExecuteJavaScriptForTests(js);
horo482eeff2016-07-19 23:06:58419 return GetManifestAndIssuedRequests();
horo61f3f4f2016-03-09 01:26:14420 }
421
Tsuyoshi Horo757835432018-11-15 00:21:35422 std::string ExecuteFaviconFetchTest(const std::string& url) {
423 FaviconUpdateWaiter waiter(
424 browser()->tab_strip_model()->GetActiveWebContents());
425 std::string js(
426 base::StringPrintf("reportOnFetch = false;"
427 "var link = document.createElement('link');"
428 "link.rel = 'icon';"
429 "link.href = '%s';"
430 "document.head.appendChild(link);",
431 url.c_str()));
432 ExecuteJavaScriptForTests(js);
433 waiter.Wait();
434 return ExecuteScriptAndExtractString("reportRequests();");
435 }
436
437 void CopyTestFile(const std::string& src, const std::string& dst) {
438 base::ScopedAllowBlockingForTesting allow_blocking;
439 base::FilePath test_data_dir;
440 base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
441 EXPECT_TRUE(base::CopyFile(test_data_dir.AppendASCII(src),
442 service_worker_dir_.GetPath().AppendASCII(dst)));
443 }
444
horo61f3f4f2016-03-09 01:26:14445 private:
446 void ExecuteJavaScriptForTests(const std::string& js) {
Sam McNallycfe7a062017-11-02 00:40:07447 base::RunLoop run_loop;
horo61f3f4f2016-03-09 01:26:14448 browser()
449 ->tab_strip_model()
450 ->GetActiveWebContents()
451 ->GetMainFrame()
Sam McNallycfe7a062017-11-02 00:40:07452 ->ExecuteJavaScriptForTests(
453 base::ASCIIToUTF16(js),
Alexander Cooperbc87af32020-07-15 15:59:45454 base::BindOnce(
455 [](base::OnceClosure quit_callback, base::Value result) {
456 std::move(quit_callback).Run();
457 },
458 run_loop.QuitClosure()));
Sam McNallycfe7a062017-11-02 00:40:07459 run_loop.Run();
horo61f3f4f2016-03-09 01:26:14460 }
461
horo482eeff2016-07-19 23:06:58462 std::string GetManifestAndIssuedRequests() {
463 base::RunLoop run_loop;
464 browser()->tab_strip_model()->GetActiveWebContents()->GetManifest(
Jan Wilken Dörrie8b2247e2020-04-20 10:04:40465 base::BindOnce(&ManifestCallbackAndRun, run_loop.QuitClosure()));
horo482eeff2016-07-19 23:06:58466 run_loop.Run();
horo61f3f4f2016-03-09 01:26:14467 return ExecuteScriptAndExtractString(
468 "if (issuedRequests.length != 0) reportRequests();"
469 "else reportOnFetch = true;");
470 }
horo482eeff2016-07-19 23:06:58471
Alexander Cooperbc87af32020-07-15 15:59:45472 static void ManifestCallbackAndRun(base::OnceClosure continuation,
horo482eeff2016-07-19 23:06:58473 const GURL&,
Dmitry Gozman88ca5a992018-05-18 00:13:33474 const blink::Manifest&) {
Alexander Cooperbc87af32020-07-15 15:59:45475 std::move(continuation).Run();
horo482eeff2016-07-19 23:06:58476 }
477
Tsuyoshi Horo757835432018-11-15 00:21:35478 DISALLOW_COPY_AND_ASSIGN(ChromeServiceWorkerLinkFetchTest);
horo61f3f4f2016-03-09 01:26:14479};
480
Tsuyoshi Horo757835432018-11-15 00:21:35481IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerLinkFetchTest, ManifestSameOrigin) {
horo61f3f4f2016-03-09 01:26:14482 // <link rel="manifest" href="manifest.json">
Takeshi Yoshino2e231cf2017-06-21 04:40:12483 EXPECT_EQ(RequestString(GetURL("/manifest.json"), "cors", "omit"),
horo61f3f4f2016-03-09 01:26:14484 ExecuteManifestFetchTest("manifest.json", ""));
485}
486
Tsuyoshi Horo757835432018-11-15 00:21:35487IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerLinkFetchTest,
488 ManifestSameOriginUseCredentials) {
horo61f3f4f2016-03-09 01:26:14489 // <link rel="manifest" href="manifest.json" crossorigin="use-credentials">
490 EXPECT_EQ(RequestString(GetURL("/manifest.json"), "cors", "include"),
491 ExecuteManifestFetchTest("manifest.json", "use-credentials"));
492}
493
Tsuyoshi Horo757835432018-11-15 00:21:35494IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerLinkFetchTest, ManifestOtherOrigin) {
495 // <link rel="manifest" href="http://www.example.com:PORT/manifest.json">
496 const std::string url = embedded_test_server()
497 ->GetURL("www.example.com", "/manifest.json")
498 .spec();
499 EXPECT_EQ(RequestString(url, "cors", "omit"),
500 ExecuteManifestFetchTest(url, ""));
horo61f3f4f2016-03-09 01:26:14501}
502
Tsuyoshi Horo757835432018-11-15 00:21:35503IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerLinkFetchTest,
504 ManifestOtherOriginUseCredentials) {
505 // <link rel="manifest" href="http://www.example.com:PORT/manifest.json"
horo61f3f4f2016-03-09 01:26:14506 // crossorigin="use-credentials">
Tsuyoshi Horo757835432018-11-15 00:21:35507 const std::string url = embedded_test_server()
508 ->GetURL("www.example.com", "/manifest.json")
509 .spec();
510 EXPECT_EQ(RequestString(url, "cors", "include"),
511 ExecuteManifestFetchTest(url, "use-credentials"));
512}
513
514IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerLinkFetchTest, FaviconSameOrigin) {
515 // <link rel="favicon" href="fav.png">
516 CopyTestFile("favicon/icon.png", "fav.png");
517 EXPECT_EQ(RequestString(GetURL("/fav.png"), "no-cors", "include"),
518 ExecuteFaviconFetchTest("/fav.png"));
519}
520
521IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerLinkFetchTest, FaviconOtherOrigin) {
522 // <link rel="favicon" href="http://www.example.com:PORT/fav.png">
523 CopyTestFile("favicon/icon.png", "fav.png");
524 const std::string url =
525 embedded_test_server()->GetURL("www.example.com", "/fav.png").spec();
526 EXPECT_EQ("", ExecuteFaviconFetchTest(url));
horo61f3f4f2016-03-09 01:26:14527}
528
Nico Weberaf3b00b2017-09-11 17:58:17529#if BUILDFLAG(ENABLE_NACL)
Matt Falkenhagen7031e8b2018-02-20 03:30:33530// This test registers a service worker and then loads a controlled iframe that
531// creates a PNaCl plugin in an <embed> element. Once loaded, the PNaCl plugin
532// is ordered to do a resource request for "/echo". The service worker records
533// all the fetch events it sees. Since requests for plug-ins and requests
534// initiated by plug-ins should not be interecepted by service workers, we
535// expect that the the service worker only see the navigation request for the
536// iframe.
horo61f3f4f2016-03-09 01:26:14537class ChromeServiceWorkerFetchPPAPITest : public ChromeServiceWorkerFetchTest {
538 protected:
539 ChromeServiceWorkerFetchPPAPITest() {}
540 ~ChromeServiceWorkerFetchPPAPITest() override {}
541
Derek Schuffd71a05822019-05-30 19:50:13542 void SetUpCommandLine(base::CommandLine* command_line) override {
543 ChromeServiceWorkerFetchTest::SetUpCommandLine(command_line);
544 // Use --enable-nacl flag to ensure the PNaCl module can load (without
545 // needing to use an OT token)
546 command_line->AppendSwitch(switches::kEnableNaCl);
547 }
548
horo61f3f4f2016-03-09 01:26:14549 void SetUpOnMainThread() override {
550 base::FilePath document_root;
551 ASSERT_TRUE(ui_test_utils::GetRelativeBuildDirectory(&document_root));
552 embedded_test_server()->AddDefaultHandlers(
553 document_root.Append(FILE_PATH_LITERAL("nacl_test_data"))
554 .Append(FILE_PATH_LITERAL("pnacl")));
555 ChromeServiceWorkerFetchTest::SetUpOnMainThread();
556 test_page_url_ = GetURL("/pnacl_url_loader.html");
557 }
558
Matt Falkenhagen7031e8b2018-02-20 03:30:33559 std::string GetNavigationRequestString(const std::string& fragment) const {
560 return RequestString(test_page_url_ + fragment, "navigate", "include");
horo61f3f4f2016-03-09 01:26:14561 }
562
563 std::string ExecutePNACLUrlLoaderTest(const std::string& mode) {
564 std::string result(ExecuteScriptAndExtractString(
565 base::StringPrintf("reportOnFetch = false;"
566 "var iframe = document.createElement('iframe');"
567 "iframe.src='%s#%s';"
568 "document.body.appendChild(iframe);",
569 test_page_url_.c_str(), mode.c_str())));
570 EXPECT_EQ(base::StringPrintf("OnOpen%s", mode.c_str()), result);
571 return ExecuteScriptAndExtractString("reportRequests();");
572 }
573
574 private:
575 std::string test_page_url_;
576
577 DISALLOW_COPY_AND_ASSIGN(ChromeServiceWorkerFetchPPAPITest);
578};
579
Reilly Grant68a277f2020-08-06 19:00:30580// Flaky on Windows and Linux ASan. https://crbug.com/1113802
horo61f3f4f2016-03-09 01:26:14581IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerFetchPPAPITest,
Reilly Grant68a277f2020-08-06 19:00:30582 DISABLED_NotInterceptedByServiceWorker) {
Matt Falkenhagen7031e8b2018-02-20 03:30:33583 // Only the navigation to the iframe should be intercepted by the service
584 // worker. The request for the PNaCl manifest ("/pnacl_url_loader.nmf"),
585 // the request for the compiled code ("/pnacl_url_loader_newlib_pnacl.pexe"),
586 // and any other requests initiated by the plug-in ("/echo") should not be
587 // seen by the service worker.
588 const std::string fragment =
589 "NotIntercepted"; // this string is not important.
590 EXPECT_EQ(GetNavigationRequestString("#" + fragment),
591 ExecutePNACLUrlLoaderTest(fragment));
horo61f3f4f2016-03-09 01:26:14592}
Nico Weberaf3b00b2017-09-11 17:58:17593#endif // BUILDFLAG(ENABLE_NACL)
horo61f3f4f2016-03-09 01:26:14594
Tsuyoshi Horoa1c6f542017-06-13 15:22:41595class ChromeServiceWorkerNavigationHintTest : public ChromeServiceWorkerTest {
596 protected:
597 void RunNavigationHintTest(
598 const char* scope,
Tsuyoshi Horo6ddf281f2017-07-14 04:02:48599 content::StartServiceWorkerForNavigationHintResult expected_result,
Tsuyoshi Horoa1c6f542017-06-13 15:22:41600 bool expected_started) {
Tsuyoshi Horoa1c6f542017-06-13 15:22:41601 base::RunLoop run_loop;
602 GetServiceWorkerContext()->StartServiceWorkerForNavigationHint(
603 embedded_test_server()->GetURL(scope),
Matt Falkenhagenda8af672017-09-12 02:39:23604 base::BindOnce(&ExpectResultAndRun<
605 content::StartServiceWorkerForNavigationHintResult>,
606 expected_result, run_loop.QuitClosure()));
Tsuyoshi Horoa1c6f542017-06-13 15:22:41607 run_loop.Run();
608 if (expected_started) {
Tsuyoshi Horo8290f132017-06-22 06:26:05609 histogram_tester_.ExpectBucketCount(
Tsuyoshi Horoa1c6f542017-06-13 15:22:41610 "ServiceWorker.StartWorker.Purpose",
611 27 /* ServiceWorkerMetrics::EventType::NAVIGATION_HINT */, 1);
Tsuyoshi Horo8290f132017-06-22 06:26:05612 histogram_tester_.ExpectBucketCount(
Tsuyoshi Horoa1c6f542017-06-13 15:22:41613 "ServiceWorker.StartWorker.StatusByPurpose_NAVIGATION_HINT",
614 0 /* SERVICE_WORKER_OK */, 1);
615 } else {
Tsuyoshi Horo8290f132017-06-22 06:26:05616 histogram_tester_.ExpectTotalCount("ServiceWorker.StartWorker.Purpose",
617 0);
618 histogram_tester_.ExpectTotalCount(
Tsuyoshi Horoa1c6f542017-06-13 15:22:41619 "ServiceWorker.StartWorker.StatusByPurpose_NAVIGATION_HINT", 0);
620 }
Tsuyoshi Horo6ddf281f2017-07-14 04:02:48621 histogram_tester_.ExpectBucketCount(
622 "ServiceWorker.StartForNavigationHint.Result",
623 static_cast<int>(expected_result), 1);
Tsuyoshi Horoa1c6f542017-06-13 15:22:41624 }
Tsuyoshi Horo8290f132017-06-22 06:26:05625
626 base::HistogramTester histogram_tester_;
Tsuyoshi Horoa1c6f542017-06-13 15:22:41627};
628
629IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerNavigationHintTest, Started) {
630 WriteFile(FILE_PATH_LITERAL("sw.js"), "self.onfetch = function(e) {};");
631 WriteFile(FILE_PATH_LITERAL("test.html"), kInstallAndWaitForActivatedPage);
632 InitializeServer();
633 NavigateToPageAndWaitForReadyTitle("/test.html");
634 GetServiceWorkerContext()->StopAllServiceWorkersForOrigin(
Nidhi Jajud00cc532020-09-25 07:06:24635 url::Origin::Create(embedded_test_server()->base_url()));
Tsuyoshi Horoa1c6f542017-06-13 15:22:41636 RunNavigationHintTest(
637 "/scope/", content::StartServiceWorkerForNavigationHintResult::STARTED,
638 true);
639}
640
641IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerNavigationHintTest, AlreadyRunning) {
642 WriteFile(FILE_PATH_LITERAL("sw.js"), "self.onfetch = function(e) {};");
643 WriteFile(FILE_PATH_LITERAL("test.html"), kInstallAndWaitForActivatedPage);
644 InitializeServer();
645 NavigateToPageAndWaitForReadyTitle("/test.html");
646 RunNavigationHintTest(
647 "/scope/",
648 content::StartServiceWorkerForNavigationHintResult::ALREADY_RUNNING,
649 false);
650}
651
652IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerNavigationHintTest,
653 NoServiceWorkerRegistration) {
654 InitializeServer();
655 RunNavigationHintTest("/scope/",
656 content::StartServiceWorkerForNavigationHintResult::
657 NO_SERVICE_WORKER_REGISTRATION,
658 false);
659}
660
661IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerNavigationHintTest,
662 NoActiveServiceWorkerVersion) {
663 WriteFile(FILE_PATH_LITERAL("sw.js"),
664 "self.oninstall = function(e) {\n"
665 " e.waitUntil(new Promise(r => { /* never resolve */ }));\n"
666 " };\n"
667 "self.onfetch = function(e) {};");
668 InitializeServer();
669 base::RunLoop run_loop;
Emma Haruka Iwaobc302102017-12-05 02:33:08670 blink::mojom::ServiceWorkerRegistrationOptions options(
Tsuyoshi Horoa1c6f542017-06-13 15:22:41671 embedded_test_server()->GetURL("/scope/"),
Asami Doi5de8dea2018-09-13 10:01:07672 blink::mojom::ScriptType::kClassic,
Emma Haruka Iwaobc302102017-12-05 02:33:08673 blink::mojom::ServiceWorkerUpdateViaCache::kImports);
674 GetServiceWorkerContext()->RegisterServiceWorker(
675 embedded_test_server()->GetURL("/sw.js"), options,
Jan Wilken Dörrie8b2247e2020-04-20 10:04:40676 base::BindOnce(&ExpectResultAndRun<bool>, true, run_loop.QuitClosure()));
Tsuyoshi Horoa1c6f542017-06-13 15:22:41677 run_loop.Run();
678 RunNavigationHintTest("/scope/",
679 content::StartServiceWorkerForNavigationHintResult::
680 NO_ACTIVE_SERVICE_WORKER_VERSION,
681 false);
682}
683
684IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerNavigationHintTest, NoFetchHandler) {
685 WriteFile(FILE_PATH_LITERAL("sw.js"), "/* empty */");
686 WriteFile(FILE_PATH_LITERAL("test.html"), kInstallAndWaitForActivatedPage);
687 InitializeServer();
688 NavigateToPageAndWaitForReadyTitle("/test.html");
689 GetServiceWorkerContext()->StopAllServiceWorkersForOrigin(
Nidhi Jajud00cc532020-09-25 07:06:24690 url::Origin::Create(embedded_test_server()->base_url()));
Tsuyoshi Horoa1c6f542017-06-13 15:22:41691 RunNavigationHintTest(
692 "/scope/",
693 content::StartServiceWorkerForNavigationHintResult::NO_FETCH_HANDLER,
694 false);
695}
696
Matt Falkenhagenea306042018-11-29 00:45:25697// Copied from devtools_sanity_browsertest.cc.
698class StaticURLDataSource : public content::URLDataSource {
699 public:
700 StaticURLDataSource(const std::string& source, const std::string& content)
701 : source_(source), content_(content) {}
702 ~StaticURLDataSource() override = default;
703
704 // content::URLDataSource:
Lucas Furukawa Gadani4b4eed02019-06-04 23:12:04705 std::string GetSource() override { return source_; }
Wei-Yin Chen (陳威尹)39f4ff32019-10-22 17:59:09706 void StartDataRequest(const GURL& url,
John Abd-El-Malek92bf3602019-07-31 02:25:48707 const content::WebContents::Getter& wc_getter,
danakjf4b9e942019-11-29 15:43:04708 GotDataCallback callback) override {
Matt Falkenhagenea306042018-11-29 00:45:25709 std::string data(content_);
danakjf4b9e942019-11-29 15:43:04710 std::move(callback).Run(base::RefCountedString::TakeString(&data));
Matt Falkenhagenea306042018-11-29 00:45:25711 }
Lucas Furukawa Gadani4b4eed02019-06-04 23:12:04712 std::string GetMimeType(const std::string& path) override {
Matt Falkenhagenea306042018-11-29 00:45:25713 return "application/javascript";
714 }
Lucas Furukawa Gadani4b4eed02019-06-04 23:12:04715 bool ShouldAddContentSecurityPolicy() override { return false; }
Matt Falkenhagenea306042018-11-29 00:45:25716
717 private:
718 const std::string source_;
719 const std::string content_;
720
721 DISALLOW_COPY_AND_ASSIGN(StaticURLDataSource);
722};
723
724// Copied from devtools_sanity_browsertest.cc.
725class MockWebUIProvider
726 : public TestChromeWebUIControllerFactory::WebUIProvider {
727 public:
728 MockWebUIProvider(const std::string& source, const std::string& content)
729 : source_(source), content_(content) {}
730 ~MockWebUIProvider() override = default;
731
732 std::unique_ptr<content::WebUIController> NewWebUI(content::WebUI* web_ui,
733 const GURL& url) override {
734 content::URLDataSource::Add(
735 Profile::FromWebUI(web_ui),
736 std::make_unique<StaticURLDataSource>(source_, content_));
737 return std::make_unique<content::WebUIController>(web_ui);
738 }
739
740 private:
741 const std::string source_;
742 const std::string content_;
743 DISALLOW_COPY_AND_ASSIGN(MockWebUIProvider);
744};
745
746// Tests that registering a service worker with a chrome:// URL fails.
747IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerTest, DisallowChromeScheme) {
748 const GURL kScript("chrome://dummyurl/sw.js");
749 const GURL kScope("chrome://dummyurl");
750
751 // Make chrome://dummyurl/sw.js serve a service worker script.
752 TestChromeWebUIControllerFactory test_factory;
753 MockWebUIProvider mock_provider("serviceworker", "// empty service worker");
754 test_factory.AddFactoryOverride(kScript.host(), &mock_provider);
755 content::WebUIControllerFactory::RegisterFactory(&test_factory);
756
757 // Try to register the service worker.
758 base::RunLoop run_loop;
759 bool result = true;
760 blink::mojom::ServiceWorkerRegistrationOptions options(
761 kScope, blink::mojom::ScriptType::kClassic,
762 blink::mojom::ServiceWorkerUpdateViaCache::kImports);
763 GetServiceWorkerContext()->RegisterServiceWorker(
764 kScript, options,
765 base::BindOnce(
766 [](base::OnceClosure quit_closure, bool* out_result, bool result) {
767 *out_result = result;
768 std::move(quit_closure).Run();
769 },
770 run_loop.QuitClosure(), &result));
771 run_loop.Run();
772
773 // Registration should fail. This is the desired behavior. At the time of this
774 // writing, there are a few reasons the registration fails:
775 // * OriginCanAccessServiceWorkers() returns false for the "chrome" scheme.
776 // * Even if that returned true, the URL loader factory bundle used to make
777 // the resource request in ServiceWorkerNewScriptLoader doesn't support
778 // the "chrome" scheme. This is because:
779 // * The call to RegisterNonNetworkSubresourceURLLoaderFactories() from
780 // CreateFactoryBundle() in embedded_worker_instance.cc doesn't register
781 // the "chrome" scheme, because there is no frame/web_contents.
782 // * Even if that registered a factory, CreateFactoryBundle() would
783 // skip it because GetServiceWorkerSchemes() doesn't include "chrome".
784 //
785 // It's difficult to change all these, so the test author hasn't actually
786 // changed Chrome in a way that makes this test fail, to prove that the test
787 // would be effective at catching a regression.
788 EXPECT_FALSE(result);
789}
790
Matt Falkenhagenc0d0bac2018-12-18 08:31:08791enum class ServicifiedFeatures { kNone, kServiceWorker, kNetwork };
792
793// A simple fixture used for navigation preload tests so far. The fixture
794// stashes the HttpRequest to a certain URL, useful for inspecting the headers
795// to see if it was a navigation preload request and if it contained cookies.
796//
797// This is in //chrome instead of //content since the tests exercise the
798// kBlockThirdPartyCookies preference which is not a //content concept.
Matt Falkenhagen4332b162019-03-04 08:58:52799class ChromeServiceWorkerNavigationPreloadTest : public InProcessBrowserTest {
Matt Falkenhagenc0d0bac2018-12-18 08:31:08800 public:
801 ChromeServiceWorkerNavigationPreloadTest() = default;
802
803 void SetUp() override {
Matt Falkenhagenc0d0bac2018-12-18 08:31:08804 embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
805 &ChromeServiceWorkerNavigationPreloadTest::HandleRequest,
806 base::Unretained(this)));
807 ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
808
809 InProcessBrowserTest::SetUp();
810 }
811
812 void SetUpOnMainThread() override {
813 // Make all hosts resolve to 127.0.0.1 so the same embedded test server can
814 // be used for cross-origin URLs.
815 host_resolver()->AddRule("*", "127.0.0.1");
816
817 embedded_test_server()->StartAcceptingConnections();
818 }
819
820 std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
821 const net::test_server::HttpRequest& request) {
822 // Intercept requests to the "test" endpoint.
823 GURL url = request.base_url;
824 url = url.Resolve(request.relative_url);
825 if (url.path() != "/service_worker/test")
826 return nullptr;
827
828 // Stash the request for testing. We'd typically prefer to echo back the
829 // request and test the resulting page contents, but that becomes
830 // cumbersome if the test involves cross-origin frames.
831 EXPECT_FALSE(received_request_);
832 received_request_ = request;
833
834 // Respond with OK.
835 std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
836 new net::test_server::BasicHttpResponse());
837 http_response->set_code(net::HTTP_OK);
838 http_response->set_content("OK");
839 http_response->set_content_type("text/plain");
840 return http_response;
841 }
842
843 bool HasHeader(const net::test_server::HttpRequest& request,
844 const std::string& name) const {
845 return request.headers.find(name) != request.headers.end();
846 }
847
848 std::string GetHeader(const net::test_server::HttpRequest& request,
849 const std::string& name) const {
850 const auto& iter = request.headers.find(name);
851 EXPECT_TRUE(iter != request.headers.end());
852 if (iter == request.headers.end())
853 return std::string();
854 return iter->second;
855 }
856
857 bool has_received_request() const { return received_request_.has_value(); }
858
859 const net::test_server::HttpRequest& received_request() const {
860 return *received_request_;
861 }
862
863 private:
864 base::test::ScopedFeatureList scoped_feature_list_;
865
866 // The request that hit the "test" endpoint.
867 base::Optional<net::test_server::HttpRequest> received_request_;
868
869 DISALLOW_COPY_AND_ASSIGN(ChromeServiceWorkerNavigationPreloadTest);
870};
871
872// Tests navigation preload during a navigation in the top-level frame
873// when third-party cookies are blocked. The navigation preload request
874// should be sent with cookies as normal. Regression test for
875// https://crbug.com/913220.
Matt Falkenhagen4332b162019-03-04 08:58:52876IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerNavigationPreloadTest,
Matt Falkenhagenc0d0bac2018-12-18 08:31:08877 TopFrameWithThirdPartyBlocking) {
878 // Enable third-party cookie blocking.
Christian Dullweber80e5f262020-08-25 13:25:22879 browser()->profile()->GetPrefs()->SetInteger(
880 prefs::kCookieControlsMode,
881 static_cast<int>(content_settings::CookieControlsMode::kBlockThirdParty));
Matt Falkenhagenc0d0bac2018-12-18 08:31:08882
883 // Load a page that registers a service worker.
884 ui_test_utils::NavigateToURL(
885 browser(), embedded_test_server()->GetURL(
886 "/service_worker/create_service_worker.html"));
887 EXPECT_EQ("DONE", EvalJs(browser()->tab_strip_model()->GetActiveWebContents(),
888 "register('navigation_preload_worker.js');"));
889
890 // Also set cookies.
891 EXPECT_EQ("foo=bar",
892 EvalJs(browser()->tab_strip_model()->GetActiveWebContents(),
893 "document.cookie = 'foo=bar'; document.cookie;"));
894
895 // Load the test page.
896 ui_test_utils::NavigateToURL(
897 browser(), embedded_test_server()->GetURL("/service_worker/test"));
898
899 // The navigation preload request should have occurred and included cookies.
900 ASSERT_TRUE(has_received_request());
901 EXPECT_EQ("true",
902 GetHeader(received_request(), "Service-Worker-Navigation-Preload"));
903 EXPECT_EQ("foo=bar", GetHeader(received_request(), "Cookie"));
904}
905
906// Tests navigation preload during a navigation in a third-party iframe
907// when third-party cookies are blocked. This blocks service worker as well,
908// so the navigation preload request should not be sent. And the navigation
909// request should not include cookies.
Matt Falkenhagen4332b162019-03-04 08:58:52910IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerNavigationPreloadTest,
Matt Falkenhagenc0d0bac2018-12-18 08:31:08911 SubFrameWithThirdPartyBlocking) {
912 // Enable third-party cookie blocking.
Christian Dullweber80e5f262020-08-25 13:25:22913 browser()->profile()->GetPrefs()->SetInteger(
914 prefs::kCookieControlsMode,
915 static_cast<int>(content_settings::CookieControlsMode::kBlockThirdParty));
Matt Falkenhagenc0d0bac2018-12-18 08:31:08916
917 // Load a page that registers a service worker.
918 ui_test_utils::NavigateToURL(
919 browser(), embedded_test_server()->GetURL(
920 "/service_worker/create_service_worker.html"));
921 EXPECT_EQ("DONE", EvalJs(browser()->tab_strip_model()->GetActiveWebContents(),
922 "register('navigation_preload_worker.js');"));
923
924 // Also set cookies.
925 EXPECT_EQ("foo=bar",
926 EvalJs(browser()->tab_strip_model()->GetActiveWebContents(),
927 "document.cookie = 'foo=bar'; document.cookie;"));
928
929 // Generate a cross-origin URL.
930 GURL top_frame_url = embedded_test_server()->GetURL(
931 "/service_worker/page_with_third_party_iframe.html");
932 GURL::Replacements replacements;
933 replacements.SetHostStr("cross-origin.example.com");
934 top_frame_url = top_frame_url.ReplaceComponents(replacements);
935
936 // Navigate to the page and embed a third-party iframe to the test
937 // page.
938 ui_test_utils::NavigateToURL(browser(), top_frame_url);
939 GURL iframe_url = embedded_test_server()->GetURL("/service_worker/test");
940 EXPECT_EQ(true, EvalJs(browser()->tab_strip_model()->GetActiveWebContents(),
941 "addIframe('" + iframe_url.spec() + "');"));
942
943 // The request should have been received. Because the navigation was for a
944 // third-party iframe with cookies blocked, the service worker should not have
945 // handled the request so navigation preload should not have occurred.
946 // Likewise, the cookies should not have been sent.
947 ASSERT_TRUE(has_received_request());
948 EXPECT_FALSE(
949 HasHeader(received_request(), "Service-Worker-Navigation-Preload"));
950 EXPECT_FALSE(HasHeader(received_request(), "Cookie"));
951}
952
Matt Falkenhagenea306042018-11-29 00:45:25953} // namespace chrome_service_worker_browser_test