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 | 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/files/file_proxy.h" | |
14 #include "base/json/json_writer.h" | 15 #include "base/json/json_writer.h" |
15 #include "base/location.h" | 16 #include "base/location.h" |
16 #include "base/memory/ptr_util.h" | 17 #include "base/memory/ptr_util.h" |
17 #include "base/memory/ref_counted.h" | 18 #include "base/memory/ref_counted.h" |
18 #include "base/memory/weak_ptr.h" | 19 #include "base/memory/weak_ptr.h" |
19 #include "base/numerics/safe_conversions.h" | 20 #include "base/numerics/safe_conversions.h" |
20 #include "base/strings/string_number_conversions.h" | 21 #include "base/strings/string_number_conversions.h" |
21 #include "headless/app/headless_shell_switches.h" | 22 #include "headless/app/headless_shell_switches.h" |
22 #include "headless/public/devtools/domains/emulation.h" | 23 #include "headless/public/devtools/domains/emulation.h" |
23 #include "headless/public/devtools/domains/inspector.h" | 24 #include "headless/public/devtools/domains/inspector.h" |
24 #include "headless/public/devtools/domains/page.h" | 25 #include "headless/public/devtools/domains/page.h" |
25 #include "headless/public/devtools/domains/runtime.h" | 26 #include "headless/public/devtools/domains/runtime.h" |
26 #include "headless/public/headless_browser.h" | 27 #include "headless/public/headless_browser.h" |
27 #include "headless/public/headless_devtools_client.h" | 28 #include "headless/public/headless_devtools_client.h" |
28 #include "headless/public/headless_devtools_target.h" | 29 #include "headless/public/headless_devtools_target.h" |
30 #include "headless/public/headless_shell.h" | |
29 #include "headless/public/headless_web_contents.h" | 31 #include "headless/public/headless_web_contents.h" |
30 #include "headless/public/util/deterministic_dispatcher.h" | 32 #include "headless/public/util/deterministic_dispatcher.h" |
31 #include "headless/public/util/deterministic_http_protocol_handler.h" | 33 #include "headless/public/util/deterministic_http_protocol_handler.h" |
32 #include "net/base/file_stream.h" | 34 #include "net/base/file_stream.h" |
33 #include "net/base/io_buffer.h" | 35 #include "net/base/io_buffer.h" |
34 #include "net/base/ip_address.h" | 36 #include "net/base/ip_address.h" |
35 #include "net/base/net_errors.h" | 37 #include "net/base/net_errors.h" |
36 #include "ui/gfx/geometry/size.h" | 38 #include "ui/gfx/geometry/size.h" |
37 | 39 |
38 namespace headless { | 40 namespace headless { |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
95 browser_->SetDefaultBrowserContext(browser_context_); | 97 browser_->SetDefaultBrowserContext(browser_context_); |
96 | 98 |
97 HeadlessWebContents::Builder builder( | 99 HeadlessWebContents::Builder builder( |
98 browser_context_->CreateWebContentsBuilder()); | 100 browser_context_->CreateWebContentsBuilder()); |
99 base::CommandLine::StringVector args = | 101 base::CommandLine::StringVector args = |
100 base::CommandLine::ForCurrentProcess()->GetArgs(); | 102 base::CommandLine::ForCurrentProcess()->GetArgs(); |
101 | 103 |
102 // TODO(alexclarke): Should we navigate to about:blank first if using | 104 // TODO(alexclarke): Should we navigate to about:blank first if using |
103 // virtual time? | 105 // virtual time? |
104 if (args.empty()) | 106 if (args.empty()) |
107 #if defined(OS_WIN) | |
108 args.push_back(L"about:blank"); | |
109 #else | |
105 args.push_back("about:blank"); | 110 args.push_back("about:blank"); |
111 #endif | |
106 for (auto it = args.rbegin(); it != args.rend(); ++it) { | 112 for (auto it = args.rbegin(); it != args.rend(); ++it) { |
107 GURL url(*it); | 113 GURL url(*it); |
108 HeadlessWebContents* web_contents = builder.SetInitialURL(url).Build(); | 114 HeadlessWebContents* web_contents = builder.SetInitialURL(url).Build(); |
109 if (!web_contents) { | 115 if (!web_contents) { |
110 LOG(ERROR) << "Navigation to " << url << " failed"; | 116 LOG(ERROR) << "Navigation to " << url << " failed"; |
111 browser_->Shutdown(); | 117 browser_->Shutdown(); |
112 return; | 118 return; |
113 } | 119 } |
114 if (!web_contents_ && !RemoteDebuggingEnabled()) { | 120 if (!web_contents_ && !RemoteDebuggingEnabled()) { |
115 // TODO(jzfeng): Support observing multiple targets. | 121 // TODO(jzfeng): Support observing multiple targets. |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
312 | 318 |
313 void OnScreenshotCaptured( | 319 void OnScreenshotCaptured( |
314 std::unique_ptr<page::CaptureScreenshotResult> result) { | 320 std::unique_ptr<page::CaptureScreenshotResult> result) { |
315 base::FilePath file_name = | 321 base::FilePath file_name = |
316 base::CommandLine::ForCurrentProcess()->GetSwitchValuePath( | 322 base::CommandLine::ForCurrentProcess()->GetSwitchValuePath( |
317 switches::kScreenshot); | 323 switches::kScreenshot); |
318 if (file_name.empty()) { | 324 if (file_name.empty()) { |
319 file_name = base::FilePath().AppendASCII(kDefaultScreenshotFileName); | 325 file_name = base::FilePath().AppendASCII(kDefaultScreenshotFileName); |
320 } | 326 } |
321 | 327 |
322 screenshot_file_stream_.reset( | 328 screenshot_file_proxy_.reset( |
323 new net::FileStream(browser_->BrowserFileThread())); | 329 new base::FileProxy(browser_->BrowserFileThread().get())); |
324 const int open_result = screenshot_file_stream_->Open( | 330 if (!screenshot_file_proxy_->CreateOrOpen( |
325 file_name, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE | | 331 file_name, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE, |
326 base::File::FLAG_ASYNC, | 332 base::Bind(&HeadlessShell::OnScreenshotFileOpened, |
327 base::Bind(&HeadlessShell::OnScreenshotFileOpened, | 333 weak_factory_.GetWeakPtr(), base::Passed(&result), |
Sami
2017/02/09 17:51:40
nit: Could you keep this base::Passed(std::move(re
dvallet
2017/02/10 05:29:49
Done
| |
328 weak_factory_.GetWeakPtr(), base::Passed(std::move(result)), | 334 file_name))) { |
329 file_name)); | |
330 if (open_result != net::ERR_IO_PENDING) { | |
331 // Operation could not be started. | 335 // Operation could not be started. |
332 OnScreenshotFileOpened(nullptr, file_name, open_result); | 336 OnScreenshotFileOpened(nullptr, file_name, base::File::FILE_ERROR_FAILED); |
333 } | 337 } |
334 } | 338 } |
335 | 339 |
336 void OnScreenshotFileOpened( | 340 void OnScreenshotFileOpened( |
337 std::unique_ptr<page::CaptureScreenshotResult> result, | 341 std::unique_ptr<page::CaptureScreenshotResult> result, |
338 const base::FilePath file_name, | 342 const base::FilePath file_name, |
339 const int open_result) { | 343 base::File::Error error_code) { |
340 if (open_result != net::OK) { | 344 if (!screenshot_file_proxy_->IsValid()) { |
341 LOG(ERROR) << "Writing screenshot to file " << file_name.value() | 345 LOG(ERROR) << "Writing screenshot to file " << file_name.value() |
342 << " was unsuccessful, could not open file: " | 346 << " was unsuccessful, could not open file: " |
343 << net::ErrorToString(open_result); | 347 << base::File::ErrorToString(error_code); |
344 return; | 348 return; |
345 } | 349 } |
346 | 350 |
347 std::string decoded_png; | 351 std::string decoded_png; |
348 base::Base64Decode(result->GetData(), &decoded_png); | 352 base::Base64Decode(result->GetData(), &decoded_png); |
349 scoped_refptr<net::IOBufferWithSize> buf = | 353 scoped_refptr<net::IOBufferWithSize> buf = |
350 new net::IOBufferWithSize(decoded_png.size()); | 354 new net::IOBufferWithSize(decoded_png.size()); |
351 memcpy(buf->data(), decoded_png.data(), decoded_png.size()); | 355 memcpy(buf->data(), decoded_png.data(), decoded_png.size()); |
352 const int write_result = screenshot_file_stream_->Write( | 356 |
353 buf.get(), buf->size(), | 357 if (!screenshot_file_proxy_->Write( |
354 base::Bind(&HeadlessShell::OnScreenshotFileWritten, | 358 0, buf->data(), buf->size(), |
355 weak_factory_.GetWeakPtr(), file_name, buf->size())); | 359 base::Bind(&HeadlessShell::OnScreenshotFileWritten, |
356 if (write_result != net::ERR_IO_PENDING) { | 360 weak_factory_.GetWeakPtr(), file_name, buf->size()))) { |
357 // Operation may have completed successfully or failed. | 361 // Operation may have completed successfully or failed. |
358 OnScreenshotFileWritten(file_name, buf->size(), write_result); | 362 OnScreenshotFileWritten(file_name, buf->size(), |
363 base::File::FILE_ERROR_FAILED, 0); | |
359 } | 364 } |
360 } | 365 } |
361 | 366 |
362 void OnScreenshotFileWritten(const base::FilePath file_name, | 367 void OnScreenshotFileWritten(const base::FilePath file_name, |
363 const int length, | 368 const int length, |
364 const int write_result) { | 369 base::File::Error error_code, |
370 int write_result) { | |
365 if (write_result < length) { | 371 if (write_result < length) { |
366 // TODO(eseckler): Support recovering from partial writes. | 372 // TODO(eseckler): Support recovering from partial writes. |
367 LOG(ERROR) << "Writing screenshot to file " << file_name.value() | 373 LOG(ERROR) << "Writing screenshot to file " << file_name.value() |
368 << " was unsuccessful: " << net::ErrorToString(write_result); | 374 << " was unsuccessful: " << net::ErrorToString(write_result); |
369 } else { | 375 } else { |
370 LOG(INFO) << "Screenshot written to file " << file_name.value() << "." | 376 LOG(INFO) << "Screenshot written to file " << file_name.value() << "." |
371 << std::endl; | 377 << std::endl; |
372 } | 378 } |
373 int close_result = screenshot_file_stream_->Close(base::Bind( | 379 if (!screenshot_file_proxy_->Close( |
374 &HeadlessShell::OnScreenshotFileClosed, weak_factory_.GetWeakPtr())); | 380 base::Bind(&HeadlessShell::OnScreenshotFileClosed, |
375 if (close_result != net::ERR_IO_PENDING) { | 381 weak_factory_.GetWeakPtr()))) { |
376 // Operation could not be started. | 382 // Operation could not be started. |
377 OnScreenshotFileClosed(close_result); | 383 OnScreenshotFileClosed(base::File::FILE_ERROR_FAILED); |
378 } | 384 } |
379 } | 385 } |
380 | 386 |
381 void OnScreenshotFileClosed(const int close_result) { Shutdown(); } | 387 void OnScreenshotFileClosed(base::File::Error error_code) { Shutdown(); } |
382 | 388 |
383 bool RemoteDebuggingEnabled() const { | 389 bool RemoteDebuggingEnabled() const { |
384 const base::CommandLine& command_line = | 390 const base::CommandLine& command_line = |
385 *base::CommandLine::ForCurrentProcess(); | 391 *base::CommandLine::ForCurrentProcess(); |
386 return command_line.HasSwitch(switches::kRemoteDebuggingPort); | 392 return command_line.HasSwitch(switches::kRemoteDebuggingPort); |
387 } | 393 } |
388 | 394 |
389 private: | 395 private: |
390 GURL url_; | 396 GURL url_; |
391 HeadlessBrowser* browser_; // Not owned. | 397 HeadlessBrowser* browser_; // Not owned. |
392 std::unique_ptr<HeadlessDevToolsClient> devtools_client_; | 398 std::unique_ptr<HeadlessDevToolsClient> devtools_client_; |
393 HeadlessWebContents* web_contents_; | 399 HeadlessWebContents* web_contents_; |
394 bool processed_page_ready_; | 400 bool processed_page_ready_; |
395 std::unique_ptr<net::FileStream> screenshot_file_stream_; | 401 std::unique_ptr<base::FileProxy> screenshot_file_proxy_; |
396 HeadlessBrowserContext* browser_context_; | 402 HeadlessBrowserContext* browser_context_; |
397 std::unique_ptr<DeterministicDispatcher> deterministic_dispatcher_; | 403 std::unique_ptr<DeterministicDispatcher> deterministic_dispatcher_; |
398 base::WeakPtrFactory<HeadlessShell> weak_factory_; | 404 base::WeakPtrFactory<HeadlessShell> weak_factory_; |
399 | 405 |
400 DISALLOW_COPY_AND_ASSIGN(HeadlessShell); | 406 DISALLOW_COPY_AND_ASSIGN(HeadlessShell); |
401 }; | 407 }; |
402 | 408 |
403 bool ValidateCommandLine(const base::CommandLine& command_line) { | 409 bool ValidateCommandLine(const base::CommandLine& command_line) { |
404 if (!command_line.HasSwitch(switches::kRemoteDebuggingPort)) { | 410 if (!command_line.HasSwitch(switches::kRemoteDebuggingPort)) { |
405 if (command_line.GetArgs().size() <= 1) | 411 if (command_line.GetArgs().size() <= 1) |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
516 builder.SetOverrideWebPreferencesCallback(base::Bind([]( | 522 builder.SetOverrideWebPreferencesCallback(base::Bind([]( |
517 WebPreferences* preferences) { preferences->hide_scrollbars = true; })); | 523 WebPreferences* preferences) { preferences->hide_scrollbars = true; })); |
518 } | 524 } |
519 | 525 |
520 return HeadlessBrowserMain( | 526 return HeadlessBrowserMain( |
521 builder.Build(), | 527 builder.Build(), |
522 base::Bind(&HeadlessShell::OnStart, base::Unretained(&shell))); | 528 base::Bind(&HeadlessShell::OnStart, base::Unretained(&shell))); |
523 } | 529 } |
524 | 530 |
525 } // namespace headless | 531 } // namespace headless |
OLD | NEW |