1 // Copyright 2016 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 #include <memory>
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/files/file_enumerator.h"
10 #include "base/files/file_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/threading/thread_restrictions.h"
14 #include "build/build_config.h"
15 #include "content/public/browser/navigation_controller.h"
16 #include "content/public/browser/navigation_entry.h"
17 #include "content/public/browser/permission_controller_delegate.h"
18 #include "content/public/browser/permission_type.h"
19 #include "content/public/browser/ssl_status.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/common/content_switches.h"
22 #include "content/public/common/url_constants.h"
23 #include "content/public/test/browser_test.h"
24 #include "content/public/test/no_renderer_crashes_assertion.h"
25 #include "headless/lib/browser/headless_browser_context_impl.h"
26 #include "headless/lib/browser/headless_web_contents_impl.h"
27 #include "headless/lib/headless_macros.h"
28 #include "headless/public/devtools/domains/inspector.h"
29 #include "headless/public/devtools/domains/network.h"
30 #include "headless/public/devtools/domains/page.h"
31 #include "headless/public/devtools/domains/tracing.h"
32 #include "headless/public/headless_browser.h"
33 #include "headless/public/headless_devtools_client.h"
34 #include "headless/public/headless_devtools_target.h"
35 #include "headless/public/headless_web_contents.h"
36 #include "headless/test/headless_browser_test.h"
37 #include "net/cert/cert_status_flags.h"
38 #include "net/test/embedded_test_server/embedded_test_server.h"
39 #include "net/test/spawned_test_server/spawned_test_server.h"
40 #include "testing/gmock/include/gmock/gmock.h"
41 #include "testing/gtest/include/gtest/gtest.h"
42 #include "ui/base/clipboard/clipboard.h"
43 #include "ui/base/clipboard/scoped_clipboard_writer.h"
44 #include "ui/gfx/geometry/size.h"
45
46 #if defined(OS_MAC)
47 #include "third_party/crashpad/crashpad/client/crash_report_database.h"
48 #endif
49
50 using testing::UnorderedElementsAre;
51
52 namespace headless {
53
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,CreateAndDestroyBrowserContext)54 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, CreateAndDestroyBrowserContext) {
55 HeadlessBrowserContext* browser_context =
56 browser()->CreateBrowserContextBuilder().Build();
57
58 EXPECT_THAT(browser()->GetAllBrowserContexts(),
59 UnorderedElementsAre(browser_context));
60
61 browser_context->Close();
62
63 EXPECT_TRUE(browser()->GetAllBrowserContexts().empty());
64 }
65
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,CreateAndDoNotDestroyBrowserContext)66 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,
67 CreateAndDoNotDestroyBrowserContext) {
68 HeadlessBrowserContext* browser_context =
69 browser()->CreateBrowserContextBuilder().Build();
70
71 EXPECT_THAT(browser()->GetAllBrowserContexts(),
72 UnorderedElementsAre(browser_context));
73
74 // We check that HeadlessBrowser correctly handles non-closed BrowserContexts.
75 // We can rely on Chromium DCHECKs to capture this.
76 }
77
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,CreateAndDestroyWebContents)78 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, CreateAndDestroyWebContents) {
79 HeadlessBrowserContext* browser_context =
80 browser()->CreateBrowserContextBuilder().Build();
81
82 HeadlessWebContents* web_contents =
83 browser_context->CreateWebContentsBuilder().Build();
84 EXPECT_TRUE(web_contents);
85
86 EXPECT_THAT(browser()->GetAllBrowserContexts(),
87 UnorderedElementsAre(browser_context));
88 EXPECT_THAT(browser_context->GetAllWebContents(),
89 UnorderedElementsAre(web_contents));
90
91 // TODO(skyostil): Verify viewport dimensions once we can.
92
93 web_contents->Close();
94
95 EXPECT_TRUE(browser_context->GetAllWebContents().empty());
96
97 browser_context->Close();
98
99 EXPECT_TRUE(browser()->GetAllBrowserContexts().empty());
100 }
101
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,WebContentsAreDestroyedWithContext)102 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,
103 WebContentsAreDestroyedWithContext) {
104 HeadlessBrowserContext* browser_context =
105 browser()->CreateBrowserContextBuilder().Build();
106
107 HeadlessWebContents* web_contents =
108 browser_context->CreateWebContentsBuilder().Build();
109 EXPECT_TRUE(web_contents);
110
111 EXPECT_THAT(browser()->GetAllBrowserContexts(),
112 UnorderedElementsAre(browser_context));
113 EXPECT_THAT(browser_context->GetAllWebContents(),
114 UnorderedElementsAre(web_contents));
115
116 browser_context->Close();
117
118 EXPECT_TRUE(browser()->GetAllBrowserContexts().empty());
119
120 // If WebContents are not destroyed, Chromium DCHECKs will capture this.
121 }
122
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,CreateAndDoNotDestroyWebContents)123 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, CreateAndDoNotDestroyWebContents) {
124 HeadlessBrowserContext* browser_context =
125 browser()->CreateBrowserContextBuilder().Build();
126
127 HeadlessWebContents* web_contents =
128 browser_context->CreateWebContentsBuilder().Build();
129 EXPECT_TRUE(web_contents);
130
131 EXPECT_THAT(browser()->GetAllBrowserContexts(),
132 UnorderedElementsAre(browser_context));
133 EXPECT_THAT(browser_context->GetAllWebContents(),
134 UnorderedElementsAre(web_contents));
135
136 // If WebContents are not destroyed, Chromium DCHECKs will capture this.
137 }
138
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,DestroyAndCreateTwoWebContents)139 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, DestroyAndCreateTwoWebContents) {
140 HeadlessBrowserContext* browser_context1 =
141 browser()->CreateBrowserContextBuilder().Build();
142 EXPECT_TRUE(browser_context1);
143 HeadlessWebContents* web_contents1 =
144 browser_context1->CreateWebContentsBuilder().Build();
145 EXPECT_TRUE(web_contents1);
146
147 EXPECT_THAT(browser()->GetAllBrowserContexts(),
148 UnorderedElementsAre(browser_context1));
149 EXPECT_THAT(browser_context1->GetAllWebContents(),
150 UnorderedElementsAre(web_contents1));
151
152 HeadlessBrowserContext* browser_context2 =
153 browser()->CreateBrowserContextBuilder().Build();
154 EXPECT_TRUE(browser_context2);
155 HeadlessWebContents* web_contents2 =
156 browser_context2->CreateWebContentsBuilder().Build();
157 EXPECT_TRUE(web_contents2);
158
159 EXPECT_THAT(browser()->GetAllBrowserContexts(),
160 UnorderedElementsAre(browser_context1, browser_context2));
161 EXPECT_THAT(browser_context1->GetAllWebContents(),
162 UnorderedElementsAre(web_contents1));
163 EXPECT_THAT(browser_context2->GetAllWebContents(),
164 UnorderedElementsAre(web_contents2));
165
166 browser_context1->Close();
167
168 EXPECT_THAT(browser()->GetAllBrowserContexts(),
169 UnorderedElementsAre(browser_context2));
170 EXPECT_THAT(browser_context2->GetAllWebContents(),
171 UnorderedElementsAre(web_contents2));
172
173 browser_context2->Close();
174
175 EXPECT_TRUE(browser()->GetAllBrowserContexts().empty());
176 }
177
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,CreateWithBadURL)178 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, CreateWithBadURL) {
179 GURL bad_url("not_valid");
180
181 HeadlessBrowserContext* browser_context =
182 browser()->CreateBrowserContextBuilder().Build();
183
184 HeadlessWebContents* web_contents =
185 browser_context->CreateWebContentsBuilder()
186 .SetInitialURL(bad_url)
187 .Build();
188
189 EXPECT_FALSE(web_contents);
190 EXPECT_TRUE(browser_context->GetAllWebContents().empty());
191 }
192
193 class HeadlessBrowserTestWithProxy : public HeadlessBrowserTest {
194 public:
HeadlessBrowserTestWithProxy()195 HeadlessBrowserTestWithProxy()
196 : proxy_server_(net::EmbeddedTestServer::TYPE_HTTP) {
197 proxy_server_.AddDefaultHandlers(
198 base::FilePath(FILE_PATH_LITERAL("headless/test/data")));
199 }
200
SetUp()201 void SetUp() override {
202 ASSERT_TRUE(proxy_server_.Start());
203 HeadlessBrowserTest::SetUp();
204 }
205
TearDown()206 void TearDown() override {
207 EXPECT_TRUE(proxy_server_.ShutdownAndWaitUntilComplete());
208 HeadlessBrowserTest::TearDown();
209 }
210
proxy_server()211 net::EmbeddedTestServer* proxy_server() { return &proxy_server_; }
212
213 private:
214 net::EmbeddedTestServer proxy_server_;
215 };
216
217 #if defined(OS_MAC) && defined(ADDRESS_SANITIZER)
218 // TODO(crbug.com/1086872): Disabled due to flakiness on Mac ASAN.
219 #define MAYBE_SetProxyConfig DISABLED_SetProxyConfig
220 #else
221 #define MAYBE_SetProxyConfig SetProxyConfig
222 #endif
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTestWithProxy,MAYBE_SetProxyConfig)223 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTestWithProxy, MAYBE_SetProxyConfig) {
224 std::unique_ptr<net::ProxyConfig> proxy_config(new net::ProxyConfig);
225 proxy_config->proxy_rules().ParseFromString(
226 proxy_server()->host_port_pair().ToString());
227 HeadlessBrowserContext* browser_context =
228 browser()
229 ->CreateBrowserContextBuilder()
230 .SetProxyConfig(std::move(proxy_config))
231 .Build();
232
233 // Load a page which doesn't actually exist, but for which the our proxy
234 // returns valid content anyway.
235 HeadlessWebContents* web_contents =
236 browser_context->CreateWebContentsBuilder()
237 .SetInitialURL(GURL("http://not-an-actual-domain.tld/hello.html"))
238 .Build();
239 EXPECT_TRUE(WaitForLoad(web_contents));
240 EXPECT_THAT(browser()->GetAllBrowserContexts(),
241 UnorderedElementsAre(browser_context));
242 EXPECT_THAT(browser_context->GetAllWebContents(),
243 UnorderedElementsAre(web_contents));
244 web_contents->Close();
245 EXPECT_TRUE(browser_context->GetAllWebContents().empty());
246 }
247
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,WebGLSupported)248 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, WebGLSupported) {
249 HeadlessBrowserContext* browser_context =
250 browser()->CreateBrowserContextBuilder().Build();
251
252 HeadlessWebContents* web_contents =
253 browser_context->CreateWebContentsBuilder().Build();
254
255 EXPECT_TRUE(
256 EvaluateScript(web_contents,
257 "(document.createElement('canvas').getContext('webgl')"
258 " instanceof WebGLRenderingContext)")
259 ->GetResult()
260 ->GetValue()
261 ->GetBool());
262 }
263
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,ClipboardCopyPasteText)264 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, ClipboardCopyPasteText) {
265 // Tests copy-pasting text with the clipboard in headless mode.
266 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
267 ASSERT_TRUE(clipboard);
268 base::string16 paste_text = base::ASCIIToUTF16("Clippy!");
269 for (ui::ClipboardBuffer buffer :
270 {ui::ClipboardBuffer::kCopyPaste, ui::ClipboardBuffer::kSelection,
271 ui::ClipboardBuffer::kDrag}) {
272 if (!ui::Clipboard::IsSupportedClipboardBuffer(buffer))
273 continue;
274 {
275 ui::ScopedClipboardWriter writer(buffer);
276 writer.WriteText(paste_text);
277 }
278 base::string16 copy_text;
279 clipboard->ReadText(buffer, /* data_dst = */ nullptr, ©_text);
280 EXPECT_EQ(paste_text, copy_text);
281 }
282 }
283
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,DefaultSizes)284 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, DefaultSizes) {
285 HeadlessBrowserContext* browser_context =
286 browser()->CreateBrowserContextBuilder().Build();
287
288 HeadlessWebContents* web_contents =
289 browser_context->CreateWebContentsBuilder().Build();
290
291 HeadlessBrowser::Options::Builder builder;
292 const HeadlessBrowser::Options kDefaultOptions = builder.Build();
293
294 #if !defined(OS_MAC)
295 // On Mac headless does not override the screen dimensions, so they are
296 // left with the actual screen values.
297 EXPECT_EQ(kDefaultOptions.window_size.width(),
298 EvaluateScript(web_contents, "screen.width")
299 ->GetResult()
300 ->GetValue()
301 ->GetInt());
302 EXPECT_EQ(kDefaultOptions.window_size.height(),
303 EvaluateScript(web_contents, "screen.height")
304 ->GetResult()
305 ->GetValue()
306 ->GetInt());
307 #endif // !defined(OS_MAC)
308 EXPECT_EQ(kDefaultOptions.window_size.width(),
309 EvaluateScript(web_contents, "window.innerWidth")
310 ->GetResult()
311 ->GetValue()
312 ->GetInt());
313 EXPECT_EQ(kDefaultOptions.window_size.height(),
314 EvaluateScript(web_contents, "window.innerHeight")
315 ->GetResult()
316 ->GetValue()
317 ->GetInt());
318 }
319
320 namespace {
321
322 class CookieSetter {
323 public:
CookieSetter(HeadlessBrowserTest * browser_test,HeadlessWebContents * web_contents,std::unique_ptr<network::SetCookieParams> set_cookie_params)324 CookieSetter(HeadlessBrowserTest* browser_test,
325 HeadlessWebContents* web_contents,
326 std::unique_ptr<network::SetCookieParams> set_cookie_params)
327 : browser_test_(browser_test),
328 web_contents_(web_contents),
329 devtools_client_(HeadlessDevToolsClient::Create()) {
330 web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get());
331 devtools_client_->GetNetwork()->GetExperimental()->SetCookie(
332 std::move(set_cookie_params),
333 base::BindOnce(&CookieSetter::OnSetCookieResult,
334 base::Unretained(this)));
335 }
336
~CookieSetter()337 ~CookieSetter() {
338 web_contents_->GetDevToolsTarget()->DetachClient(devtools_client_.get());
339 }
340
OnSetCookieResult(std::unique_ptr<network::SetCookieResult> result)341 void OnSetCookieResult(std::unique_ptr<network::SetCookieResult> result) {
342 result_ = std::move(result);
343 browser_test_->FinishAsynchronousTest();
344 }
345
TakeResult()346 std::unique_ptr<network::SetCookieResult> TakeResult() {
347 return std::move(result_);
348 }
349
350 private:
351 HeadlessBrowserTest* browser_test_; // Not owned.
352 HeadlessWebContents* web_contents_; // Not owned.
353 std::unique_ptr<HeadlessDevToolsClient> devtools_client_;
354
355 std::unique_ptr<network::SetCookieResult> result_;
356
357 DISALLOW_COPY_AND_ASSIGN(CookieSetter);
358 };
359
360 } // namespace
361
362 // TODO(skyostil): This test currently relies on being able to run a shell
363 // script.
364 #if defined(OS_POSIX)
365 class HeadlessBrowserRendererCommandPrefixTest : public HeadlessBrowserTest {
366 public:
launcher_stamp() const367 const base::FilePath& launcher_stamp() const { return launcher_stamp_; }
368
SetUp()369 void SetUp() override {
370 base::ThreadRestrictions::SetIOAllowed(true);
371 base::CreateTemporaryFile(&launcher_stamp_);
372
373 base::ScopedFILE launcher_file =
374 base::CreateAndOpenTemporaryStream(&launcher_script_);
375 fprintf(launcher_file.get(), "#!/bin/sh\n");
376 fprintf(launcher_file.get(), "echo $@ > %s\n",
377 launcher_stamp_.value().c_str());
378 fprintf(launcher_file.get(), "exec $@\n");
379 launcher_file.reset();
380 #if !defined(OS_FUCHSIA)
381 base::SetPosixFilePermissions(launcher_script_,
382 base::FILE_PERMISSION_READ_BY_USER |
383 base::FILE_PERMISSION_EXECUTE_BY_USER);
384 #endif // !defined(OS_FUCHSIA)
385
386 HeadlessBrowserTest::SetUp();
387 }
388
TearDown()389 void TearDown() override {
390 if (!launcher_script_.empty())
391 base::DeleteFile(launcher_script_);
392 if (!launcher_stamp_.empty())
393 base::DeleteFile(launcher_stamp_);
394 }
395
SetUpCommandLine(base::CommandLine * command_line)396 void SetUpCommandLine(base::CommandLine* command_line) override {
397 command_line->AppendSwitch("--no-sandbox");
398 command_line->AppendSwitchASCII("--renderer-cmd-prefix",
399 launcher_script_.value());
400 }
401
402 private:
403 base::FilePath launcher_stamp_;
404 base::FilePath launcher_script_;
405 };
406
IN_PROC_BROWSER_TEST_F(HeadlessBrowserRendererCommandPrefixTest,Prefix)407 IN_PROC_BROWSER_TEST_F(HeadlessBrowserRendererCommandPrefixTest, Prefix) {
408 base::ThreadRestrictions::SetIOAllowed(true);
409 EXPECT_TRUE(embedded_test_server()->Start());
410
411 HeadlessBrowserContext* browser_context =
412 browser()->CreateBrowserContextBuilder().Build();
413
414 HeadlessWebContents* web_contents =
415 browser_context->CreateWebContentsBuilder()
416 .SetInitialURL(embedded_test_server()->GetURL("/hello.html"))
417 .Build();
418 EXPECT_TRUE(WaitForLoad(web_contents));
419
420 // Make sure the launcher was invoked when starting the renderer.
421 std::string stamp;
422 EXPECT_TRUE(base::ReadFileToString(launcher_stamp(), &stamp));
423 EXPECT_GE(stamp.find("--type=renderer"), 0u);
424 }
425 #endif // defined(OS_POSIX)
426
427 class CrashReporterTest : public HeadlessBrowserTest,
428 public HeadlessWebContents::Observer,
429 inspector::ExperimentalObserver {
430 public:
CrashReporterTest()431 CrashReporterTest() {}
432 ~CrashReporterTest() override = default;
433
SetUp()434 void SetUp() override {
435 base::ThreadRestrictions::SetIOAllowed(true);
436 base::CreateNewTempDirectory(FILE_PATH_LITERAL("CrashReporterTest"),
437 &crash_dumps_dir_);
438 EXPECT_FALSE(options()->enable_crash_reporter);
439 options()->enable_crash_reporter = true;
440 options()->crash_dumps_dir = crash_dumps_dir_;
441 HeadlessBrowserTest::SetUp();
442 }
443
TearDown()444 void TearDown() override {
445 base::ThreadRestrictions::SetIOAllowed(true);
446 base::DeleteFile(crash_dumps_dir_);
447 }
448
449 // HeadlessWebContents::Observer implementation:
DevToolsTargetReady()450 void DevToolsTargetReady() override {
451 EXPECT_TRUE(web_contents_->GetDevToolsTarget());
452 devtools_client_ = HeadlessDevToolsClient::Create();
453 web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get());
454 devtools_client_->GetInspector()->GetExperimental()->AddObserver(this);
455 }
456
457 // inspector::ExperimentalObserver implementation:
OnTargetCrashed(const inspector::TargetCrashedParams &)458 void OnTargetCrashed(const inspector::TargetCrashedParams&) override {
459 FinishAsynchronousTest();
460 }
461
462 protected:
463 HeadlessBrowserContext* browser_context_ = nullptr;
464 HeadlessWebContents* web_contents_ = nullptr;
465 std::unique_ptr<HeadlessDevToolsClient> devtools_client_;
466 base::FilePath crash_dumps_dir_;
467 };
468
469 // TODO(skyostil): Minidump generation currently is only supported on Linux and
470 // Mac.
471 #if (defined(HEADLESS_USE_BREAKPAD) || defined(OS_MAC)) && \
472 !defined(ADDRESS_SANITIZER)
473 #define MAYBE_GenerateMinidump GenerateMinidump
474 #else
475 #define MAYBE_GenerateMinidump DISABLED_GenerateMinidump
476 #endif // defined(HEADLESS_USE_BREAKPAD) || defined(OS_MAC)
IN_PROC_BROWSER_TEST_F(CrashReporterTest,MAYBE_GenerateMinidump)477 IN_PROC_BROWSER_TEST_F(CrashReporterTest, MAYBE_GenerateMinidump) {
478 content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes;
479
480 // Navigates a tab to chrome://crash and checks that a minidump is generated.
481 // Note that we only test renderer crashes here -- browser crashes need to be
482 // tested with a separate harness.
483 //
484 // The case where crash reporting is disabled is covered by
485 // HeadlessCrashObserverTest.
486 browser_context_ = browser()->CreateBrowserContextBuilder().Build();
487
488 web_contents_ = browser_context_->CreateWebContentsBuilder()
489 .SetInitialURL(GURL(content::kChromeUICrashURL))
490 .Build();
491
492 web_contents_->AddObserver(this);
493 RunAsynchronousTest();
494
495 // The target has crashed and should no longer be there.
496 EXPECT_FALSE(web_contents_->GetDevToolsTarget());
497
498 // Check that one minidump got created.
499 {
500 base::ThreadRestrictions::SetIOAllowed(true);
501
502 #if defined(OS_MAC)
503 auto database = crashpad::CrashReportDatabase::Initialize(crash_dumps_dir_);
504 std::vector<crashpad::CrashReportDatabase::Report> reports;
505 ASSERT_EQ(database->GetPendingReports(&reports),
506 crashpad::CrashReportDatabase::kNoError);
507 EXPECT_EQ(reports.size(), 1u);
508 #else
509 base::FileEnumerator it(crash_dumps_dir_, /* recursive */ false,
510 base::FileEnumerator::FILES);
511 base::FilePath minidump = it.Next();
512 EXPECT_FALSE(minidump.empty());
513 EXPECT_EQ(FILE_PATH_LITERAL(".dmp"), minidump.Extension());
514 EXPECT_TRUE(it.Next().empty());
515 #endif
516 }
517
518 web_contents_->RemoveObserver(this);
519 web_contents_->Close();
520 web_contents_ = nullptr;
521
522 browser_context_->Close();
523 browser_context_ = nullptr;
524 }
525
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,PermissionManagerAlwaysASK)526 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, PermissionManagerAlwaysASK) {
527 GURL url("https://example.com");
528
529 HeadlessBrowserContext* browser_context =
530 browser()->CreateBrowserContextBuilder().Build();
531
532 HeadlessWebContents* headless_web_contents =
533 browser_context->CreateWebContentsBuilder().Build();
534 EXPECT_TRUE(headless_web_contents);
535
536 HeadlessWebContentsImpl* web_contents =
537 HeadlessWebContentsImpl::From(headless_web_contents);
538
539 content::PermissionControllerDelegate* permission_controller_delegate =
540 web_contents->browser_context()->GetPermissionControllerDelegate();
541 EXPECT_NE(nullptr, permission_controller_delegate);
542
543 // Check that the permission manager returns ASK for a given permission type.
544 EXPECT_EQ(blink::mojom::PermissionStatus::ASK,
545 permission_controller_delegate->GetPermissionStatus(
546 content::PermissionType::NOTIFICATIONS, url, url));
547 }
548
549 namespace {
550
551 class TraceHelper : public tracing::ExperimentalObserver {
552 public:
TraceHelper(HeadlessBrowserTest * browser_test,HeadlessDevToolsTarget * target)553 TraceHelper(HeadlessBrowserTest* browser_test, HeadlessDevToolsTarget* target)
554 : browser_test_(browser_test),
555 target_(target),
556 client_(HeadlessDevToolsClient::Create()),
557 tracing_data_(std::make_unique<base::ListValue>()) {
558 EXPECT_FALSE(target_->IsAttached());
559 target_->AttachClient(client_.get());
560 EXPECT_TRUE(target_->IsAttached());
561
562 client_->GetTracing()->GetExperimental()->AddObserver(this);
563
564 client_->GetTracing()->GetExperimental()->Start(
565 tracing::StartParams::Builder().Build(),
566 base::BindOnce(&TraceHelper::OnTracingStarted, base::Unretained(this)));
567 }
568
~TraceHelper()569 ~TraceHelper() override {
570 target_->DetachClient(client_.get());
571 EXPECT_FALSE(target_->IsAttached());
572 }
573
TakeTracingData()574 std::unique_ptr<base::ListValue> TakeTracingData() {
575 return std::move(tracing_data_);
576 }
577
578 private:
OnTracingStarted(std::unique_ptr<tracing::StartResult>)579 void OnTracingStarted(std::unique_ptr<tracing::StartResult>) {
580 // We don't need the callback from End, but the OnTracingComplete event.
581 client_->GetTracing()->GetExperimental()->End(
582 tracing::EndParams::Builder().Build());
583 }
584
585 // tracing::ExperimentalObserver implementation:
OnDataCollected(const tracing::DataCollectedParams & params)586 void OnDataCollected(const tracing::DataCollectedParams& params) override {
587 for (const auto& value : *params.GetValue()) {
588 tracing_data_->Append(value->CreateDeepCopy());
589 }
590 }
591
OnTracingComplete(const tracing::TracingCompleteParams & params)592 void OnTracingComplete(
593 const tracing::TracingCompleteParams& params) override {
594 browser_test_->FinishAsynchronousTest();
595 }
596
597 HeadlessBrowserTest* browser_test_; // Not owned.
598 HeadlessDevToolsTarget* target_; // Not owned.
599 std::unique_ptr<HeadlessDevToolsClient> client_;
600
601 std::unique_ptr<base::ListValue> tracing_data_;
602
603 DISALLOW_COPY_AND_ASSIGN(TraceHelper);
604 };
605
606 } // namespace
607
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,TraceUsingBrowserDevToolsTarget)608 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, TraceUsingBrowserDevToolsTarget) {
609 HeadlessDevToolsTarget* target = browser()->GetDevToolsTarget();
610 EXPECT_NE(nullptr, target);
611
612 TraceHelper helper(this, target);
613 RunAsynchronousTest();
614
615 std::unique_ptr<base::ListValue> tracing_data = helper.TakeTracingData();
616 EXPECT_TRUE(tracing_data);
617 EXPECT_LT(0u, tracing_data->GetSize());
618 }
619
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,WindowPrint)620 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, WindowPrint) {
621 EXPECT_TRUE(embedded_test_server()->Start());
622
623 HeadlessBrowserContext* browser_context =
624 browser()->CreateBrowserContextBuilder().Build();
625
626 HeadlessWebContents* web_contents =
627 browser_context->CreateWebContentsBuilder()
628 .SetInitialURL(embedded_test_server()->GetURL("/hello.html"))
629 .Build();
630 EXPECT_TRUE(WaitForLoad(web_contents));
631 EXPECT_FALSE(
632 EvaluateScript(web_contents, "window.print()")->HasExceptionDetails());
633 }
634
635 class HeadlessBrowserAllowInsecureLocalhostTest : public HeadlessBrowserTest {
636 public:
SetUpCommandLine(base::CommandLine * command_line)637 void SetUpCommandLine(base::CommandLine* command_line) override {
638 command_line->AppendSwitch(switches::kAllowInsecureLocalhost);
639 }
640 };
641
IN_PROC_BROWSER_TEST_F(HeadlessBrowserAllowInsecureLocalhostTest,AllowInsecureLocalhostFlag)642 IN_PROC_BROWSER_TEST_F(HeadlessBrowserAllowInsecureLocalhostTest,
643 AllowInsecureLocalhostFlag) {
644 net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
645 https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED);
646 https_server.ServeFilesFromSourceDirectory("headless/test/data");
647 ASSERT_TRUE(https_server.Start());
648 GURL test_url = https_server.GetURL("/hello.html");
649
650 HeadlessBrowserContext* browser_context =
651 browser()->CreateBrowserContextBuilder().Build();
652
653 HeadlessWebContentsImpl* web_contents =
654 HeadlessWebContentsImpl::From(browser_context->CreateWebContentsBuilder()
655 .SetInitialURL(test_url)
656 .Build());
657
658 // If the certificate fails to validate, this should fail.
659 EXPECT_TRUE(WaitForLoad(web_contents));
660 }
661
662 class HeadlessBrowserTestAppendCommandLineFlags : public HeadlessBrowserTest {
663 public:
HeadlessBrowserTestAppendCommandLineFlags()664 HeadlessBrowserTestAppendCommandLineFlags() {
665 options()->append_command_line_flags_callback = base::BindRepeating(
666 &HeadlessBrowserTestAppendCommandLineFlags::AppendCommandLineFlags,
667 base::Unretained(this));
668 }
669
AppendCommandLineFlags(base::CommandLine * command_line,HeadlessBrowserContext * child_browser_context,const std::string & child_process_type,int child_process_id)670 void AppendCommandLineFlags(base::CommandLine* command_line,
671 HeadlessBrowserContext* child_browser_context,
672 const std::string& child_process_type,
673 int child_process_id) {
674 if (child_process_type != "renderer")
675 return;
676
677 callback_was_run_ = true;
678 EXPECT_LE(0, child_process_id);
679 EXPECT_NE(nullptr, command_line);
680 EXPECT_NE(nullptr, child_browser_context);
681 }
682
683 protected:
684 bool callback_was_run_ = false;
685 };
686
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTestAppendCommandLineFlags,AppendChildProcessCommandLineFlags)687 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTestAppendCommandLineFlags,
688 AppendChildProcessCommandLineFlags) {
689 // Create a new renderer process, and verify that callback was executed.
690 HeadlessBrowserContext* browser_context =
691 browser()->CreateBrowserContextBuilder().Build();
692 HeadlessWebContents* web_contents =
693 browser_context->CreateWebContentsBuilder()
694 .SetInitialURL(GURL("about:blank"))
695 .Build();
696
697 EXPECT_TRUE(callback_was_run_);
698
699 // Used only for lifetime.
700 (void)web_contents;
701 }
702
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,ServerWantsClientCertificate)703 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, ServerWantsClientCertificate) {
704 net::SpawnedTestServer::SSLOptions ssl_options;
705 ssl_options.request_client_certificate = true;
706
707 net::SpawnedTestServer server(
708 net::SpawnedTestServer::TYPE_HTTPS, ssl_options,
709 base::FilePath(FILE_PATH_LITERAL("headless/test/data")));
710 EXPECT_TRUE(server.Start());
711
712 HeadlessBrowserContext* browser_context =
713 browser()->CreateBrowserContextBuilder().Build();
714
715 HeadlessWebContents* web_contents =
716 browser_context->CreateWebContentsBuilder()
717 .SetInitialURL(server.GetURL("/hello.html"))
718 .Build();
719 EXPECT_TRUE(WaitForLoad(web_contents));
720 }
721
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,AIAFetching)722 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, AIAFetching) {
723 net::EmbeddedTestServer server(net::EmbeddedTestServer::TYPE_HTTPS);
724 net::EmbeddedTestServer::ServerCertificateConfig cert_config;
725 cert_config.intermediate = net::EmbeddedTestServer::IntermediateType::kByAIA;
726 server.SetSSLConfig(cert_config);
727 server.AddDefaultHandlers(base::FilePath(FILE_PATH_LITERAL("net/data/ssl")));
728 ASSERT_TRUE(server.Start());
729
730 HeadlessBrowserContext* browser_context =
731 browser()->CreateBrowserContextBuilder().Build();
732 browser()->SetDefaultBrowserContext(browser_context);
733
734 GURL url = server.GetURL("/defaultresponse");
735 HeadlessWebContents* web_contents =
736 browser_context->CreateWebContentsBuilder().SetInitialURL(url).Build();
737 EXPECT_TRUE(WaitForLoad(web_contents));
738 content::NavigationEntry* last_entry =
739 HeadlessWebContentsImpl::From(web_contents)
740 ->web_contents()
741 ->GetController()
742 .GetLastCommittedEntry();
743 EXPECT_FALSE(net::IsCertStatusError(last_entry->GetSSL().cert_status));
744 EXPECT_EQ(url, last_entry->GetURL());
745 }
746
747 } // namespace headless
748