OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <memory> | 5 #include <memory> |
6 #include <sstream> | 6 #include <sstream> |
7 #include <string> | 7 #include <string> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/base64.h" | 10 #include "base/base64.h" |
11 #include "base/base_switches.h" | 11 #include "base/base_switches.h" |
12 #include "base/bind.h" | 12 #include "base/bind.h" |
13 #include "base/callback.h" | 13 #include "base/callback.h" |
14 #include "base/command_line.h" | 14 #include "base/command_line.h" |
15 #include "base/files/file_path.h" | 15 #include "base/files/file_path.h" |
16 #include "base/json/json_writer.h" | 16 #include "base/json/json_writer.h" |
17 #include "base/location.h" | 17 #include "base/location.h" |
18 #include "base/memory/weak_ptr.h" | 18 #include "base/memory/weak_ptr.h" |
19 #include "base/numerics/safe_conversions.h" | 19 #include "base/numerics/safe_conversions.h" |
20 #include "base/strings/string_number_conversions.h" | 20 #include "base/strings/string_number_conversions.h" |
| 21 #include "content/public/app/content_main.h" |
21 #include "content/public/common/content_switches.h" | 22 #include "content/public/common/content_switches.h" |
22 #include "headless/app/headless_shell.h" | 23 #include "headless/app/headless_shell.h" |
23 #include "headless/app/headless_shell_switches.h" | 24 #include "headless/app/headless_shell_switches.h" |
24 #include "headless/lib/browser/headless_devtools.h" | 25 #include "headless/lib/browser/headless_devtools.h" |
25 #include "headless/public/headless_devtools_target.h" | 26 #include "headless/public/headless_devtools_target.h" |
26 #include "headless/public/util/deterministic_http_protocol_handler.h" | 27 #include "headless/public/util/deterministic_http_protocol_handler.h" |
27 #include "net/base/io_buffer.h" | 28 #include "net/base/io_buffer.h" |
28 #include "net/base/ip_address.h" | 29 #include "net/base/ip_address.h" |
29 #include "net/base/net_errors.h" | 30 #include "net/base/net_errors.h" |
30 #include "net/http/http_util.h" | 31 #include "net/http/http_util.h" |
31 #include "ui/gfx/geometry/size.h" | 32 #include "ui/gfx/geometry/size.h" |
32 | 33 |
| 34 #if defined(OS_WIN) |
| 35 #include "sandbox/win/src/sandbox_types.h" |
| 36 #endif |
| 37 |
33 namespace headless { | 38 namespace headless { |
34 namespace { | 39 namespace { |
35 // Address where to listen to incoming DevTools connections. | 40 // Address where to listen to incoming DevTools connections. |
36 const char kDevToolsHttpServerAddress[] = "127.0.0.1"; | 41 const char kDevToolsHttpServerAddress[] = "127.0.0.1"; |
37 // Default file name for screenshot. Can be overriden by "--screenshot" switch. | 42 // Default file name for screenshot. Can be overriden by "--screenshot" switch. |
38 const char kDefaultScreenshotFileName[] = "screenshot.png"; | 43 const char kDefaultScreenshotFileName[] = "screenshot.png"; |
39 // Default file name for pdf. Can be overriden by "--print-to-pdf" switch. | 44 // Default file name for pdf. Can be overriden by "--print-to-pdf" switch. |
40 const char kDefaultPDFFileName[] = "output.pdf"; | 45 const char kDefaultPDFFileName[] = "output.pdf"; |
41 | 46 |
42 bool ParseWindowSize(std::string window_size, gfx::Size* parsed_window_size) { | 47 bool ParseWindowSize(std::string window_size, gfx::Size* parsed_window_size) { |
(...skipping 12 matching lines...) Expand all Loading... |
55 : browser_(nullptr), | 60 : browser_(nullptr), |
56 devtools_client_(HeadlessDevToolsClient::Create()), | 61 devtools_client_(HeadlessDevToolsClient::Create()), |
57 web_contents_(nullptr), | 62 web_contents_(nullptr), |
58 processed_page_ready_(false), | 63 processed_page_ready_(false), |
59 browser_context_(nullptr), | 64 browser_context_(nullptr), |
60 weak_factory_(this) {} | 65 weak_factory_(this) {} |
61 | 66 |
62 HeadlessShell::~HeadlessShell() {} | 67 HeadlessShell::~HeadlessShell() {} |
63 | 68 |
64 void HeadlessShell::OnStart(HeadlessBrowser* browser) { | 69 void HeadlessShell::OnStart(HeadlessBrowser* browser) { |
| 70 // TODO(dvallet): Consider making a Windows specific class to make specific |
| 71 // child builds clearer. |
| 72 #if !defined(CHROME_MULTIPLE_DLL_CHILD) |
65 browser_ = browser; | 73 browser_ = browser; |
66 | 74 |
67 HeadlessBrowserContext::Builder context_builder = | 75 HeadlessBrowserContext::Builder context_builder = |
68 browser_->CreateBrowserContextBuilder(); | 76 browser_->CreateBrowserContextBuilder(); |
69 // TODO(eseckler): These switches should also affect BrowserContexts that | 77 // TODO(eseckler): These switches should also affect BrowserContexts that |
70 // are created via DevTools later. | 78 // are created via DevTools later. |
71 DeterministicHttpProtocolHandler* http_handler; | 79 DeterministicHttpProtocolHandler* http_handler = nullptr; |
72 DeterministicHttpProtocolHandler* https_handler; | 80 DeterministicHttpProtocolHandler* https_handler = nullptr; |
73 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 81 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
74 switches::kDeterministicFetch)) { | 82 switches::kDeterministicFetch)) { |
75 deterministic_dispatcher_.reset( | 83 deterministic_dispatcher_.reset( |
76 new DeterministicDispatcher(browser_->BrowserIOThread())); | 84 new DeterministicDispatcher(browser_->BrowserIOThread())); |
77 | 85 |
78 ProtocolHandlerMap protocol_handlers; | 86 ProtocolHandlerMap protocol_handlers; |
79 protocol_handlers[url::kHttpScheme] = | 87 protocol_handlers[url::kHttpScheme] = |
80 base::MakeUnique<DeterministicHttpProtocolHandler>( | 88 base::MakeUnique<DeterministicHttpProtocolHandler>( |
81 deterministic_dispatcher_.get(), browser->BrowserIOThread()); | 89 deterministic_dispatcher_.get(), browser->BrowserIOThread()); |
82 http_handler = static_cast<DeterministicHttpProtocolHandler*>( | 90 http_handler = static_cast<DeterministicHttpProtocolHandler*>( |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
118 browser_->Shutdown(); | 126 browser_->Shutdown(); |
119 return; | 127 return; |
120 } | 128 } |
121 if (!web_contents_ && !RemoteDebuggingEnabled()) { | 129 if (!web_contents_ && !RemoteDebuggingEnabled()) { |
122 // TODO(jzfeng): Support observing multiple targets. | 130 // TODO(jzfeng): Support observing multiple targets. |
123 url_ = url; | 131 url_ = url; |
124 web_contents_ = web_contents; | 132 web_contents_ = web_contents; |
125 web_contents_->AddObserver(this); | 133 web_contents_->AddObserver(this); |
126 } | 134 } |
127 } | 135 } |
| 136 #endif // !defined(CHROME_MULTIPLE_DLL_CHILD) |
128 } | 137 } |
129 | 138 |
130 void HeadlessShell::Shutdown() { | 139 void HeadlessShell::Shutdown() { |
| 140 #if !defined(CHROME_MULTIPLE_DLL_CHILD) |
131 if (!web_contents_) | 141 if (!web_contents_) |
132 return; | 142 return; |
133 if (!RemoteDebuggingEnabled()) { | 143 if (!RemoteDebuggingEnabled()) { |
134 devtools_client_->GetEmulation()->GetExperimental()->RemoveObserver(this); | 144 devtools_client_->GetEmulation()->GetExperimental()->RemoveObserver(this); |
135 devtools_client_->GetInspector()->GetExperimental()->RemoveObserver(this); | 145 devtools_client_->GetInspector()->GetExperimental()->RemoveObserver(this); |
136 devtools_client_->GetPage()->GetExperimental()->RemoveObserver(this); | 146 devtools_client_->GetPage()->GetExperimental()->RemoveObserver(this); |
137 if (web_contents_->GetDevToolsTarget()) { | 147 if (web_contents_->GetDevToolsTarget()) { |
138 web_contents_->GetDevToolsTarget()->DetachClient(devtools_client_.get()); | 148 web_contents_->GetDevToolsTarget()->DetachClient(devtools_client_.get()); |
139 } | 149 } |
140 } | 150 } |
141 web_contents_->RemoveObserver(this); | 151 web_contents_->RemoveObserver(this); |
142 web_contents_ = nullptr; | 152 web_contents_ = nullptr; |
143 browser_context_->Close(); | 153 browser_context_->Close(); |
144 browser_->Shutdown(); | 154 browser_->Shutdown(); |
| 155 #endif // !defined(CHROME_MULTIPLE_DLL_CHILD) |
145 } | 156 } |
146 | 157 |
147 void HeadlessShell::DevToolsTargetReady() { | 158 void HeadlessShell::DevToolsTargetReady() { |
| 159 #if !defined(CHROME_MULTIPLE_DLL_CHILD) |
148 web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get()); | 160 web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get()); |
149 devtools_client_->GetInspector()->GetExperimental()->AddObserver(this); | 161 devtools_client_->GetInspector()->GetExperimental()->AddObserver(this); |
150 devtools_client_->GetPage()->GetExperimental()->AddObserver(this); | 162 devtools_client_->GetPage()->GetExperimental()->AddObserver(this); |
151 devtools_client_->GetPage()->Enable(); | 163 devtools_client_->GetPage()->Enable(); |
152 | 164 |
153 devtools_client_->GetEmulation()->GetExperimental()->AddObserver(this); | 165 devtools_client_->GetEmulation()->GetExperimental()->AddObserver(this); |
154 | 166 |
155 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 167 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
156 switches::kDeterministicFetch)) { | 168 switches::kDeterministicFetch)) { |
157 devtools_client_->GetPage()->GetExperimental()->SetControlNavigations( | 169 devtools_client_->GetPage()->GetExperimental()->SetControlNavigations( |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
209 int timeout_ms; | 221 int timeout_ms; |
210 CHECK(base::StringToInt(timeout_ms_ascii, &timeout_ms)) | 222 CHECK(base::StringToInt(timeout_ms_ascii, &timeout_ms)) |
211 << "Expected an integer value for --timeout="; | 223 << "Expected an integer value for --timeout="; |
212 browser_->BrowserMainThread()->PostDelayedTask( | 224 browser_->BrowserMainThread()->PostDelayedTask( |
213 FROM_HERE, | 225 FROM_HERE, |
214 base::Bind(&HeadlessShell::FetchTimeout, weak_factory_.GetWeakPtr()), | 226 base::Bind(&HeadlessShell::FetchTimeout, weak_factory_.GetWeakPtr()), |
215 base::TimeDelta::FromMilliseconds(timeout_ms)); | 227 base::TimeDelta::FromMilliseconds(timeout_ms)); |
216 } | 228 } |
217 | 229 |
218 // TODO(skyostil): Implement more features to demonstrate the devtools API. | 230 // TODO(skyostil): Implement more features to demonstrate the devtools API. |
| 231 #endif // !defined(CHROME_MULTIPLE_DLL_CHILD) |
219 } | 232 } |
220 | 233 |
221 void HeadlessShell::FetchTimeout() { | 234 void HeadlessShell::FetchTimeout() { |
222 LOG(INFO) << "Timeout."; | 235 LOG(INFO) << "Timeout."; |
223 devtools_client_->GetPage()->GetExperimental()->StopLoading( | 236 devtools_client_->GetPage()->GetExperimental()->StopLoading( |
224 page::StopLoadingParams::Builder().Build()); | 237 page::StopLoadingParams::Builder().Build()); |
225 } | 238 } |
226 | 239 |
227 void HeadlessShell::OnTargetCrashed( | 240 void HeadlessShell::OnTargetCrashed( |
228 const inspector::TargetCrashedParams& params) { | 241 const inspector::TargetCrashedParams& params) { |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
433 if (!file_proxy_->Write( | 446 if (!file_proxy_->Write( |
434 0, buf->data(), buf->size(), | 447 0, buf->data(), buf->size(), |
435 base::Bind(&HeadlessShell::OnFileWritten, weak_factory_.GetWeakPtr(), | 448 base::Bind(&HeadlessShell::OnFileWritten, weak_factory_.GetWeakPtr(), |
436 file_name, buf->size()))) { | 449 file_name, buf->size()))) { |
437 // Operation may have completed successfully or failed. | 450 // Operation may have completed successfully or failed. |
438 OnFileWritten(file_name, buf->size(), base::File::FILE_ERROR_FAILED, 0); | 451 OnFileWritten(file_name, buf->size(), base::File::FILE_ERROR_FAILED, 0); |
439 } | 452 } |
440 } | 453 } |
441 | 454 |
442 void HeadlessShell::OnFileWritten(const base::FilePath file_name, | 455 void HeadlessShell::OnFileWritten(const base::FilePath file_name, |
443 const int length, | 456 const size_t length, |
444 base::File::Error error_code, | 457 base::File::Error error_code, |
445 int write_result) { | 458 int write_result) { |
446 if (write_result < length) { | 459 if (write_result < static_cast<int>(length)) { |
447 // TODO(eseckler): Support recovering from partial writes. | 460 // TODO(eseckler): Support recovering from partial writes. |
448 LOG(ERROR) << "Writing to file " << file_name.value() | 461 LOG(ERROR) << "Writing to file " << file_name.value() |
449 << " was unsuccessful: " | 462 << " was unsuccessful: " |
450 << base::File::ErrorToString(error_code); | 463 << base::File::ErrorToString(error_code); |
451 } else { | 464 } else { |
452 LOG(INFO) << "Written to file " << file_name.value() << "."; | 465 LOG(INFO) << "Written to file " << file_name.value() << "."; |
453 } | 466 } |
454 if (!file_proxy_->Close(base::Bind(&HeadlessShell::OnFileClosed, | 467 if (!file_proxy_->Close(base::Bind(&HeadlessShell::OnFileClosed, |
455 weak_factory_.GetWeakPtr()))) { | 468 weak_factory_.GetWeakPtr()))) { |
456 // Operation could not be started. | 469 // Operation could not be started. |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
520 return false; | 533 return false; |
521 } | 534 } |
522 if (command_line.HasSwitch(switches::kVirtualTimeBudget)) { | 535 if (command_line.HasSwitch(switches::kVirtualTimeBudget)) { |
523 LOG(ERROR) << "Virtual time budget is disabled " | 536 LOG(ERROR) << "Virtual time budget is disabled " |
524 << "when remote debugging is enabled."; | 537 << "when remote debugging is enabled."; |
525 return false; | 538 return false; |
526 } | 539 } |
527 return true; | 540 return true; |
528 } | 541 } |
529 | 542 |
| 543 #if defined(OS_WIN) |
| 544 int HeadlessShellMain(HINSTANCE instance, |
| 545 sandbox::SandboxInterfaceInfo* sandbox_info) { |
| 546 base::CommandLine::Init(0, nullptr); |
| 547 RunChildProcessIfNeeded(instance, sandbox_info); |
| 548 HeadlessBrowser::Options::Builder builder(0, nullptr); |
| 549 builder.SetInstance(instance); |
| 550 builder.SetSandboxInfo(std::move(sandbox_info)); |
| 551 #else |
530 int HeadlessShellMain(int argc, const char** argv) { | 552 int HeadlessShellMain(int argc, const char** argv) { |
531 base::CommandLine::Init(argc, argv); | 553 base::CommandLine::Init(argc, argv); |
532 RunChildProcessIfNeeded(argc, argv); | 554 RunChildProcessIfNeeded(argc, argv); |
| 555 HeadlessBrowser::Options::Builder builder(argc, argv); |
| 556 #endif // defined(OS_WIN) |
533 HeadlessShell shell; | 557 HeadlessShell shell; |
534 HeadlessBrowser::Options::Builder builder(argc, argv); | |
535 | 558 |
536 const base::CommandLine& command_line( | 559 const base::CommandLine& command_line( |
537 *base::CommandLine::ForCurrentProcess()); | 560 *base::CommandLine::ForCurrentProcess()); |
538 if (!ValidateCommandLine(command_line)) | 561 if (!ValidateCommandLine(command_line)) |
539 return EXIT_FAILURE; | 562 return EXIT_FAILURE; |
540 | 563 |
541 if (command_line.HasSwitch(::switches::kEnableCrashReporter)) | 564 if (command_line.HasSwitch(switches::kEnableCrashReporter)) |
542 builder.SetCrashReporterEnabled(true); | 565 builder.SetCrashReporterEnabled(true); |
543 if (command_line.HasSwitch(switches::kCrashDumpsDir)) { | 566 if (command_line.HasSwitch(switches::kCrashDumpsDir)) { |
544 builder.SetCrashDumpsDir( | 567 builder.SetCrashDumpsDir( |
545 command_line.GetSwitchValuePath(switches::kCrashDumpsDir)); | 568 command_line.GetSwitchValuePath(switches::kCrashDumpsDir)); |
546 } | 569 } |
547 | 570 |
548 // Enable devtools if requested, either by specifying a port (and optional | 571 // Enable devtools if requested, either by specifying a port (and optional |
549 // address), or by specifying the fd of an already-open socket. | 572 // address), or by specifying the fd of an already-open socket. |
550 if (command_line.HasSwitch(::switches::kRemoteDebuggingPort)) { | 573 if (command_line.HasSwitch(::switches::kRemoteDebuggingPort)) { |
551 std::string address = kDevToolsHttpServerAddress; | 574 std::string address = kDevToolsHttpServerAddress; |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
632 std::string ua = command_line.GetSwitchValueASCII(switches::kUserAgent); | 655 std::string ua = command_line.GetSwitchValueASCII(switches::kUserAgent); |
633 if (net::HttpUtil::IsValidHeaderValue(ua)) | 656 if (net::HttpUtil::IsValidHeaderValue(ua)) |
634 builder.SetUserAgent(ua); | 657 builder.SetUserAgent(ua); |
635 } | 658 } |
636 | 659 |
637 return HeadlessBrowserMain( | 660 return HeadlessBrowserMain( |
638 builder.Build(), | 661 builder.Build(), |
639 base::Bind(&HeadlessShell::OnStart, base::Unretained(&shell))); | 662 base::Bind(&HeadlessShell::OnStart, base::Unretained(&shell))); |
640 } | 663 } |
641 | 664 |
| 665 int HeadlessShellMain(const content::ContentMainParams& params) { |
| 666 #if defined(OS_WIN) |
| 667 return HeadlessShellMain(params.instance, params.sandbox_info); |
| 668 #else |
| 669 return HeadlessShellMain(params.argc, params.argv); |
| 670 #endif |
| 671 } |
| 672 |
642 } // namespace headless | 673 } // namespace headless |
OLD | NEW |