Chromium Code Reviews| 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 <iostream> | 5 #include <iostream> |
| 6 #include <memory> | 6 #include <memory> |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/base64.h" | 9 #include "base/base64.h" |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/callback.h" | 11 #include "base/callback.h" |
| 12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 13 #include "base/files/file_path.h" | 13 #include "base/files/file_path.h" |
| 14 #include "base/json/json_writer.h" | 14 #include "base/json/json_writer.h" |
| 15 #include "base/location.h" | 15 #include "base/location.h" |
| 16 #include "base/memory/ref_counted.h" | 16 #include "base/memory/ref_counted.h" |
| 17 #include "base/numerics/safe_conversions.h" | 17 #include "base/numerics/safe_conversions.h" |
| 18 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" |
| 19 #include "content/public/common/content_switches.h" | 19 #include "content/public/common/content_switches.h" |
| 20 #include "headless/app/headless_shell_switches.h" | 20 #include "headless/app/headless_shell_switches.h" |
| 21 #include "headless/public/devtools/domains/emulation.h" | 21 #include "headless/public/devtools/domains/emulation.h" |
| 22 #include "headless/public/devtools/domains/inspector.h" | |
| 22 #include "headless/public/devtools/domains/page.h" | 23 #include "headless/public/devtools/domains/page.h" |
| 23 #include "headless/public/devtools/domains/runtime.h" | 24 #include "headless/public/devtools/domains/runtime.h" |
| 24 #include "headless/public/headless_browser.h" | 25 #include "headless/public/headless_browser.h" |
| 25 #include "headless/public/headless_devtools_client.h" | 26 #include "headless/public/headless_devtools_client.h" |
| 26 #include "headless/public/headless_devtools_target.h" | 27 #include "headless/public/headless_devtools_target.h" |
| 27 #include "headless/public/headless_web_contents.h" | 28 #include "headless/public/headless_web_contents.h" |
| 28 #include "headless/public/util/deterministic_dispatcher.h" | 29 #include "headless/public/util/deterministic_dispatcher.h" |
| 29 #include "headless/public/util/deterministic_http_protocol_handler.h" | 30 #include "headless/public/util/deterministic_http_protocol_handler.h" |
| 30 #include "net/base/file_stream.h" | 31 #include "net/base/file_stream.h" |
| 31 #include "net/base/io_buffer.h" | 32 #include "net/base/io_buffer.h" |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 48 parsed_window_size->set_height(height); | 49 parsed_window_size->set_height(height); |
| 49 return true; | 50 return true; |
| 50 } | 51 } |
| 51 return false; | 52 return false; |
| 52 } | 53 } |
| 53 } // namespace | 54 } // namespace |
| 54 | 55 |
| 55 // An application which implements a simple headless browser. | 56 // An application which implements a simple headless browser. |
| 56 class HeadlessShell : public HeadlessWebContents::Observer, | 57 class HeadlessShell : public HeadlessWebContents::Observer, |
| 57 emulation::ExperimentalObserver, | 58 emulation::ExperimentalObserver, |
| 59 inspector::ExperimentalObserver, | |
| 58 page::Observer { | 60 page::Observer { |
| 59 public: | 61 public: |
| 60 HeadlessShell() | 62 HeadlessShell() |
| 61 : browser_(nullptr), | 63 : browser_(nullptr), |
| 62 devtools_client_(HeadlessDevToolsClient::Create()), | 64 devtools_client_(HeadlessDevToolsClient::Create()), |
| 63 web_contents_(nullptr), | 65 web_contents_(nullptr), |
| 64 processed_page_ready_(false), | 66 processed_page_ready_(false), |
| 65 browser_context_(nullptr) {} | 67 browser_context_(nullptr) {} |
| 66 ~HeadlessShell() override {} | 68 ~HeadlessShell() override {} |
| 67 | 69 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 111 return; | 113 return; |
| 112 } | 114 } |
| 113 web_contents_->AddObserver(this); | 115 web_contents_->AddObserver(this); |
| 114 } | 116 } |
| 115 | 117 |
| 116 void Shutdown() { | 118 void Shutdown() { |
| 117 if (!web_contents_) | 119 if (!web_contents_) |
| 118 return; | 120 return; |
| 119 if (!RemoteDebuggingEnabled()) { | 121 if (!RemoteDebuggingEnabled()) { |
| 120 devtools_client_->GetEmulation()->GetExperimental()->RemoveObserver(this); | 122 devtools_client_->GetEmulation()->GetExperimental()->RemoveObserver(this); |
| 123 devtools_client_->GetInspector()->GetExperimental()->RemoveObserver(this); | |
| 121 devtools_client_->GetPage()->RemoveObserver(this); | 124 devtools_client_->GetPage()->RemoveObserver(this); |
| 122 if (web_contents_->GetDevToolsTarget()) { | 125 if (web_contents_->GetDevToolsTarget()) { |
| 123 web_contents_->GetDevToolsTarget()->DetachClient( | 126 web_contents_->GetDevToolsTarget()->DetachClient( |
| 124 devtools_client_.get()); | 127 devtools_client_.get()); |
| 125 } | 128 } |
| 126 } | 129 } |
| 127 web_contents_->RemoveObserver(this); | 130 web_contents_->RemoveObserver(this); |
| 128 web_contents_ = nullptr; | 131 web_contents_ = nullptr; |
| 129 browser_context_->Close(); | 132 browser_context_->Close(); |
| 130 browser_->Shutdown(); | 133 browser_->Shutdown(); |
| 131 } | 134 } |
| 132 | 135 |
| 133 // HeadlessWebContents::Observer implementation: | 136 // HeadlessWebContents::Observer implementation: |
| 134 void DevToolsTargetReady() override { | 137 void DevToolsTargetReady() override { |
| 135 if (RemoteDebuggingEnabled()) | 138 if (RemoteDebuggingEnabled()) |
| 136 return; | 139 return; |
| 137 web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get()); | 140 web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get()); |
| 141 devtools_client_->GetInspector()->GetExperimental()->AddObserver(this); | |
| 138 devtools_client_->GetPage()->AddObserver(this); | 142 devtools_client_->GetPage()->AddObserver(this); |
| 139 devtools_client_->GetPage()->Enable(); | 143 devtools_client_->GetPage()->Enable(); |
| 140 // Check if the document had already finished loading by the time we | 144 // Check if the document had already finished loading by the time we |
| 141 // attached. | 145 // attached. |
| 142 | 146 |
| 143 devtools_client_->GetEmulation()->GetExperimental()->AddObserver(this); | 147 devtools_client_->GetEmulation()->GetExperimental()->AddObserver(this); |
| 144 | 148 |
| 145 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 149 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 146 switches::kVirtualTimeBudget)) { | 150 switches::kVirtualTimeBudget)) { |
| 147 std::string budget_ms_ascii = | 151 std::string budget_ms_ascii = |
| 148 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | 152 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| 149 switches::kVirtualTimeBudget); | 153 switches::kVirtualTimeBudget); |
| 150 int budget_ms; | 154 int budget_ms; |
| 151 CHECK(base::StringToInt(budget_ms_ascii, &budget_ms)) | 155 CHECK(base::StringToInt(budget_ms_ascii, &budget_ms)) |
| 152 << "Expected an integer value for --virtual-time-budget="; | 156 << "Expected an integer value for --virtual-time-budget="; |
| 153 devtools_client_->GetEmulation()->GetExperimental()->SetVirtualTimePolicy( | 157 devtools_client_->GetEmulation()->GetExperimental()->SetVirtualTimePolicy( |
| 154 emulation::SetVirtualTimePolicyParams::Builder() | 158 emulation::SetVirtualTimePolicyParams::Builder() |
| 155 .SetPolicy(emulation::VirtualTimePolicy:: | 159 .SetPolicy(emulation::VirtualTimePolicy:: |
| 156 PAUSE_IF_NETWORK_FETCHES_PENDING) | 160 PAUSE_IF_NETWORK_FETCHES_PENDING) |
| 157 .SetBudget(budget_ms) | 161 .SetBudget(budget_ms) |
| 158 .Build()); | 162 .Build()); |
| 159 } else { | 163 } else { |
| 160 PollReadyState(); | 164 PollReadyState(); |
| 161 } | 165 } |
| 162 // TODO(skyostil): Implement more features to demonstrate the devtools API. | 166 // TODO(skyostil): Implement more features to demonstrate the devtools API. |
| 163 } | 167 } |
| 164 | 168 |
| 165 void RenderProcessExited(base::TerminationStatus status, | 169 void OnTargetCrashed(const inspector::TargetCrashedParams& params) override { |
| 166 int exit_code) override { | |
| 167 if (status == base::TERMINATION_STATUS_NORMAL_TERMINATION) | |
| 168 return; | |
| 169 | |
| 170 LOG(ERROR) << "Abnormal renderer termination."; | 170 LOG(ERROR) << "Abnormal renderer termination."; |
| 171 Shutdown(); | 171 Shutdown(); |
|
Sami
2016/11/21 14:59:28
Should we remove this call to Shutdown() too (coul
alex clarke (OOO till 29th)
2016/11/22 10:48:55
Do people do that?
tearing it down
Sami
2016/11/22 11:23:11
Yeah, I would expect the NodeJS module to be used
alex clarke (OOO till 29th)
2016/11/22 15:30:58
Note due to the way DevToolsTargetReady is written
| |
| 172 } | 172 } |
| 173 | 173 |
| 174 void PollReadyState() { | 174 void PollReadyState() { |
| 175 // We need to check the current location in addition to the ready state to | 175 // We need to check the current location in addition to the ready state to |
| 176 // be sure the expected page is ready. | 176 // be sure the expected page is ready. |
| 177 devtools_client_->GetRuntime()->Evaluate( | 177 devtools_client_->GetRuntime()->Evaluate( |
| 178 "document.readyState + ' ' + document.location.href", | 178 "document.readyState + ' ' + document.location.href", |
| 179 base::Bind(&HeadlessShell::OnReadyState, base::Unretained(this))); | 179 base::Bind(&HeadlessShell::OnReadyState, base::Unretained(this))); |
| 180 } | 180 } |
| 181 | 181 |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 441 } | 441 } |
| 442 builder.SetWindowSize(parsed_window_size); | 442 builder.SetWindowSize(parsed_window_size); |
| 443 } | 443 } |
| 444 | 444 |
| 445 return HeadlessBrowserMain( | 445 return HeadlessBrowserMain( |
| 446 builder.Build(), | 446 builder.Build(), |
| 447 base::Bind(&HeadlessShell::OnStart, base::Unretained(&shell))); | 447 base::Bind(&HeadlessShell::OnStart, base::Unretained(&shell))); |
| 448 } | 448 } |
| 449 | 449 |
| 450 } // namespace headless | 450 } // namespace headless |
| OLD | NEW |