Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(264)

Side by Side Diff: headless/app/headless_shell.cc

Issue 2687083002: Headless: make URLRequestDispatcher aware of navigations (Closed)
Patch Set: Responding to feedback. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « headless/BUILD.gn ('k') | headless/public/util/deterministic_dispatcher.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 8
9 #include "base/base64.h" 9 #include "base/base64.h"
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 11 matching lines...) Expand all
22 #include "headless/public/devtools/domains/emulation.h" 22 #include "headless/public/devtools/domains/emulation.h"
23 #include "headless/public/devtools/domains/inspector.h" 23 #include "headless/public/devtools/domains/inspector.h"
24 #include "headless/public/devtools/domains/page.h" 24 #include "headless/public/devtools/domains/page.h"
25 #include "headless/public/devtools/domains/runtime.h" 25 #include "headless/public/devtools/domains/runtime.h"
26 #include "headless/public/headless_browser.h" 26 #include "headless/public/headless_browser.h"
27 #include "headless/public/headless_devtools_client.h" 27 #include "headless/public/headless_devtools_client.h"
28 #include "headless/public/headless_devtools_target.h" 28 #include "headless/public/headless_devtools_target.h"
29 #include "headless/public/headless_web_contents.h" 29 #include "headless/public/headless_web_contents.h"
30 #include "headless/public/util/deterministic_dispatcher.h" 30 #include "headless/public/util/deterministic_dispatcher.h"
31 #include "headless/public/util/deterministic_http_protocol_handler.h" 31 #include "headless/public/util/deterministic_http_protocol_handler.h"
32 #include "headless/public/util/navigation_request.h"
32 #include "net/base/file_stream.h" 33 #include "net/base/file_stream.h"
33 #include "net/base/io_buffer.h" 34 #include "net/base/io_buffer.h"
34 #include "net/base/ip_address.h" 35 #include "net/base/ip_address.h"
35 #include "net/base/net_errors.h" 36 #include "net/base/net_errors.h"
36 #include "ui/gfx/geometry/size.h" 37 #include "ui/gfx/geometry/size.h"
37 38
38 namespace headless { 39 namespace headless {
40 class HeadlessShell;
41
39 namespace { 42 namespace {
40 // Address where to listen to incoming DevTools connections. 43 // Address where to listen to incoming DevTools connections.
41 const char kDevToolsHttpServerAddress[] = "127.0.0.1"; 44 const char kDevToolsHttpServerAddress[] = "127.0.0.1";
42 // Default file name for screenshot. Can be overriden by "--screenshot" switch. 45 // Default file name for screenshot. Can be overriden by "--screenshot" switch.
43 const char kDefaultScreenshotFileName[] = "screenshot.png"; 46 const char kDefaultScreenshotFileName[] = "screenshot.png";
44 47
45 bool ParseWindowSize(std::string window_size, gfx::Size* parsed_window_size) { 48 bool ParseWindowSize(std::string window_size, gfx::Size* parsed_window_size) {
46 int width, height = 0; 49 int width, height = 0;
47 if (sscanf(window_size.c_str(), "%d%*[x,]%d", &width, &height) >= 2 && 50 if (sscanf(window_size.c_str(), "%d%*[x,]%d", &width, &height) >= 2 &&
48 width >= 0 && height >= 0) { 51 width >= 0 && height >= 0) {
49 parsed_window_size->set_width(width); 52 parsed_window_size->set_width(width);
50 parsed_window_size->set_height(height); 53 parsed_window_size->set_height(height);
51 return true; 54 return true;
52 } 55 }
53 return false; 56 return false;
54 } 57 }
55 } // namespace 58 } // namespace
56 59
60 // Used in deterministic mode to make sure navigations and resource requests
61 // complete in the order requested.
62 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.
63 public:
64 SimpleNavigationRequest(base::WeakPtr<HeadlessShell> headless_shell,
65 const page::NavigationRequestedParams& params)
66 : headless_shell_(headless_shell),
67 navigation_id_(params.GetNavigationId()) {}
68
69 ~SimpleNavigationRequest() override {}
70
71 void StartProcessing(base::Closure done_callback) override;
72
73 // Note the navigation likely isn't done when this is called, however we
74 // expect it will have been committed and the initial resource load requested.
75 static void ProcessNavigationResult(
76 base::Closure done_callback,
77 std::unique_ptr<page::ProcessNavigationResult>) {
78 done_callback.Run();
79 }
80
81 private:
82 base::WeakPtr<HeadlessShell> headless_shell_;
83 int navigation_id_;
84 };
85
57 // An application which implements a simple headless browser. 86 // An application which implements a simple headless browser.
58 class HeadlessShell : public HeadlessWebContents::Observer, 87 class HeadlessShell : public HeadlessWebContents::Observer,
59 emulation::ExperimentalObserver, 88 emulation::ExperimentalObserver,
60 inspector::ExperimentalObserver, 89 inspector::ExperimentalObserver,
61 page::Observer { 90 page::ExperimentalObserver {
62 public: 91 public:
63 HeadlessShell() 92 HeadlessShell()
64 : browser_(nullptr), 93 : browser_(nullptr),
65 devtools_client_(HeadlessDevToolsClient::Create()), 94 devtools_client_(HeadlessDevToolsClient::Create()),
66 web_contents_(nullptr), 95 web_contents_(nullptr),
67 processed_page_ready_(false), 96 processed_page_ready_(false),
68 browser_context_(nullptr), 97 browser_context_(nullptr),
69 weak_factory_(this) {} 98 weak_factory_(this) {}
70 ~HeadlessShell() override {} 99 ~HeadlessShell() override {}
71 100
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 } 148 }
120 } 149 }
121 } 150 }
122 151
123 void Shutdown() { 152 void Shutdown() {
124 if (!web_contents_) 153 if (!web_contents_)
125 return; 154 return;
126 if (!RemoteDebuggingEnabled()) { 155 if (!RemoteDebuggingEnabled()) {
127 devtools_client_->GetEmulation()->GetExperimental()->RemoveObserver(this); 156 devtools_client_->GetEmulation()->GetExperimental()->RemoveObserver(this);
128 devtools_client_->GetInspector()->GetExperimental()->RemoveObserver(this); 157 devtools_client_->GetInspector()->GetExperimental()->RemoveObserver(this);
129 devtools_client_->GetPage()->RemoveObserver(this); 158 devtools_client_->GetPage()->GetExperimental()->RemoveObserver(this);
130 if (web_contents_->GetDevToolsTarget()) { 159 if (web_contents_->GetDevToolsTarget()) {
131 web_contents_->GetDevToolsTarget()->DetachClient( 160 web_contents_->GetDevToolsTarget()->DetachClient(
132 devtools_client_.get()); 161 devtools_client_.get());
133 } 162 }
134 } 163 }
135 web_contents_->RemoveObserver(this); 164 web_contents_->RemoveObserver(this);
136 web_contents_ = nullptr; 165 web_contents_ = nullptr;
137 browser_context_->Close(); 166 browser_context_->Close();
138 browser_->Shutdown(); 167 browser_->Shutdown();
139 } 168 }
140 169
141 // HeadlessWebContents::Observer implementation: 170 // HeadlessWebContents::Observer implementation:
142 void DevToolsTargetReady() override { 171 void DevToolsTargetReady() override {
143 web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get()); 172 web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get());
144 devtools_client_->GetInspector()->GetExperimental()->AddObserver(this); 173 devtools_client_->GetInspector()->GetExperimental()->AddObserver(this);
145 devtools_client_->GetPage()->AddObserver(this); 174 devtools_client_->GetPage()->GetExperimental()->AddObserver(this);
146 devtools_client_->GetPage()->Enable(); 175 devtools_client_->GetPage()->Enable();
147 // Check if the document had already finished loading by the time we 176 // Check if the document had already finished loading by the time we
148 // attached. 177 // attached.
149 178
150 devtools_client_->GetEmulation()->GetExperimental()->AddObserver(this); 179 devtools_client_->GetEmulation()->GetExperimental()->AddObserver(this);
151 180
152 if (base::CommandLine::ForCurrentProcess()->HasSwitch( 181 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
182 switches::kDeterministicFetch)) {
183 devtools_client_->GetPage()->GetExperimental()->SetControlNavigations(
184 headless::page::SetControlNavigationsParams::Builder()
185 .SetEnabled(true)
186 .Build());
187 }
188
189 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
153 switches::kVirtualTimeBudget)) { 190 switches::kVirtualTimeBudget)) {
154 std::string budget_ms_ascii = 191 std::string budget_ms_ascii =
155 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 192 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
156 switches::kVirtualTimeBudget); 193 switches::kVirtualTimeBudget);
157 int budget_ms; 194 int budget_ms;
158 CHECK(base::StringToInt(budget_ms_ascii, &budget_ms)) 195 CHECK(base::StringToInt(budget_ms_ascii, &budget_ms))
159 << "Expected an integer value for --virtual-time-budget="; 196 << "Expected an integer value for --virtual-time-budget=";
160 devtools_client_->GetEmulation()->GetExperimental()->SetVirtualTimePolicy( 197 devtools_client_->GetEmulation()->GetExperimental()->SetVirtualTimePolicy(
161 emulation::SetVirtualTimePolicyParams::Builder() 198 emulation::SetVirtualTimePolicyParams::Builder()
162 .SetPolicy(emulation::VirtualTimePolicy:: 199 .SetPolicy(emulation::VirtualTimePolicy::
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
228 265
229 // page::Observer implementation: 266 // page::Observer implementation:
230 void OnLoadEventFired(const page::LoadEventFiredParams& params) override { 267 void OnLoadEventFired(const page::LoadEventFiredParams& params) override {
231 if (base::CommandLine::ForCurrentProcess()->HasSwitch( 268 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
232 switches::kVirtualTimeBudget)) { 269 switches::kVirtualTimeBudget)) {
233 return; 270 return;
234 } 271 }
235 OnPageReady(); 272 OnPageReady();
236 } 273 }
237 274
275 void OnNavigationRequested(
276 const headless::page::NavigationRequestedParams& params) override {
277 deterministic_dispatcher_->NavigationRequested(
278 base::MakeUnique<SimpleNavigationRequest>(weak_factory_.GetWeakPtr(),
279 params));
280 }
281
238 void OnPageReady() { 282 void OnPageReady() {
239 if (processed_page_ready_) 283 if (processed_page_ready_)
240 return; 284 return;
241 processed_page_ready_ = true; 285 processed_page_ready_ = true;
242 286
243 if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpDom)) { 287 if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpDom)) {
244 FetchDom(); 288 FetchDom();
245 } else if (base::CommandLine::ForCurrentProcess()->HasSwitch( 289 } else if (base::CommandLine::ForCurrentProcess()->HasSwitch(
246 switches::kRepl)) { 290 switches::kRepl)) {
247 LOG(INFO) 291 LOG(INFO)
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
379 } 423 }
380 424
381 void OnScreenshotFileClosed(const int close_result) { Shutdown(); } 425 void OnScreenshotFileClosed(const int close_result) { Shutdown(); }
382 426
383 bool RemoteDebuggingEnabled() const { 427 bool RemoteDebuggingEnabled() const {
384 const base::CommandLine& command_line = 428 const base::CommandLine& command_line =
385 *base::CommandLine::ForCurrentProcess(); 429 *base::CommandLine::ForCurrentProcess();
386 return command_line.HasSwitch(switches::kRemoteDebuggingPort); 430 return command_line.HasSwitch(switches::kRemoteDebuggingPort);
387 } 431 }
388 432
433 HeadlessDevToolsClient* devtools_client() const {
434 return devtools_client_.get();
435 }
436
389 private: 437 private:
390 GURL url_; 438 GURL url_;
391 HeadlessBrowser* browser_; // Not owned. 439 HeadlessBrowser* browser_; // Not owned.
392 std::unique_ptr<HeadlessDevToolsClient> devtools_client_; 440 std::unique_ptr<HeadlessDevToolsClient> devtools_client_;
393 HeadlessWebContents* web_contents_; 441 HeadlessWebContents* web_contents_;
394 bool processed_page_ready_; 442 bool processed_page_ready_;
395 std::unique_ptr<net::FileStream> screenshot_file_stream_; 443 std::unique_ptr<net::FileStream> screenshot_file_stream_;
396 HeadlessBrowserContext* browser_context_; 444 HeadlessBrowserContext* browser_context_;
397 std::unique_ptr<DeterministicDispatcher> deterministic_dispatcher_; 445 std::unique_ptr<DeterministicDispatcher> deterministic_dispatcher_;
398 base::WeakPtrFactory<HeadlessShell> weak_factory_; 446 base::WeakPtrFactory<HeadlessShell> weak_factory_;
399 447
400 DISALLOW_COPY_AND_ASSIGN(HeadlessShell); 448 DISALLOW_COPY_AND_ASSIGN(HeadlessShell);
401 }; 449 };
402 450
451 void SimpleNavigationRequest::StartProcessing(base::Closure done_callback) {
452 if (!headless_shell_)
453 return;
454
455 // Allow the navigation to proceed.
456 headless_shell_->devtools_client()
457 ->GetPage()
458 ->GetExperimental()
459 ->ProcessNavigation(
460 headless::page::ProcessNavigationParams::Builder()
461 .SetNavigationId(navigation_id_)
462 .SetResponse(headless::page::NavigationResponse::PROCEED)
463 .Build(),
464 base::Bind(&SimpleNavigationRequest::ProcessNavigationResult,
465 done_callback));
466 }
467
403 bool ValidateCommandLine(const base::CommandLine& command_line) { 468 bool ValidateCommandLine(const base::CommandLine& command_line) {
404 if (!command_line.HasSwitch(switches::kRemoteDebuggingPort)) { 469 if (!command_line.HasSwitch(switches::kRemoteDebuggingPort)) {
405 if (command_line.GetArgs().size() <= 1) 470 if (command_line.GetArgs().size() <= 1)
406 return true; 471 return true;
407 LOG(ERROR) << "Open multiple tabs is only supported when the " 472 LOG(ERROR) << "Open multiple tabs is only supported when the "
408 << "remote debug port is set."; 473 << "remote debug port is set.";
409 return false; 474 return false;
410 } 475 }
411 if (command_line.HasSwitch(switches::kDumpDom)) { 476 if (command_line.HasSwitch(switches::kDumpDom)) {
412 LOG(ERROR) << "Dump DOM is disabled when remote debugging is enabled."; 477 LOG(ERROR) << "Dump DOM is disabled when remote debugging is enabled.";
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
516 builder.SetOverrideWebPreferencesCallback(base::Bind([]( 581 builder.SetOverrideWebPreferencesCallback(base::Bind([](
517 WebPreferences* preferences) { preferences->hide_scrollbars = true; })); 582 WebPreferences* preferences) { preferences->hide_scrollbars = true; }));
518 } 583 }
519 584
520 return HeadlessBrowserMain( 585 return HeadlessBrowserMain(
521 builder.Build(), 586 builder.Build(),
522 base::Bind(&HeadlessShell::OnStart, base::Unretained(&shell))); 587 base::Bind(&HeadlessShell::OnStart, base::Unretained(&shell)));
523 } 588 }
524 589
525 } // namespace headless 590 } // namespace headless
OLDNEW
« no previous file with comments | « headless/BUILD.gn ('k') | headless/public/util/deterministic_dispatcher.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698