Chromium Code Reviews| Index: headless/app/headless_shell.cc |
| diff --git a/headless/app/headless_shell.cc b/headless/app/headless_shell.cc |
| index 942fb9bbad7084131d5f94af51c8bdb28cc6e313..f103c3fc172f62af7e8ad796b48447b3b046de3a 100644 |
| --- a/headless/app/headless_shell.cc |
| +++ b/headless/app/headless_shell.cc |
| @@ -29,6 +29,7 @@ |
| #include "headless/public/headless_web_contents.h" |
| #include "headless/public/util/deterministic_dispatcher.h" |
| #include "headless/public/util/deterministic_http_protocol_handler.h" |
| +#include "headless/public/util/navigation_request.h" |
| #include "net/base/file_stream.h" |
| #include "net/base/io_buffer.h" |
| #include "net/base/ip_address.h" |
| @@ -36,6 +37,8 @@ |
| #include "ui/gfx/geometry/size.h" |
| namespace headless { |
| +class HeadlessShell; |
| + |
| namespace { |
| // Address where to listen to incoming DevTools connections. |
| const char kDevToolsHttpServerAddress[] = "127.0.0.1"; |
| @@ -54,11 +57,37 @@ bool ParseWindowSize(std::string window_size, gfx::Size* parsed_window_size) { |
| } |
| } // namespace |
| +// Used in deterministic mode to make sure navigations and resource requests |
| +// complete in the order requested. |
| +class SimpleNavigationRequest : public NavigationRequest { |
|
Sami
2017/02/09 14:05:11
s/Simple/Shell/? Not sure what a complex navigatio
alex clarke (OOO till 29th)
2017/02/09 15:08:32
Done.
|
| + public: |
| + SimpleNavigationRequest(base::WeakPtr<HeadlessShell> headless_shell, |
| + const page::NavigationRequestedParams& params) |
| + : headless_shell_(headless_shell), |
| + navigation_id_(params.GetNavigationId()) {} |
| + |
| + ~SimpleNavigationRequest() override {} |
| + |
| + void StartProcessing(base::Closure done_callback) override; |
| + |
| + // Note the navigation likely isn't done when this is called, however we |
| + // expect it will have been committed and the initial resource load requested. |
| + static void ProcessNavigationResult( |
| + base::Closure done_callback, |
| + std::unique_ptr<page::ProcessNavigationResult>) { |
| + done_callback.Run(); |
| + } |
| + |
| + private: |
| + base::WeakPtr<HeadlessShell> headless_shell_; |
| + int navigation_id_; |
| +}; |
| + |
| // An application which implements a simple headless browser. |
| class HeadlessShell : public HeadlessWebContents::Observer, |
| emulation::ExperimentalObserver, |
| inspector::ExperimentalObserver, |
| - page::Observer { |
| + page::ExperimentalObserver { |
| public: |
| HeadlessShell() |
| : browser_(nullptr), |
| @@ -126,7 +155,7 @@ class HeadlessShell : public HeadlessWebContents::Observer, |
| if (!RemoteDebuggingEnabled()) { |
| devtools_client_->GetEmulation()->GetExperimental()->RemoveObserver(this); |
| devtools_client_->GetInspector()->GetExperimental()->RemoveObserver(this); |
| - devtools_client_->GetPage()->RemoveObserver(this); |
| + devtools_client_->GetPage()->GetExperimental()->RemoveObserver(this); |
| if (web_contents_->GetDevToolsTarget()) { |
| web_contents_->GetDevToolsTarget()->DetachClient( |
| devtools_client_.get()); |
| @@ -142,7 +171,7 @@ class HeadlessShell : public HeadlessWebContents::Observer, |
| void DevToolsTargetReady() override { |
| web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get()); |
| devtools_client_->GetInspector()->GetExperimental()->AddObserver(this); |
| - devtools_client_->GetPage()->AddObserver(this); |
| + devtools_client_->GetPage()->GetExperimental()->AddObserver(this); |
| devtools_client_->GetPage()->Enable(); |
| // Check if the document had already finished loading by the time we |
| // attached. |
| @@ -150,6 +179,14 @@ class HeadlessShell : public HeadlessWebContents::Observer, |
| devtools_client_->GetEmulation()->GetExperimental()->AddObserver(this); |
| if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kDeterministicFetch)) { |
| + devtools_client_->GetPage()->GetExperimental()->SetControlNavigations( |
| + headless::page::SetControlNavigationsParams::Builder() |
| + .SetEnabled(true) |
| + .Build()); |
| + } |
| + |
| + if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kVirtualTimeBudget)) { |
| std::string budget_ms_ascii = |
| base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| @@ -235,6 +272,13 @@ class HeadlessShell : public HeadlessWebContents::Observer, |
| OnPageReady(); |
| } |
| + void OnNavigationRequested( |
| + const headless::page::NavigationRequestedParams& params) override { |
| + deterministic_dispatcher_->NavigationRequested( |
| + base::MakeUnique<SimpleNavigationRequest>(weak_factory_.GetWeakPtr(), |
| + params)); |
| + } |
| + |
| void OnPageReady() { |
| if (processed_page_ready_) |
| return; |
| @@ -386,6 +430,10 @@ class HeadlessShell : public HeadlessWebContents::Observer, |
| return command_line.HasSwitch(switches::kRemoteDebuggingPort); |
| } |
| + HeadlessDevToolsClient* devtools_client() const { |
| + return devtools_client_.get(); |
| + } |
| + |
| private: |
| GURL url_; |
| HeadlessBrowser* browser_; // Not owned. |
| @@ -400,6 +448,23 @@ class HeadlessShell : public HeadlessWebContents::Observer, |
| DISALLOW_COPY_AND_ASSIGN(HeadlessShell); |
| }; |
| +void SimpleNavigationRequest::StartProcessing(base::Closure done_callback) { |
| + if (!headless_shell_) |
| + return; |
| + |
| + // Allow the navigation to proceed. |
| + headless_shell_->devtools_client() |
| + ->GetPage() |
| + ->GetExperimental() |
| + ->ProcessNavigation( |
| + headless::page::ProcessNavigationParams::Builder() |
| + .SetNavigationId(navigation_id_) |
| + .SetResponse(headless::page::NavigationResponse::PROCEED) |
| + .Build(), |
| + base::Bind(&SimpleNavigationRequest::ProcessNavigationResult, |
| + done_callback)); |
| +} |
| + |
| bool ValidateCommandLine(const base::CommandLine& command_line) { |
| if (!command_line.HasSwitch(switches::kRemoteDebuggingPort)) { |
| if (command_line.GetArgs().size() <= 1) |