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