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 #if !defined(CHROME_MULTIPLE_DLL_CHILD) | |
alex clarke (OOO till 29th)
2017/05/12 11:31:28
It's kind of a shame about all the #ifs although t
dvallet
2017/05/12 21:12:03
That's a good idea Alex!
I'll look into it and wi
| |
65 browser_ = browser; | 71 browser_ = browser; |
66 | 72 |
67 HeadlessBrowserContext::Builder context_builder = | 73 HeadlessBrowserContext::Builder context_builder = |
68 browser_->CreateBrowserContextBuilder(); | 74 browser_->CreateBrowserContextBuilder(); |
69 // TODO(eseckler): These switches should also affect BrowserContexts that | 75 // TODO(eseckler): These switches should also affect BrowserContexts that |
70 // are created via DevTools later. | 76 // are created via DevTools later. |
71 DeterministicHttpProtocolHandler* http_handler; | 77 DeterministicHttpProtocolHandler* http_handler = nullptr; |
72 DeterministicHttpProtocolHandler* https_handler; | 78 DeterministicHttpProtocolHandler* https_handler = nullptr; |
73 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 79 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
74 switches::kDeterministicFetch)) { | 80 switches::kDeterministicFetch)) { |
75 deterministic_dispatcher_.reset( | 81 deterministic_dispatcher_.reset( |
76 new DeterministicDispatcher(browser_->BrowserIOThread())); | 82 new DeterministicDispatcher(browser_->BrowserIOThread())); |
77 | 83 |
78 ProtocolHandlerMap protocol_handlers; | 84 ProtocolHandlerMap protocol_handlers; |
79 protocol_handlers[url::kHttpScheme] = | 85 protocol_handlers[url::kHttpScheme] = |
80 base::MakeUnique<DeterministicHttpProtocolHandler>( | 86 base::MakeUnique<DeterministicHttpProtocolHandler>( |
81 deterministic_dispatcher_.get(), browser->BrowserIOThread()); | 87 deterministic_dispatcher_.get(), browser->BrowserIOThread()); |
82 http_handler = static_cast<DeterministicHttpProtocolHandler*>( | 88 http_handler = static_cast<DeterministicHttpProtocolHandler*>( |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
118 browser_->Shutdown(); | 124 browser_->Shutdown(); |
119 return; | 125 return; |
120 } | 126 } |
121 if (!web_contents_ && !RemoteDebuggingEnabled()) { | 127 if (!web_contents_ && !RemoteDebuggingEnabled()) { |
122 // TODO(jzfeng): Support observing multiple targets. | 128 // TODO(jzfeng): Support observing multiple targets. |
123 url_ = url; | 129 url_ = url; |
124 web_contents_ = web_contents; | 130 web_contents_ = web_contents; |
125 web_contents_->AddObserver(this); | 131 web_contents_->AddObserver(this); |
126 } | 132 } |
127 } | 133 } |
134 #endif // !defined(CHROME_MULTIPLE_DLL_CHILD) | |
128 } | 135 } |
129 | 136 |
130 void HeadlessShell::Shutdown() { | 137 void HeadlessShell::Shutdown() { |
138 #if !defined(CHROME_MULTIPLE_DLL_CHILD) | |
131 if (!web_contents_) | 139 if (!web_contents_) |
132 return; | 140 return; |
133 if (!RemoteDebuggingEnabled()) { | 141 if (!RemoteDebuggingEnabled()) { |
134 devtools_client_->GetEmulation()->GetExperimental()->RemoveObserver(this); | 142 devtools_client_->GetEmulation()->GetExperimental()->RemoveObserver(this); |
135 devtools_client_->GetInspector()->GetExperimental()->RemoveObserver(this); | 143 devtools_client_->GetInspector()->GetExperimental()->RemoveObserver(this); |
136 devtools_client_->GetPage()->GetExperimental()->RemoveObserver(this); | 144 devtools_client_->GetPage()->GetExperimental()->RemoveObserver(this); |
137 if (web_contents_->GetDevToolsTarget()) { | 145 if (web_contents_->GetDevToolsTarget()) { |
138 web_contents_->GetDevToolsTarget()->DetachClient(devtools_client_.get()); | 146 web_contents_->GetDevToolsTarget()->DetachClient(devtools_client_.get()); |
139 } | 147 } |
140 } | 148 } |
141 web_contents_->RemoveObserver(this); | 149 web_contents_->RemoveObserver(this); |
142 web_contents_ = nullptr; | 150 web_contents_ = nullptr; |
143 browser_context_->Close(); | 151 browser_context_->Close(); |
144 browser_->Shutdown(); | 152 browser_->Shutdown(); |
153 #endif // !defined(CHROME_MULTIPLE_DLL_CHILD) | |
145 } | 154 } |
146 | 155 |
147 void HeadlessShell::DevToolsTargetReady() { | 156 void HeadlessShell::DevToolsTargetReady() { |
157 #if !defined(CHROME_MULTIPLE_DLL_CHILD) | |
148 web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get()); | 158 web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get()); |
149 devtools_client_->GetInspector()->GetExperimental()->AddObserver(this); | 159 devtools_client_->GetInspector()->GetExperimental()->AddObserver(this); |
150 devtools_client_->GetPage()->GetExperimental()->AddObserver(this); | 160 devtools_client_->GetPage()->GetExperimental()->AddObserver(this); |
151 devtools_client_->GetPage()->Enable(); | 161 devtools_client_->GetPage()->Enable(); |
152 | 162 |
153 devtools_client_->GetEmulation()->GetExperimental()->AddObserver(this); | 163 devtools_client_->GetEmulation()->GetExperimental()->AddObserver(this); |
154 | 164 |
155 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 165 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
156 switches::kDeterministicFetch)) { | 166 switches::kDeterministicFetch)) { |
157 devtools_client_->GetPage()->GetExperimental()->SetControlNavigations( | 167 devtools_client_->GetPage()->GetExperimental()->SetControlNavigations( |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
209 int timeout_ms; | 219 int timeout_ms; |
210 CHECK(base::StringToInt(timeout_ms_ascii, &timeout_ms)) | 220 CHECK(base::StringToInt(timeout_ms_ascii, &timeout_ms)) |
211 << "Expected an integer value for --timeout="; | 221 << "Expected an integer value for --timeout="; |
212 browser_->BrowserMainThread()->PostDelayedTask( | 222 browser_->BrowserMainThread()->PostDelayedTask( |
213 FROM_HERE, | 223 FROM_HERE, |
214 base::Bind(&HeadlessShell::FetchTimeout, weak_factory_.GetWeakPtr()), | 224 base::Bind(&HeadlessShell::FetchTimeout, weak_factory_.GetWeakPtr()), |
215 base::TimeDelta::FromMilliseconds(timeout_ms)); | 225 base::TimeDelta::FromMilliseconds(timeout_ms)); |
216 } | 226 } |
217 | 227 |
218 // TODO(skyostil): Implement more features to demonstrate the devtools API. | 228 // TODO(skyostil): Implement more features to demonstrate the devtools API. |
229 #endif // !defined(CHROME_MULTIPLE_DLL_CHILD) | |
219 } | 230 } |
220 | 231 |
221 void HeadlessShell::FetchTimeout() { | 232 void HeadlessShell::FetchTimeout() { |
222 LOG(INFO) << "Timeout."; | 233 LOG(INFO) << "Timeout."; |
223 devtools_client_->GetPage()->GetExperimental()->StopLoading( | 234 devtools_client_->GetPage()->GetExperimental()->StopLoading( |
224 page::StopLoadingParams::Builder().Build()); | 235 page::StopLoadingParams::Builder().Build()); |
225 } | 236 } |
226 | 237 |
227 void HeadlessShell::OnTargetCrashed( | 238 void HeadlessShell::OnTargetCrashed( |
228 const inspector::TargetCrashedParams& params) { | 239 const inspector::TargetCrashedParams& params) { |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
433 if (!file_proxy_->Write( | 444 if (!file_proxy_->Write( |
434 0, buf->data(), buf->size(), | 445 0, buf->data(), buf->size(), |
435 base::Bind(&HeadlessShell::OnFileWritten, weak_factory_.GetWeakPtr(), | 446 base::Bind(&HeadlessShell::OnFileWritten, weak_factory_.GetWeakPtr(), |
436 file_name, buf->size()))) { | 447 file_name, buf->size()))) { |
437 // Operation may have completed successfully or failed. | 448 // Operation may have completed successfully or failed. |
438 OnFileWritten(file_name, buf->size(), base::File::FILE_ERROR_FAILED, 0); | 449 OnFileWritten(file_name, buf->size(), base::File::FILE_ERROR_FAILED, 0); |
439 } | 450 } |
440 } | 451 } |
441 | 452 |
442 void HeadlessShell::OnFileWritten(const base::FilePath file_name, | 453 void HeadlessShell::OnFileWritten(const base::FilePath file_name, |
443 const int length, | 454 const size_t length, |
444 base::File::Error error_code, | 455 base::File::Error error_code, |
445 int write_result) { | 456 int write_result) { |
446 if (write_result < length) { | 457 if (write_result < static_cast<int>(length)) { |
447 // TODO(eseckler): Support recovering from partial writes. | 458 // TODO(eseckler): Support recovering from partial writes. |
448 LOG(ERROR) << "Writing to file " << file_name.value() | 459 LOG(ERROR) << "Writing to file " << file_name.value() |
449 << " was unsuccessful: " | 460 << " was unsuccessful: " |
450 << base::File::ErrorToString(error_code); | 461 << base::File::ErrorToString(error_code); |
451 } else { | 462 } else { |
452 LOG(INFO) << "Written to file " << file_name.value() << "."; | 463 LOG(INFO) << "Written to file " << file_name.value() << "."; |
453 } | 464 } |
454 if (!file_proxy_->Close(base::Bind(&HeadlessShell::OnFileClosed, | 465 if (!file_proxy_->Close(base::Bind(&HeadlessShell::OnFileClosed, |
455 weak_factory_.GetWeakPtr()))) { | 466 weak_factory_.GetWeakPtr()))) { |
456 // Operation could not be started. | 467 // Operation could not be started. |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
520 return false; | 531 return false; |
521 } | 532 } |
522 if (command_line.HasSwitch(switches::kVirtualTimeBudget)) { | 533 if (command_line.HasSwitch(switches::kVirtualTimeBudget)) { |
523 LOG(ERROR) << "Virtual time budget is disabled " | 534 LOG(ERROR) << "Virtual time budget is disabled " |
524 << "when remote debugging is enabled."; | 535 << "when remote debugging is enabled."; |
525 return false; | 536 return false; |
526 } | 537 } |
527 return true; | 538 return true; |
528 } | 539 } |
529 | 540 |
541 #if defined(OS_WIN) | |
542 int HeadlessShellMain(HINSTANCE instance, | |
543 sandbox::SandboxInterfaceInfo* sandbox_info) { | |
544 base::CommandLine::Init(0, nullptr); | |
545 RunChildProcessIfNeeded(instance, sandbox_info); | |
546 HeadlessBrowser::Options::Builder builder(0, nullptr); | |
547 builder.SetInstance(instance); | |
548 builder.SetSandboxInfo(std::move(sandbox_info)); | |
549 #else | |
530 int HeadlessShellMain(int argc, const char** argv) { | 550 int HeadlessShellMain(int argc, const char** argv) { |
531 base::CommandLine::Init(argc, argv); | 551 base::CommandLine::Init(argc, argv); |
532 RunChildProcessIfNeeded(argc, argv); | 552 RunChildProcessIfNeeded(argc, argv); |
553 HeadlessBrowser::Options::Builder builder(argc, argv); | |
554 #endif // defined(OS_WIN) | |
533 HeadlessShell shell; | 555 HeadlessShell shell; |
534 HeadlessBrowser::Options::Builder builder(argc, argv); | |
535 | 556 |
536 const base::CommandLine& command_line( | 557 const base::CommandLine& command_line( |
537 *base::CommandLine::ForCurrentProcess()); | 558 *base::CommandLine::ForCurrentProcess()); |
538 if (!ValidateCommandLine(command_line)) | 559 if (!ValidateCommandLine(command_line)) |
539 return EXIT_FAILURE; | 560 return EXIT_FAILURE; |
540 | 561 |
541 if (command_line.HasSwitch(::switches::kEnableCrashReporter)) | 562 if (command_line.HasSwitch(switches::kEnableCrashReporter)) |
542 builder.SetCrashReporterEnabled(true); | 563 builder.SetCrashReporterEnabled(true); |
543 if (command_line.HasSwitch(switches::kCrashDumpsDir)) { | 564 if (command_line.HasSwitch(switches::kCrashDumpsDir)) { |
544 builder.SetCrashDumpsDir( | 565 builder.SetCrashDumpsDir( |
545 command_line.GetSwitchValuePath(switches::kCrashDumpsDir)); | 566 command_line.GetSwitchValuePath(switches::kCrashDumpsDir)); |
546 } | 567 } |
547 | 568 |
548 // Enable devtools if requested, either by specifying a port (and optional | 569 // Enable devtools if requested, either by specifying a port (and optional |
549 // address), or by specifying the fd of an already-open socket. | 570 // address), or by specifying the fd of an already-open socket. |
550 if (command_line.HasSwitch(::switches::kRemoteDebuggingPort)) { | 571 if (command_line.HasSwitch(::switches::kRemoteDebuggingPort)) { |
551 std::string address = kDevToolsHttpServerAddress; | 572 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); | 653 std::string ua = command_line.GetSwitchValueASCII(switches::kUserAgent); |
633 if (net::HttpUtil::IsValidHeaderValue(ua)) | 654 if (net::HttpUtil::IsValidHeaderValue(ua)) |
634 builder.SetUserAgent(ua); | 655 builder.SetUserAgent(ua); |
635 } | 656 } |
636 | 657 |
637 return HeadlessBrowserMain( | 658 return HeadlessBrowserMain( |
638 builder.Build(), | 659 builder.Build(), |
639 base::Bind(&HeadlessShell::OnStart, base::Unretained(&shell))); | 660 base::Bind(&HeadlessShell::OnStart, base::Unretained(&shell))); |
640 } | 661 } |
641 | 662 |
663 int HeadlessShellMain(const content::ContentMainParams& params) { | |
664 #if defined(OS_WIN) | |
665 return HeadlessShellMain(params.instance, params.sandbox_info); | |
666 #else | |
667 return HeadlessShellMain(params.argc, params.argv); | |
668 #endif | |
669 } | |
670 | |
642 } // namespace headless | 671 } // namespace headless |
OLD | NEW |