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, &copy_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