summaryrefslogtreecommitdiff
path: root/chromium/headless
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-11-20 10:33:36 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-11-22 11:45:12 +0000
commitbe59a35641616a4cf23c4a13fa0632624b021c1b (patch)
tree9da183258bdf9cc413f7562079d25ace6955467f /chromium/headless
parentd702e4b6a64574e97fc7df8fe3238cde70242080 (diff)
downloadqtwebengine-chromium-be59a35641616a4cf23c4a13fa0632624b021c1b.tar.gz
BASELINE: Update Chromium to 62.0.3202.101
Change-Id: I2d5eca8117600df6d331f6166ab24d943d9814ac Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/headless')
-rw-r--r--chromium/headless/BUILD.gn95
-rw-r--r--chromium/headless/DEPS3
-rw-r--r--chromium/headless/app/headless_example.cc8
-rw-r--r--chromium/headless/app/headless_shell.cc73
-rw-r--r--chromium/headless/app/headless_shell.h9
-rw-r--r--chromium/headless/app/headless_shell_switches.cc6
-rw-r--r--chromium/headless/app/headless_shell_switches.h1
-rw-r--r--chromium/headless/app/shell_navigation_request.cc62
-rw-r--r--chromium/headless/app/shell_navigation_request.h23
-rw-r--r--chromium/headless/lib/browser/OWNERS4
-rw-r--r--chromium/headless/lib/browser/headless_browser_context_impl.cc33
-rw-r--r--chromium/headless/lib/browser/headless_browser_context_impl.h5
-rw-r--r--chromium/headless/lib/browser/headless_browser_context_options.cc7
-rw-r--r--chromium/headless/lib/browser/headless_browser_context_options.h3
-rw-r--r--chromium/headless/lib/browser/headless_browser_impl.cc9
-rw-r--r--chromium/headless/lib/browser/headless_browser_impl_mac.mm17
-rw-r--r--chromium/headless/lib/browser/headless_browser_main_parts_mac.mm2
-rw-r--r--chromium/headless/lib/browser/headless_browser_manifest_overlay.json (renamed from chromium/headless/lib/browser/headless_browser_manifest_overlay_template.json)5
-rw-r--r--chromium/headless/lib/browser/headless_content_browser_client.cc66
-rw-r--r--chromium/headless/lib/browser/headless_content_browser_client.h4
-rw-r--r--chromium/headless/lib/browser/headless_devtools.cc2
-rw-r--r--chromium/headless/lib/browser/headless_devtools_client_impl.cc10
-rw-r--r--chromium/headless/lib/browser/headless_network_delegate.cc50
-rw-r--r--chromium/headless/lib/browser/headless_network_delegate.h10
-rw-r--r--chromium/headless/lib/browser/headless_packaged_services_manifest_overlay.json4
-rw-r--r--chromium/headless/lib/browser/headless_print_manager.cc2
-rw-r--r--chromium/headless/lib/browser/headless_url_request_context_getter.cc27
-rw-r--r--chromium/headless/lib/browser/headless_url_request_context_getter.h12
-rw-r--r--chromium/headless/lib/browser/headless_web_contents_impl.cc81
-rw-r--r--chromium/headless/lib/browser/headless_web_contents_impl.h10
-rw-r--r--chromium/headless/lib/dom_tree_extraction_expected_nodes.txt4
-rw-r--r--chromium/headless/lib/frame_id_browsertest.cc45
-rw-r--r--chromium/headless/lib/headless_browser_browsertest.cc32
-rw-r--r--chromium/headless/lib/headless_content_main_delegate.cc69
-rw-r--r--chromium/headless/lib/headless_content_main_delegate.h9
-rw-r--r--chromium/headless/lib/headless_content_main_delegate_win.cc5
-rw-r--r--chromium/headless/lib/headless_devtools_client_browsertest.cc157
-rw-r--r--chromium/headless/lib/headless_macros.h6
-rw-r--r--chromium/headless/lib/headless_web_contents_browsertest.cc53
-rw-r--r--chromium/headless/lib/renderer/OWNERS2
-rw-r--r--chromium/headless/lib/renderer/headless_content_renderer_client.cc8
-rw-r--r--chromium/headless/lib/renderer/headless_print_render_frame_helper_delegate.cc46
-rw-r--r--chromium/headless/lib/renderer/headless_print_render_frame_helper_delegate.h33
-rw-r--r--chromium/headless/lib/renderer/headless_print_web_view_helper_delegate.cc44
-rw-r--r--chromium/headless/lib/renderer/headless_print_web_view_helper_delegate.h32
-rw-r--r--chromium/headless/lib/renderer/headless_render_frame_controller_impl.cc8
-rw-r--r--chromium/headless/lib/renderer/headless_render_frame_controller_impl.h5
-rw-r--r--chromium/headless/lib/resources/headless_lib_resources.grd6
-rw-r--r--chromium/headless/lib/utility/DEPS4
-rw-r--r--chromium/headless/lib/utility/headless_content_utility_client.cc32
-rw-r--r--chromium/headless/lib/utility/headless_content_utility_client.h30
-rw-r--r--chromium/headless/lib/virtual_time_browsertest.cc17
-rw-r--r--chromium/headless/public/headless_browser.cc5
-rw-r--r--chromium/headless/public/headless_browser.h2
-rw-r--r--chromium/headless/public/headless_browser_context.h4
-rw-r--r--chromium/headless/public/headless_web_contents.h7
-rw-r--r--chromium/headless/public/util/deterministic_http_protocol_handler.cc5
-rw-r--r--chromium/headless/public/util/fontconfig.cc4
-rw-r--r--chromium/headless/public/util/generic_url_request_job.cc186
-rw-r--r--chromium/headless/public/util/generic_url_request_job.h70
-rw-r--r--chromium/headless/public/util/generic_url_request_job_test.cc334
-rw-r--r--chromium/headless/public/util/http_url_fetcher.cc21
-rw-r--r--chromium/headless/public/util/http_url_fetcher.h5
-rw-r--r--chromium/headless/public/util/navigation_request.h3
-rw-r--r--chromium/headless/public/util/testing/generic_url_request_mocks.cc29
-rw-r--r--chromium/headless/public/util/testing/generic_url_request_mocks.h11
-rw-r--r--chromium/headless/public/util/url_fetcher.cc7
-rw-r--r--chromium/headless/public/util/url_fetcher.h19
68 files changed, 1340 insertions, 662 deletions
diff --git a/chromium/headless/BUILD.gn b/chromium/headless/BUILD.gn
index d723d947dce..84cad42d18b 100644
--- a/chromium/headless/BUILD.gn
+++ b/chromium/headless/BUILD.gn
@@ -7,6 +7,7 @@ import("//build/util/process_version.gni")
import("//headless/headless.gni")
import("//mojo/public/tools/bindings/mojom.gni")
import("//printing/features/features.gni")
+import("//services/service_manager/public/service_manifest.gni")
import("//testing/test.gni")
import("//third_party/closure_compiler/compile_js.gni")
import("//tools/grit/grit_rule.gni")
@@ -28,8 +29,8 @@ group("headless_lib") {
repack("pak") {
sources = [
- "$root_gen_dir/blink/public/resources/blink_image_resources_100_percent.pak",
"$root_gen_dir/blink/public/resources/blink_resources.pak",
+ "$root_gen_dir/blink/public/resources/blink_scaled_resources_100_percent.pak",
"$root_gen_dir/components/components_resources.pak",
"$root_gen_dir/components/strings/components_strings_en-US.pak",
"$root_gen_dir/content/app/resources/content_resources_100_percent.pak",
@@ -61,8 +62,8 @@ repack("pak") {
"//content/browser/devtools:resources",
"//content/browser/tracing:resources",
"//net:net_resources",
- "//third_party/WebKit/public:image_resources",
"//third_party/WebKit/public:resources",
+ "//third_party/WebKit/public:scaled_resources_100_percent",
"//ui/resources",
"//ui/strings",
]
@@ -115,17 +116,30 @@ mojom("headless_render_frame_controller") {
]
}
+service_manifest("headless_browser_manifest_overlay") {
+ source = "lib/browser/headless_browser_manifest_overlay.json"
+}
+
+service_manifest("headless_packaged_services_manifest_overlay") {
+ source = "lib/browser/headless_packaged_services_manifest_overlay.json"
+ packaged_services =
+ [ "//components/printing/service:pdf_compositor_manifest" ]
+}
+
grit("resources") {
source = "lib/resources/headless_lib_resources.grd"
outputs = [
"grit/headless_lib_resources.h",
"$root_gen_dir/headless/headless_lib_resources.pak",
]
+ source_is_generated = true
grit_flags = [
"-E",
"mojom_root=" + rebase_path(root_gen_dir, root_build_dir),
]
deps = [
+ ":headless_browser_manifest_overlay",
+ ":headless_packaged_services_manifest_overlay",
":headless_render_frame_controller_js",
":tab_socket_js",
]
@@ -223,7 +237,7 @@ js_library("js_devtools_bindings_lib") {
extra_deps = [ ":gen_devtools_client_api" ]
}
-if (headless_fontconfig_utils) {
+if (headless_fontconfig_utils && !is_fuchsia) {
static_library("headless_fontconfig_utils") {
sources = [
"public/util/fontconfig.cc",
@@ -280,8 +294,6 @@ component("headless") {
"lib/browser/headless_window_tree_host.h",
"lib/headless_content_client.cc",
"lib/headless_content_client.h",
- "lib/headless_crash_reporter_client.cc",
- "lib/headless_crash_reporter_client.h",
"public/headless_browser.cc",
"public/headless_browser.h",
"public/headless_browser_context.h",
@@ -323,6 +335,13 @@ component("headless") {
"public/util/user_agent.h",
]
+ if (!is_fuchsia) {
+ sources += [
+ "lib/headless_crash_reporter_client.cc",
+ "lib/headless_crash_reporter_client.h",
+ ]
+ }
+
sources += generated_devtools_api
if (use_aura) {
@@ -344,8 +363,8 @@ component("headless") {
sources += [
"lib/browser/headless_print_manager.cc",
"lib/browser/headless_print_manager.h",
- "lib/renderer/headless_print_web_view_helper_delegate.cc",
- "lib/renderer/headless_print_web_view_helper_delegate.h",
+ "lib/renderer/headless_print_render_frame_helper_delegate.cc",
+ "lib/renderer/headless_print_render_frame_helper_delegate.h",
]
}
@@ -388,18 +407,31 @@ component("headless") {
"lib/renderer/headless_render_frame_controller_impl.h",
"lib/renderer/headless_tab_socket_bindings.cc",
"lib/renderer/headless_tab_socket_bindings.h",
+ "lib/utility/headless_content_utility_client.cc",
+ "lib/utility/headless_content_utility_client.h",
]
deps += [
- "//components/crash/content/browser",
"//components/security_state/content",
+ "//gin",
+ "//third_party/WebKit/public:blink",
"//third_party/WebKit/public:blink_headers",
+ "//v8",
]
+ if (!is_fuchsia) {
+ deps += [ "//components/crash/content/browser" ]
+ }
+ if (is_win) {
+ deps += [ "//components/crash/content/app:crash_export_thunks" ]
+ }
+
if (enable_basic_printing) {
deps += [
"//components/printing/browser",
"//components/printing/renderer",
+ "//components/printing/service/public/cpp:factory",
+ "//components/printing/service/public/interfaces",
]
}
}
@@ -424,7 +456,7 @@ component("headless") {
deps += [ "//ui/ozone" ]
}
- if (headless_fontconfig_utils) {
+ if (headless_fontconfig_utils && !is_fuchsia) {
deps += [ ":headless_fontconfig_utils" ]
}
@@ -496,6 +528,8 @@ test("headless_unittests") {
sources += [
"lib/browser/headless_content_browser_client.cc",
"lib/browser/headless_content_browser_client.h",
+ "lib/utility/headless_content_utility_client.cc",
+ "lib/utility/headless_content_utility_client.h",
]
}
@@ -503,7 +537,6 @@ test("headless_unittests") {
":headless_renderer",
"//base/test:run_all_unittests",
"//base/test:test_support",
- "//components/crash/content/browser",
"//components/security_state/content",
"//content/public/app:both",
"//content/public/child:child",
@@ -512,9 +545,21 @@ test("headless_unittests") {
"//testing/gtest",
]
+ if (!is_fuchsia) {
+ deps += [ "//components/crash/content/browser" ]
+ }
+
+ if (is_win) {
+ deps += [ "//components/crash/content/app:crash_export_thunks" ]
+ }
+
if (enable_basic_printing) {
sources += [ "lib/browser/headless_printing_unittest.cc" ]
- deps += [ "//components/printing/browser" ]
+ deps += [
+ "//components/printing/browser",
+ "//components/printing/service/public/cpp:factory",
+ "//third_party/WebKit/public:blink",
+ ]
}
}
@@ -638,19 +683,27 @@ test("headless_browsertests") {
sources += [
"lib/browser/headless_content_browser_client.cc",
"lib/browser/headless_content_browser_client.h",
+ "lib/utility/headless_content_utility_client.cc",
+ "lib/utility/headless_content_utility_client.h",
]
}
deps = [
":headless_renderer",
"//base",
- "//components/crash/content/browser",
"//components/security_state/content",
"//content/test:test_support",
"//testing/gmock",
"//testing/gtest",
]
+ if (!is_fuchsia) {
+ deps += [
+ "//components/crash/content/app:test_support",
+ "//components/crash/content/browser",
+ ]
+ }
+
# Only include this if we built the js_binary
if (is_linux) {
data += [ "$root_out_dir/headless_browser_tests.pak" ]
@@ -661,6 +714,7 @@ test("headless_browsertests") {
if (enable_basic_printing) {
deps += [
"//components/printing/browser",
+ "//components/printing/service/public/cpp:factory",
"//pdf",
]
}
@@ -734,6 +788,8 @@ if (is_win) {
"lib/headless_content_main_delegate.cc",
"lib/headless_content_main_delegate.h",
"lib/headless_content_main_delegate_win.cc",
+ "lib/utility/headless_content_utility_client.cc",
+ "lib/utility/headless_content_utility_client.h",
]
deps += [ "//third_party/WebKit/public:blink_headers" ]
}
@@ -754,12 +810,13 @@ static_library("headless_shell_lib") {
"app/shell_navigation_request.h",
"lib/browser/headless_content_browser_client.cc",
"lib/browser/headless_content_browser_client.h",
+ "lib/utility/headless_content_utility_client.cc",
+ "lib/utility/headless_content_utility_client.h",
"public/headless_shell.h",
]
deps = [
":headless_renderer",
- "//components/crash/content/browser",
"//components/security_state/content",
"//content/public/app:both",
"//content/public/browser",
@@ -767,10 +824,15 @@ static_library("headless_shell_lib") {
"//content/public/common",
]
+ if (!is_fuchsia) {
+ deps += [ "//components/crash/content/browser" ]
+ }
+
if (enable_basic_printing) {
deps += [
"//components/printing/browser",
"//components/printing/renderer",
+ "//components/printing/service/public/cpp:factory",
]
}
@@ -778,6 +840,7 @@ static_library("headless_shell_lib") {
defines = [ "HEADLESS_USE_CRASPHAD" ]
deps += [
+ "//components/crash/content/app:crash_export_thunks",
"//components/crash/content/app:run_as_crashpad_handler",
"//content:sandbox_helper_win",
"//sandbox",
@@ -785,6 +848,12 @@ static_library("headless_shell_lib") {
}
}
+if (is_fuchsia) {
+ fuchsia_executable_runner("headless_shell_fuchsia") {
+ exe_target = ":headless_shell"
+ }
+}
+
executable("headless_shell") {
sources = [
"app/headless_shell_main.cc",
diff --git a/chromium/headless/DEPS b/chromium/headless/DEPS
index 70959d7e827..343e456ad58 100644
--- a/chromium/headless/DEPS
+++ b/chromium/headless/DEPS
@@ -1,6 +1,8 @@
include_rules = [
"+components/crash/content/app",
"+components/crash/content/browser",
+ "+components/printing/service/public/cpp",
+ "+components/printing/service/public/interfaces",
"+content/public/app",
"+content/public/browser",
"+content/public/renderer",
@@ -8,6 +10,7 @@ include_rules = [
"+content/public/test",
"+mojo/public",
"+net",
+ "+printing/features",
"+ui/base",
"+ui/base/resource",
"+ui/display",
diff --git a/chromium/headless/app/headless_example.cc b/chromium/headless/app/headless_example.cc
index d344796bdde..693095a151f 100644
--- a/chromium/headless/app/headless_example.cc
+++ b/chromium/headless/app/headless_example.cc
@@ -97,9 +97,11 @@ void HeadlessExample::DevToolsTargetReady() {
void HeadlessExample::OnLoadEventFired(
const headless::page::LoadEventFiredParams& params) {
// The page has now finished loading. Let's grab a snapshot of the DOM by
- // evaluating the outerHTML property on the body element.
+ // evaluating the innerHTML property on the document element.
devtools_client_->GetRuntime()->Evaluate(
- "document.body.outerHTML",
+ "(document.doctype ? new "
+ "XMLSerializer().serializeToString(document.doctype) + '\\n' : '') + "
+ "document.documentElement.outerHTML",
base::Bind(&HeadlessExample::OnDomFetched, weak_factory_.GetWeakPtr()));
}
@@ -108,7 +110,7 @@ void HeadlessExample::OnDomFetched(
std::string dom;
// Make sure the evaluation succeeded before reading the result.
if (result->HasExceptionDetails()) {
- LOG(ERROR) << "Failed to evaluate document.body.outerHTML: "
+ LOG(ERROR) << "Failed to serialize document: "
<< result->GetExceptionDetails()->GetText();
} else if (result->GetResult()->GetValue()->GetAsString(&dom)) {
printf("%s\n", dom.c_str());
diff --git a/chromium/headless/app/headless_shell.cc b/chromium/headless/app/headless_shell.cc
index b7bb09c26aa..b44101e9a46 100644
--- a/chromium/headless/app/headless_shell.cc
+++ b/chromium/headless/app/headless_shell.cc
@@ -20,7 +20,9 @@
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "base/task_scheduler/post_task.h"
+#include "build/build_config.h"
#include "content/public/app/content_main.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_switches.h"
#include "headless/app/headless_shell.h"
#include "headless/app/headless_shell_switches.h"
@@ -31,6 +33,7 @@
#include "net/base/ip_address.h"
#include "net/base/net_errors.h"
#include "net/http/http_util.h"
+#include "ui/base/ui_base_switches.h"
#include "ui/gfx/geometry/size.h"
#if defined(OS_WIN)
@@ -83,6 +86,11 @@ void HeadlessShell::OnStart(HeadlessBrowser* browser) {
browser_->CreateBrowserContextBuilder();
// TODO(eseckler): These switches should also affect BrowserContexts that
// are created via DevTools later.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(::switches::kLang)) {
+ context_builder.SetAcceptLanguage(
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ ::switches::kLang));
+ }
DeterministicHttpProtocolHandler* http_handler = nullptr;
DeterministicHttpProtocolHandler* https_handler = nullptr;
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -153,6 +161,10 @@ void HeadlessShell::Shutdown() {
web_contents_->GetDevToolsTarget()->DetachClient(devtools_client_.get());
}
}
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDeterministicFetch)) {
+ devtools_client_->GetNetwork()->GetExperimental()->RemoveObserver(this);
+ }
web_contents_->RemoveObserver(this);
web_contents_ = nullptr;
browser_context_->Close();
@@ -160,6 +172,7 @@ void HeadlessShell::Shutdown() {
}
void HeadlessShell::DevToolsTargetReady() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get());
devtools_client_->GetInspector()->GetExperimental()->AddObserver(this);
devtools_client_->GetPage()->GetExperimental()->AddObserver(this);
@@ -169,10 +182,13 @@ void HeadlessShell::DevToolsTargetReady() {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDeterministicFetch)) {
- devtools_client_->GetPage()->GetExperimental()->SetControlNavigations(
- headless::page::SetControlNavigationsParams::Builder()
- .SetEnabled(true)
- .Build());
+ devtools_client_->GetNetwork()->GetExperimental()->AddObserver(this);
+ devtools_client_->GetNetwork()
+ ->GetExperimental()
+ ->SetRequestInterceptionEnabled(
+ headless::network::SetRequestInterceptionEnabledParams::Builder()
+ .SetEnabled(true)
+ .Build());
}
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDefaultBackgroundColor)) {
@@ -248,6 +264,7 @@ void HeadlessShell::OnTargetCrashed(
}
void HeadlessShell::PollReadyState() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// We need to check the current location in addition to the ready state to
// be sure the expected page is ready.
devtools_client_->GetRuntime()->Evaluate(
@@ -288,11 +305,20 @@ void HeadlessShell::OnLoadEventFired(const page::LoadEventFiredParams& params) {
OnPageReady();
}
-void HeadlessShell::OnNavigationRequested(
- const headless::page::NavigationRequestedParams& params) {
- deterministic_dispatcher_->NavigationRequested(
- base::MakeUnique<ShellNavigationRequest>(weak_factory_.GetWeakPtr(),
- params));
+// network::Observer implementation:
+void HeadlessShell::OnRequestIntercepted(
+ const headless::network::RequestInterceptedParams& params) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ if (params.GetIsNavigationRequest()) {
+ deterministic_dispatcher_->NavigationRequested(
+ base::MakeUnique<ShellNavigationRequest>(weak_factory_.GetWeakPtr(),
+ params.GetInterceptionId()));
+ return;
+ }
+ devtools_client_->GetNetwork()->GetExperimental()->ContinueInterceptedRequest(
+ headless::network::ContinueInterceptedRequestParams::Builder()
+ .SetInterceptionId(params.GetInterceptionId())
+ .Build());
}
void HeadlessShell::OnPageReady() {
@@ -319,15 +345,18 @@ void HeadlessShell::OnPageReady() {
}
void HeadlessShell::FetchDom() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
devtools_client_->GetRuntime()->Evaluate(
- "document.body.outerHTML",
+ "(document.doctype ? new "
+ "XMLSerializer().serializeToString(document.doctype) + '\\n' : '') + "
+ "document.documentElement.outerHTML",
base::Bind(&HeadlessShell::OnDomFetched, weak_factory_.GetWeakPtr()));
}
void HeadlessShell::OnDomFetched(
std::unique_ptr<runtime::EvaluateResult> result) {
if (result->HasExceptionDetails()) {
- LOG(ERROR) << "Failed to evaluate document.body.outerHTML: "
+ LOG(ERROR) << "Failed to serialize document: "
<< result->GetExceptionDetails()->GetText();
} else {
std::string dom;
@@ -339,6 +368,7 @@ void HeadlessShell::OnDomFetched(
}
void HeadlessShell::InputExpression() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Note that a real system should read user input asynchronously, because
// otherwise all other browser activity is suspended (e.g., page loading).
printf(">>> ");
@@ -369,6 +399,7 @@ void HeadlessShell::OnExpressionResult(
}
void HeadlessShell::CaptureScreenshot() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
devtools_client_->GetPage()->GetExperimental()->CaptureScreenshot(
page::CaptureScreenshotParams::Builder().Build(),
base::Bind(&HeadlessShell::OnScreenshotCaptured,
@@ -387,6 +418,7 @@ void HeadlessShell::OnScreenshotCaptured(
}
void HeadlessShell::PrintToPDF() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
devtools_client_->GetPage()->GetExperimental()->PrintToPDF(
page::PrintToPDFParams::Builder()
.SetDisplayHeaderFooter(true)
@@ -408,6 +440,7 @@ void HeadlessShell::OnPDFCreated(
void HeadlessShell::WriteFile(const std::string& file_path_switch,
const std::string& default_file_name,
const std::string& base64_data) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
base::FilePath file_name =
base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
file_path_switch);
@@ -427,6 +460,7 @@ void HeadlessShell::WriteFile(const std::string& file_path_switch,
void HeadlessShell::OnFileOpened(const std::string& base64_data,
const base::FilePath file_name,
base::File::Error error_code) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!file_proxy_->IsValid()) {
LOG(ERROR) << "Writing to file " << file_name.value()
<< " was unsuccessful, could not open file: "
@@ -459,6 +493,7 @@ void HeadlessShell::OnFileWritten(const base::FilePath file_name,
const size_t length,
base::File::Error error_code,
int write_result) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (write_result < static_cast<int>(length)) {
// TODO(eseckler): Support recovering from partial writes.
LOG(ERROR) << "Writing to file " << file_name.value()
@@ -553,7 +588,8 @@ int HeadlessShellMain(HINSTANCE instance,
::switches::kProcessType);
if (process_type == crash_reporter::switches::kCrashpadHandler) {
return crash_reporter::RunAsCrashpadHandler(
- *base::CommandLine::ForCurrentProcess(), ::switches::kProcessType);
+ *base::CommandLine::ForCurrentProcess(), base::FilePath(),
+ ::switches::kProcessType, switches::kUserDataDir);
}
#endif // defined(HEADLESS_USE_CRASPHAD)
RunChildProcessIfNeeded(instance, sandbox_info);
@@ -568,8 +604,12 @@ int HeadlessShellMain(int argc, const char** argv) {
#endif // defined(OS_WIN)
HeadlessShell shell;
- const base::CommandLine& command_line(
- *base::CommandLine::ForCurrentProcess());
+#if defined(OS_FUCHSIA)
+ // TODO(fuchsia): Remove this when GPU accelerated compositing is ready.
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(::switches::kDisableGpu);
+#endif
+
+ base::CommandLine& command_line(*base::CommandLine::ForCurrentProcess());
if (!ValidateCommandLine(command_line))
return EXIT_FAILURE;
@@ -624,6 +664,11 @@ int HeadlessShellMain(int argc, const char** argv) {
command_line.GetSwitchValueASCII(switches::kProxyServer);
std::unique_ptr<net::ProxyConfig> proxy_config(new net::ProxyConfig);
proxy_config->proxy_rules().ParseFromString(proxy_server);
+ if (command_line.HasSwitch(switches::kProxyBypassList)) {
+ std::string bypass_list =
+ command_line.GetSwitchValueASCII(switches::kProxyBypassList);
+ proxy_config->proxy_rules().bypass_rules.ParseFromString(bypass_list);
+ }
builder.SetProxyConfig(std::move(proxy_config));
}
diff --git a/chromium/headless/app/headless_shell.h b/chromium/headless/app/headless_shell.h
index 4aef3fd6a38..18092fca723 100644
--- a/chromium/headless/app/headless_shell.h
+++ b/chromium/headless/app/headless_shell.h
@@ -28,7 +28,8 @@ namespace headless {
class HeadlessShell : public HeadlessWebContents::Observer,
public emulation::ExperimentalObserver,
public inspector::ExperimentalObserver,
- public page::ExperimentalObserver {
+ public page::ExperimentalObserver,
+ public network::ExperimentalObserver {
public:
HeadlessShell();
~HeadlessShell() override;
@@ -50,8 +51,10 @@ class HeadlessShell : public HeadlessWebContents::Observer,
// page::Observer implementation:
void OnLoadEventFired(const page::LoadEventFiredParams& params) override;
- void OnNavigationRequested(
- const headless::page::NavigationRequestedParams& params) override;
+
+ // network::Observer implementation:
+ void OnRequestIntercepted(
+ const headless::network::RequestInterceptedParams& params) override;
virtual void Shutdown();
diff --git a/chromium/headless/app/headless_shell_switches.cc b/chromium/headless/app/headless_shell_switches.cc
index 7293dd9a53e..dc23d6d715a 100644
--- a/chromium/headless/app/headless_shell_switches.cc
+++ b/chromium/headless/app/headless_shell_switches.cc
@@ -32,6 +32,12 @@ const char kHideScrollbars[] = "hide-scrollbars";
// Save a pdf file of the loaded page.
const char kPrintToPDF[] = "print-to-pdf";
+// Specifies a list of hosts for whom we bypass proxy settings and use direct
+// connections. Ignored unless --proxy-server is also specified. This is a
+// comma-separated list of bypass rules. See: "net/proxy/proxy_bypass_rules.h"
+// for the format of these rules.
+const char kProxyBypassList[] = "proxy-bypass-list";
+
// Uses a specified proxy server, overrides system settings. This switch only
// affects HTTP and HTTPS requests.
const char kProxyServer[] = "proxy-server";
diff --git a/chromium/headless/app/headless_shell_switches.h b/chromium/headless/app/headless_shell_switches.h
index 90566c6f085..b18895d0652 100644
--- a/chromium/headless/app/headless_shell_switches.h
+++ b/chromium/headless/app/headless_shell_switches.h
@@ -17,6 +17,7 @@ extern const char kDeterministicFetch[];
extern const char kDumpDom[];
extern const char kHideScrollbars[];
extern const char kPrintToPDF[];
+extern const char kProxyBypassList[];
extern const char kProxyServer[];
extern const char kRemoteDebuggingAddress[];
extern const char kRemoteDebuggingSocketFd[];
diff --git a/chromium/headless/app/shell_navigation_request.cc b/chromium/headless/app/shell_navigation_request.cc
index 3c419bce8ec..64d5840168c 100644
--- a/chromium/headless/app/shell_navigation_request.cc
+++ b/chromium/headless/app/shell_navigation_request.cc
@@ -4,39 +4,73 @@
#include "headless/app/shell_navigation_request.h"
+#include "content/public/browser/browser_thread.h"
#include "headless/app/headless_shell.h"
namespace headless {
ShellNavigationRequest::ShellNavigationRequest(
base::WeakPtr<HeadlessShell> headless_shell,
- const page::NavigationRequestedParams& params)
- : headless_shell_(headless_shell),
- navigation_id_(params.GetNavigationId()) {}
+ const std::string& interception_id)
+ : headless_shell_(
+ base::MakeUnique<base::WeakPtr<HeadlessShell>>(headless_shell)),
+ interception_id_(interception_id) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+}
ShellNavigationRequest::~ShellNavigationRequest() {}
void ShellNavigationRequest::StartProcessing(base::Closure done_callback) {
- if (!headless_shell_)
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ // The devtools bindings can only be called on the UI thread.
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&ShellNavigationRequest::StartProcessingOnUiThread,
+ base::Passed(std::move(headless_shell_)), interception_id_,
+ std::move(done_callback)));
+}
+
+// static
+void ShellNavigationRequest::StartProcessingOnUiThread(
+ std::unique_ptr<base::WeakPtr<HeadlessShell>> headless_shell,
+ std::string interception_id,
+ base::Closure done_callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ if (!headless_shell)
return;
// Allow the navigation to proceed.
- headless_shell_->devtools_client()
- ->GetPage()
+ (*headless_shell)
+ ->devtools_client()
+ ->GetNetwork()
->GetExperimental()
- ->ProcessNavigation(
- headless::page::ProcessNavigationParams::Builder()
- .SetNavigationId(navigation_id_)
- .SetResponse(headless::page::NavigationResponse::PROCEED)
+ ->ContinueInterceptedRequest(
+ headless::network::ContinueInterceptedRequestParams::Builder()
+ .SetInterceptionId(interception_id)
.Build(),
- base::Bind(&ShellNavigationRequest::ProcessNavigationResult,
- done_callback));
+ base::Bind(&ShellNavigationRequest::ContinueInterceptedRequestResult,
+ std::move(done_callback)));
}
// static
-void ShellNavigationRequest::ProcessNavigationResult(
+void ShellNavigationRequest::ContinueInterceptedRequestResult(
base::Closure done_callback,
- std::unique_ptr<page::ProcessNavigationResult>) {
+ std::unique_ptr<network::ContinueInterceptedRequestResult>) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ // The |done_callback| must be fired on the IO thread.
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO, FROM_HERE,
+ base::Bind(
+ &ShellNavigationRequest::ContinueInterceptedRequestResultOnIoThread,
+ std::move(done_callback)));
+}
+
+// static
+void ShellNavigationRequest::ContinueInterceptedRequestResultOnIoThread(
+ base::Closure done_callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
done_callback.Run();
}
diff --git a/chromium/headless/app/shell_navigation_request.h b/chromium/headless/app/shell_navigation_request.h
index 20ef77f0e4e..1abad6ed305 100644
--- a/chromium/headless/app/shell_navigation_request.h
+++ b/chromium/headless/app/shell_navigation_request.h
@@ -8,7 +8,7 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "headless/public/devtools/domains/page.h"
+#include "headless/public/devtools/domains/network.h"
#include "headless/public/util/navigation_request.h"
namespace headless {
@@ -19,21 +19,32 @@ class HeadlessShell;
class ShellNavigationRequest : public NavigationRequest {
public:
ShellNavigationRequest(base::WeakPtr<HeadlessShell> headless_shell,
- const page::NavigationRequestedParams& params);
+ const std::string& interception_id);
~ShellNavigationRequest() override;
void StartProcessing(base::Closure done_callback) override;
private:
+ static void StartProcessingOnUiThread(
+ std::unique_ptr<base::WeakPtr<HeadlessShell>> headless_shell,
+ std::string interception_id,
+ base::Closure done_callback);
+
// 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(
+ static void ContinueInterceptedRequestResult(
base::Closure done_callback,
- std::unique_ptr<page::ProcessNavigationResult>);
+ std::unique_ptr<network::ContinueInterceptedRequestResult>);
+
+ static void ContinueInterceptedRequestResultOnIoThread(
+ base::Closure done_callback);
- base::WeakPtr<HeadlessShell> headless_shell_;
- int navigation_id_;
+ // Yuck we need to post a weak pointer from the IO -> UI threads but WeakPtr
+ // is super finicky about which threads it's touched on. By boxing this up in
+ // a unique_ptr we can pass it about and only touch it on the UI thread.
+ std::unique_ptr<base::WeakPtr<HeadlessShell>> headless_shell_;
+ std::string interception_id_;
};
} // namespace headless
diff --git a/chromium/headless/lib/browser/OWNERS b/chromium/headless/lib/browser/OWNERS
new file mode 100644
index 00000000000..d2386d842bd
--- /dev/null
+++ b/chromium/headless/lib/browser/OWNERS
@@ -0,0 +1,4 @@
+per-file headless_browser_manifest_overlay.json=set noparent
+per-file headless_browser_manifest_overlay.json=file://ipc/SECURITY_OWNERS
+per-file headless_packaged_services_manifest_overlay.json=set noparent
+per-file headless_packaged_services_manifest_overlay.json=file://ipc/SECURITY_OWNERS
diff --git a/chromium/headless/lib/browser/headless_browser_context_impl.cc b/chromium/headless/lib/browser/headless_browser_context_impl.cc
index 1954451f3ff..bdcaad176e1 100644
--- a/chromium/headless/lib/browser/headless_browser_context_impl.cc
+++ b/chromium/headless/lib/browser/headless_browser_context_impl.cc
@@ -92,6 +92,13 @@ HeadlessBrowserContextImpl::HeadlessBrowserContextImpl(
HeadlessBrowserContextImpl::~HeadlessBrowserContextImpl() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ // Inform observers that we're going away.
+ {
+ base::AutoLock lock(observers_lock_);
+ for (auto& observer : observers_)
+ observer.OnHeadlessBrowserContextDestruct();
+ }
+
// Destroy all web contents before shutting down storage partitions.
web_contents_map_.clear();
@@ -168,6 +175,19 @@ int HeadlessBrowserContextImpl::GetFrameTreeNodeId(int render_process_id,
return find_it->second;
}
+int HeadlessBrowserContextImpl::GetFrameTreeNodeIdForDevToolsFrameId(
+ const std::string& devtools_id) const {
+ base::AutoLock lock(frame_tree_node_map_lock_);
+ for (const auto& pair : frame_tree_node_map_) {
+ std::string frame_devtools_id = content::DevToolsAgentHost::
+ GetUntrustedDevToolsFrameIdForFrameTreeNodeId(pair.first.first,
+ pair.second);
+ if (frame_devtools_id == devtools_id)
+ return pair.second;
+ }
+ return -1;
+}
+
void HeadlessBrowserContextImpl::Close() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
browser_->DestroyBrowserContext(this);
@@ -380,6 +400,19 @@ HeadlessBrowserContext::Builder::SetProductNameAndVersion(
return *this;
}
+HeadlessBrowserContext::Builder& HeadlessBrowserContext::Builder::SetUserAgent(
+ const std::string& user_agent) {
+ options_->user_agent_ = user_agent;
+ return *this;
+}
+
+HeadlessBrowserContext::Builder&
+HeadlessBrowserContext::Builder::SetAcceptLanguage(
+ const std::string& accept_language) {
+ options_->accept_language_ = accept_language;
+ return *this;
+}
+
HeadlessBrowserContext::Builder&
HeadlessBrowserContext::Builder::SetProxyConfig(
std::unique_ptr<net::ProxyConfig> proxy_config) {
diff --git a/chromium/headless/lib/browser/headless_browser_context_impl.h b/chromium/headless/lib/browser/headless_browser_context_impl.h
index ca4bac35ac7..98b6ccdffdd 100644
--- a/chromium/headless/lib/browser/headless_browser_context_impl.h
+++ b/chromium/headless/lib/browser/headless_browser_context_impl.h
@@ -95,6 +95,11 @@ class HeadlessBrowserContextImpl : public HeadlessBrowserContext,
// if it can't be found. Can be called on any thread.
int GetFrameTreeNodeId(int render_process_id, int render_frame_id) const;
+ // Returns the FrameTreeNode id corresponding to |devtools_id| or -1 if it
+ // can't be found. Must be called on the IO thread.
+ int GetFrameTreeNodeIdForDevToolsFrameId(
+ const std::string& devtools_id) const;
+
void NotifyChildContentsCreated(HeadlessWebContentsImpl* parent,
HeadlessWebContentsImpl* child);
diff --git a/chromium/headless/lib/browser/headless_browser_context_options.cc b/chromium/headless/lib/browser/headless_browser_context_options.cc
index 5ca1ab3a2d6..5898576830a 100644
--- a/chromium/headless/lib/browser/headless_browser_context_options.cc
+++ b/chromium/headless/lib/browser/headless_browser_context_options.cc
@@ -41,8 +41,13 @@ const std::string& HeadlessBrowserContextOptions::product_name_and_version()
browser_options_->product_name_and_version);
}
+const std::string& HeadlessBrowserContextOptions::accept_language() const {
+ return ReturnOverriddenValue(accept_language_,
+ browser_options_->accept_language);
+}
+
const std::string& HeadlessBrowserContextOptions::user_agent() const {
- return browser_options_->user_agent;
+ return ReturnOverriddenValue(user_agent_, browser_options_->user_agent);
}
const net::ProxyConfig* HeadlessBrowserContextOptions::proxy_config() const {
diff --git a/chromium/headless/lib/browser/headless_browser_context_options.h b/chromium/headless/lib/browser/headless_browser_context_options.h
index 1d3fb84b038..23a4f6251a7 100644
--- a/chromium/headless/lib/browser/headless_browser_context_options.h
+++ b/chromium/headless/lib/browser/headless_browser_context_options.h
@@ -27,6 +27,7 @@ class HeadlessBrowserContextOptions {
HeadlessBrowserContextOptions&& options);
const std::string& product_name_and_version() const;
+ const std::string& accept_language() const;
const std::string& user_agent() const;
// See HeadlessBrowser::Options::proxy_config.
@@ -62,6 +63,8 @@ class HeadlessBrowserContextOptions {
HeadlessBrowser::Options* browser_options_;
base::Optional<std::string> product_name_and_version_;
+ base::Optional<std::string> accept_language_;
+ base::Optional<std::string> user_agent_;
std::unique_ptr<net::ProxyConfig> proxy_config_;
base::Optional<std::string> host_resolver_rules_;
base::Optional<gfx::Size> window_size_;
diff --git a/chromium/headless/lib/browser/headless_browser_impl.cc b/chromium/headless/lib/browser/headless_browser_impl.cc
index 0f64f11b922..08ba287a98e 100644
--- a/chromium/headless/lib/browser/headless_browser_impl.cc
+++ b/chromium/headless/lib/browser/headless_browser_impl.cc
@@ -30,6 +30,10 @@
#include "ui/events/devices/device_data_manager.h"
#include "ui/gfx/geometry/size.h"
+#if defined(USE_NSS_CERTS)
+#include "net/cert_net/nss_ocsp.h"
+#endif
+
namespace content {
class DevToolsAgentHost;
}
@@ -131,6 +135,11 @@ void HeadlessBrowserImpl::set_browser_main_parts(
}
void HeadlessBrowserImpl::RunOnStartCallback() {
+#if defined(USE_NSS_CERTS)
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO, FROM_HERE,
+ base::Bind(&net::SetMessageLoopForNSSHttpIO));
+#endif
// We don't support the tethering domain on this agent host.
agent_host_ = content::DevToolsAgentHost::CreateForBrowser(
nullptr, content::DevToolsAgentHost::CreateServerSocketCallback());
diff --git a/chromium/headless/lib/browser/headless_browser_impl_mac.mm b/chromium/headless/lib/browser/headless_browser_impl_mac.mm
index 9c40982dc33..9b3be46db03 100644
--- a/chromium/headless/lib/browser/headless_browser_impl_mac.mm
+++ b/chromium/headless/lib/browser/headless_browser_impl_mac.mm
@@ -10,9 +10,24 @@
namespace headless {
+namespace {
+
+NSString* const kActivityReason = @"Batch headless process";
+const NSActivityOptions kActivityOptions =
+ (NSActivityUserInitiatedAllowingIdleSystemSleep |
+ NSActivityLatencyCritical) &
+ ~(NSActivitySuddenTerminationDisabled |
+ NSActivityAutomaticTerminationDisabled);
+
+} // namespace
+
void HeadlessBrowserImpl::PlatformInitialize() {}
-void HeadlessBrowserImpl::PlatformStart() {}
+void HeadlessBrowserImpl::PlatformStart() {
+ // Disallow headless to be throttled as a background process.
+ [[NSProcessInfo processInfo] beginActivityWithOptions:kActivityOptions
+ reason:kActivityReason];
+}
void HeadlessBrowserImpl::PlatformInitializeWebContents(
HeadlessWebContentsImpl* web_contents) {
diff --git a/chromium/headless/lib/browser/headless_browser_main_parts_mac.mm b/chromium/headless/lib/browser/headless_browser_main_parts_mac.mm
index e8ab0a3e0f0..a1404e78306 100644
--- a/chromium/headless/lib/browser/headless_browser_main_parts_mac.mm
+++ b/chromium/headless/lib/browser/headless_browser_main_parts_mac.mm
@@ -13,6 +13,8 @@ namespace headless {
void HeadlessBrowserMainParts::PreMainMessageLoopStart() {
// Force the NSApplication subclass to be used.
[HeadlessShellCrApplication sharedApplication];
+ // Force hide dock and menu bar.
+ [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
}
} // namespace headless
diff --git a/chromium/headless/lib/browser/headless_browser_manifest_overlay_template.json b/chromium/headless/lib/browser/headless_browser_manifest_overlay.json
index d5e3e9943c0..6483a30250d 100644
--- a/chromium/headless/lib/browser/headless_browser_manifest_overlay_template.json
+++ b/chromium/headless/lib/browser/headless_browser_manifest_overlay.json
@@ -1,6 +1,11 @@
{
"name": "content_browser",
"interface_provider_specs": {
+ "service_manager:connector": {
+ "requires": {
+ "pdf_compositor": [ "composite" ]
+ }
+ },
"navigation:frame": {
"provides": {
"renderer": []
diff --git a/chromium/headless/lib/browser/headless_content_browser_client.cc b/chromium/headless/lib/browser/headless_content_browser_client.cc
index bce11ceb850..2915b27be4f 100644
--- a/chromium/headless/lib/browser/headless_content_browser_client.cc
+++ b/chromium/headless/lib/browser/headless_content_browser_client.cc
@@ -28,8 +28,10 @@
#include "headless/lib/browser/headless_devtools_manager_delegate.h"
#include "headless/lib/browser/headless_quota_permission_context.h"
#include "headless/lib/headless_macros.h"
+#include "net/base/url_util.h"
#include "storage/browser/quota/quota_settings.h"
#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/ui_base_switches.h"
#include "ui/gfx/switches.h"
#if defined(HEADLESS_USE_BREAKPAD)
@@ -39,6 +41,11 @@
#include "content/public/common/content_descriptors.h"
#endif // defined(HEADLESS_USE_BREAKPAD)
+#if BUILDFLAG(ENABLE_BASIC_PRINTING) && !defined(CHROME_MULTIPLE_DLL_CHILD)
+#include "base/strings/utf_string_conversions.h"
+#include "components/printing/service/public/interfaces/pdf_compositor.mojom.h"
+#endif
+
namespace headless {
namespace {
@@ -140,20 +147,28 @@ HeadlessContentBrowserClient::GetServiceManifestOverlay(
base::StringPiece name) {
if (name == content::mojom::kBrowserServiceName)
return GetBrowserServiceManifestOverlay();
- else if (name == content::mojom::kRendererServiceName)
+ if (name == content::mojom::kRendererServiceName)
return GetRendererServiceManifestOverlay();
+ if (name == content::mojom::kPackagedServicesServiceName)
+ return GetPackagedServicesServiceManifestOverlay();
return nullptr;
}
+void HeadlessContentBrowserClient::RegisterOutOfProcessServices(
+ OutOfProcessServiceMap* services) {
+#if BUILDFLAG(ENABLE_BASIC_PRINTING) && !defined(CHROME_MULTIPLE_DLL_CHILD)
+ (*services)[printing::mojom::kServiceName] = {
+ base::ASCIIToUTF16("PDF Compositor Service"),
+ content::SANDBOX_TYPE_UTILITY};
+#endif
+}
+
std::unique_ptr<base::Value>
HeadlessContentBrowserClient::GetBrowserServiceManifestOverlay() {
- if (browser_->options()->mojo_service_names.empty())
- return nullptr;
-
base::StringPiece manifest_template =
ui::ResourceBundle::GetSharedInstance().GetRawDataResource(
- IDR_HEADLESS_BROWSER_MANIFEST_OVERLAY_TEMPLATE);
+ IDR_HEADLESS_BROWSER_MANIFEST_OVERLAY);
std::unique_ptr<base::Value> manifest =
base::JSONReader::Read(manifest_template);
@@ -179,6 +194,14 @@ HeadlessContentBrowserClient::GetRendererServiceManifestOverlay() {
return base::JSONReader::Read(manifest_template);
}
+std::unique_ptr<base::Value>
+HeadlessContentBrowserClient::GetPackagedServicesServiceManifestOverlay() {
+ base::StringPiece manifest_template =
+ ui::ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_HEADLESS_PACKAGED_SERVICES_MANIFEST_OVERLAY);
+ return base::JSONReader::Read(manifest_template);
+}
+
content::QuotaPermissionContext*
HeadlessContentBrowserClient::CreateQuotaPermissionContext() {
return new HeadlessQuotaPermissionContext();
@@ -196,7 +219,7 @@ void HeadlessContentBrowserClient::GetQuotaSettings(
void HeadlessContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
const base::CommandLine& command_line,
int child_process_id,
- content::FileDescriptorInfo* mappings) {
+ content::PosixFileDescriptorInfo* mappings) {
#if defined(HEADLESS_USE_BREAKPAD)
int crash_signal_fd = GetCrashSignalFD(command_line, *browser_->options());
if (crash_signal_fd >= 0)
@@ -221,6 +244,25 @@ void HeadlessContentBrowserClient::AppendExtraCommandLineSwitches(
if (breakpad::IsCrashReporterEnabled())
command_line->AppendSwitch(::switches::kEnableCrashReporter);
#endif // defined(HEADLESS_USE_BREAKPAD)
+
+ // If we're spawning a renderer, then override the language switch.
+ if (command_line->GetSwitchValueASCII(::switches::kProcessType) ==
+ ::switches::kRendererProcess) {
+ content::RenderProcessHost* render_process_host =
+ content::RenderProcessHost::FromID(child_process_id);
+ if (render_process_host) {
+ HeadlessBrowserContextImpl* headless_browser_context_impl =
+ HeadlessBrowserContextImpl::From(
+ render_process_host->GetBrowserContext());
+ std::vector<base::StringPiece> languages = base::SplitStringPiece(
+ headless_browser_context_impl->options()->accept_language(), ",",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ if (!languages.empty()) {
+ command_line->AppendSwitchASCII(::switches::kLang,
+ languages[0].as_string());
+ }
+ }
+ }
}
void HeadlessContentBrowserClient::AllowCertificateError(
@@ -234,8 +276,18 @@ void HeadlessContentBrowserClient::AllowCertificateError(
bool expired_previous_decision,
const base::Callback<void(content::CertificateRequestResultType)>&
callback) {
- if (!callback.is_null())
+ if (!callback.is_null()) {
+ // If --allow-insecure-localhost is specified, and the request
+ // was for localhost, then the error was not fatal.
+ bool allow_localhost = base::CommandLine::ForCurrentProcess()->HasSwitch(
+ ::switches::kAllowInsecureLocalhost);
+ if (allow_localhost && net::IsLocalhost(request_url.host())) {
+ callback.Run(content::CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE);
+ return;
+ }
+
callback.Run(content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY);
+ }
}
void HeadlessContentBrowserClient::ResourceDispatcherHostCreated() {
diff --git a/chromium/headless/lib/browser/headless_content_browser_client.h b/chromium/headless/lib/browser/headless_content_browser_client.h
index 5efc35393ad..f018a500120 100644
--- a/chromium/headless/lib/browser/headless_content_browser_client.h
+++ b/chromium/headless/lib/browser/headless_content_browser_client.h
@@ -25,6 +25,7 @@ class HeadlessContentBrowserClient : public content::ContentBrowserClient {
content::DevToolsManagerDelegate* GetDevToolsManagerDelegate() override;
std::unique_ptr<base::Value> GetServiceManifestOverlay(
base::StringPiece name) override;
+ void RegisterOutOfProcessServices(OutOfProcessServiceMap* services) override;
content::QuotaPermissionContext* CreateQuotaPermissionContext() override;
void GetQuotaSettings(
content::BrowserContext* context,
@@ -34,7 +35,7 @@ class HeadlessContentBrowserClient : public content::ContentBrowserClient {
void GetAdditionalMappedFilesForChildProcess(
const base::CommandLine& command_line,
int child_process_id,
- content::FileDescriptorInfo* mappings) override;
+ content::PosixFileDescriptorInfo* mappings) override;
#endif
void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
int child_process_id) override;
@@ -58,6 +59,7 @@ class HeadlessContentBrowserClient : public content::ContentBrowserClient {
private:
std::unique_ptr<base::Value> GetBrowserServiceManifestOverlay();
std::unique_ptr<base::Value> GetRendererServiceManifestOverlay();
+ std::unique_ptr<base::Value> GetPackagedServicesServiceManifestOverlay();
HeadlessBrowserImpl* browser_; // Not owned.
diff --git a/chromium/headless/lib/browser/headless_devtools.cc b/chromium/headless/lib/browser/headless_devtools.cc
index d69b55768cf..21e498de64e 100644
--- a/chromium/headless/lib/browser/headless_devtools.cc
+++ b/chromium/headless/lib/browser/headless_devtools.cc
@@ -119,7 +119,7 @@ void StartLocalDevToolsHttpHandler(HeadlessBrowser::Options* options) {
content::DevToolsAgentHost::StartRemoteDebuggingServer(
std::move(socket_factory), std::string(),
options->user_data_dir, // TODO(altimin): Figure a proper value for this.
- base::FilePath(), options->product_name_and_version, options->user_agent);
+ base::FilePath());
}
void StopLocalDevToolsHttpHandler() {
diff --git a/chromium/headless/lib/browser/headless_devtools_client_impl.cc b/chromium/headless/lib/browser/headless_devtools_client_impl.cc
index 3d07de1a574..ec7e3d4aa01 100644
--- a/chromium/headless/lib/browser/headless_devtools_client_impl.cc
+++ b/chromium/headless/lib/browser/headless_devtools_client_impl.cc
@@ -75,11 +75,11 @@ HeadlessDevToolsClientImpl::~HeadlessDevToolsClientImpl() {}
bool HeadlessDevToolsClientImpl::AttachToHost(
content::DevToolsAgentHost* agent_host) {
DCHECK(!agent_host_);
- if (agent_host->AttachClient(this)) {
- agent_host_ = agent_host;
- return true;
- }
- return false;
+ if (agent_host->IsAttached())
+ return false;
+ agent_host->AttachClient(this);
+ agent_host_ = agent_host;
+ return true;
}
void HeadlessDevToolsClientImpl::ForceAttachToHost(
diff --git a/chromium/headless/lib/browser/headless_network_delegate.cc b/chromium/headless/lib/browser/headless_network_delegate.cc
index d6722a626d7..cad704764e2 100644
--- a/chromium/headless/lib/browser/headless_network_delegate.cc
+++ b/chromium/headless/lib/browser/headless_network_delegate.cc
@@ -4,6 +4,7 @@
#include "headless/lib/browser/headless_network_delegate.h"
+#include "content/public/browser/resource_request_info.h"
#include "headless/lib/browser/headless_browser_context_impl.h"
#include "net/base/net_errors.h"
#include "net/http/http_request_headers.h"
@@ -21,9 +22,17 @@ const char kDevToolsEmulateNetworkConditionsClientId[] =
HeadlessNetworkDelegate::HeadlessNetworkDelegate(
HeadlessBrowserContextImpl* headless_browser_context)
- : headless_browser_context_(headless_browser_context) {}
+ : headless_browser_context_(headless_browser_context) {
+ base::AutoLock lock(lock_);
+ if (headless_browser_context_)
+ headless_browser_context_->AddObserver(this);
+}
-HeadlessNetworkDelegate::~HeadlessNetworkDelegate() {}
+HeadlessNetworkDelegate::~HeadlessNetworkDelegate() {
+ base::AutoLock lock(lock_);
+ if (headless_browser_context_)
+ headless_browser_context_->RemoveObserver(this);
+}
int HeadlessNetworkDelegate::OnBeforeURLRequest(
net::URLRequest* request,
@@ -62,8 +71,38 @@ void HeadlessNetworkDelegate::OnResponseStarted(net::URLRequest* request,
void HeadlessNetworkDelegate::OnCompleted(net::URLRequest* request,
bool started,
int net_error) {
- if (net_error != net::OK)
+ base::AutoLock lock(lock_);
+ if (!headless_browser_context_)
+ return;
+
+ if (net_error != net::OK) {
headless_browser_context_->NotifyUrlRequestFailed(request, net_error);
+ return;
+ }
+
+ if (request->response_info().network_accessed || request->was_cached() ||
+ request->GetResponseCode() != 200 || request->GetRawBodyBytes() > 0) {
+ return;
+ }
+
+ const content::ResourceRequestInfo* resource_request_info =
+ content::ResourceRequestInfo::ForRequest(request);
+ if (!resource_request_info)
+ return;
+
+ content::ResourceType resource_type =
+ resource_request_info->GetResourceType();
+
+ if (resource_type != content::RESOURCE_TYPE_MAIN_FRAME &&
+ resource_type != content::RESOURCE_TYPE_SUB_FRAME) {
+ return;
+ }
+
+ // The |request| was for a navigation where an empty response was served but
+ // the network wasn't accessed and it wasn't cached, so we can be reasonably
+ // certain that DevTools canceled the associated navigation. When it does so
+ // an empty resource is served.
+ headless_browser_context_->NotifyUrlRequestFailed(request, net::ERR_ABORTED);
}
void HeadlessNetworkDelegate::OnURLRequestDestroyed(net::URLRequest* request) {}
@@ -98,4 +137,9 @@ bool HeadlessNetworkDelegate::OnCanAccessFile(
return true;
}
+void HeadlessNetworkDelegate::OnHeadlessBrowserContextDestruct() {
+ base::AutoLock lock(lock_);
+ headless_browser_context_ = nullptr;
+}
+
} // namespace headless
diff --git a/chromium/headless/lib/browser/headless_network_delegate.h b/chromium/headless/lib/browser/headless_network_delegate.h
index fc11b76b530..ccfb5f63976 100644
--- a/chromium/headless/lib/browser/headless_network_delegate.h
+++ b/chromium/headless/lib/browser/headless_network_delegate.h
@@ -7,6 +7,8 @@
#include "base/macros.h"
+#include "base/synchronization/lock.h"
+#include "headless/public/headless_browser_context.h"
#include "net/base/network_delegate_impl.h"
namespace headless {
@@ -14,13 +16,15 @@ class HeadlessBrowserContextImpl;
// We use the HeadlessNetworkDelegate to remove DevTools request headers before
// requests are actually fetched and for reporting failed network requests.
-class HeadlessNetworkDelegate : public net::NetworkDelegateImpl {
+class HeadlessNetworkDelegate : public net::NetworkDelegateImpl,
+ public HeadlessBrowserContext::Observer {
public:
explicit HeadlessNetworkDelegate(
HeadlessBrowserContextImpl* headless_browser_context);
~HeadlessNetworkDelegate() override;
private:
+ // net::NetworkDelegateImpl implementation:
int OnBeforeURLRequest(net::URLRequest* request,
const net::CompletionCallback& callback,
GURL* new_url) override;
@@ -69,6 +73,10 @@ class HeadlessNetworkDelegate : public net::NetworkDelegateImpl {
const base::FilePath& original_path,
const base::FilePath& absolute_path) const override;
+ // HeadlessBrowserContext::Observer implementation:
+ void OnHeadlessBrowserContextDestruct() override;
+
+ base::Lock lock_; // Protects |headless_browser_context_|.
HeadlessBrowserContextImpl* headless_browser_context_; // Not owned.
DISALLOW_COPY_AND_ASSIGN(HeadlessNetworkDelegate);
diff --git a/chromium/headless/lib/browser/headless_packaged_services_manifest_overlay.json b/chromium/headless/lib/browser/headless_packaged_services_manifest_overlay.json
new file mode 100644
index 00000000000..2b560d9751c
--- /dev/null
+++ b/chromium/headless/lib/browser/headless_packaged_services_manifest_overlay.json
@@ -0,0 +1,4 @@
+{
+ "name": "content_packaged_services",
+ "interface_provider_specs": {}
+}
diff --git a/chromium/headless/lib/browser/headless_print_manager.cc b/chromium/headless/lib/browser/headless_print_manager.cc
index 2c761cd84fb..327937fd518 100644
--- a/chromium/headless/lib/browser/headless_print_manager.cc
+++ b/chromium/headless/lib/browser/headless_print_manager.cc
@@ -293,7 +293,7 @@ void HeadlessPrintManager::OnDidPrintPage(
return;
}
auto metafile = base::MakeUnique<printing::PdfMetafileSkia>(
- printing::PDF_SKIA_DOCUMENT_TYPE);
+ printing::SkiaDocumentType::PDF);
if (!metafile->InitFromData(shared_buf->memory(), params.data_size)) {
ReleaseJob(METAFILE_INVALID_HEADER);
return;
diff --git a/chromium/headless/lib/browser/headless_url_request_context_getter.cc b/chromium/headless/lib/browser/headless_url_request_context_getter.cc
index 3b1d2db63bd..a2dbb0d67bb 100644
--- a/chromium/headless/lib/browser/headless_url_request_context_getter.cc
+++ b/chromium/headless/lib/browser/headless_url_request_context_getter.cc
@@ -11,9 +11,11 @@
#include "base/memory/ptr_util.h"
#include "base/task_scheduler/post_task.h"
#include "content/public/browser/browser_thread.h"
+#include "headless/lib/browser/headless_browser_context_impl.h"
#include "headless/lib/browser/headless_browser_context_options.h"
#include "headless/lib/browser/headless_network_delegate.h"
#include "net/dns/mapped_host_resolver.h"
+#include "net/http/http_util.h"
#include "net/proxy/proxy_service.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_builder.h"
@@ -29,6 +31,7 @@ HeadlessURLRequestContextGetter::HeadlessURLRequestContextGetter(
net::NetLog* net_log,
HeadlessBrowserContextImpl* headless_browser_context)
: io_task_runner_(std::move(io_task_runner)),
+ accept_language_(options->accept_language()),
user_agent_(options->user_agent()),
host_resolver_rules_(options->host_resolver_rules()),
proxy_config_(options->proxy_config()),
@@ -54,16 +57,23 @@ HeadlessURLRequestContextGetter::HeadlessURLRequestContextGetter(
proxy_config_service_ =
net::ProxyService::CreateSystemProxyConfigService(io_task_runner_);
}
+ base::AutoLock lock(lock_);
+ headless_browser_context_->AddObserver(this);
}
-HeadlessURLRequestContextGetter::~HeadlessURLRequestContextGetter() {}
+HeadlessURLRequestContextGetter::~HeadlessURLRequestContextGetter() {
+ base::AutoLock lock(lock_);
+ if (headless_browser_context_)
+ headless_browser_context_->RemoveObserver(this);
+}
net::URLRequestContext*
HeadlessURLRequestContextGetter::GetURLRequestContext() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (!url_request_context_) {
net::URLRequestContextBuilder builder;
- // TODO(skyostil): Make language settings configurable.
+ builder.set_accept_language(
+ net::HttpUtil::GenerateAcceptLanguageHeader(accept_language_));
builder.set_user_agent(user_agent_);
// TODO(skyostil): Make these configurable.
builder.set_data_enabled(true);
@@ -73,8 +83,12 @@ HeadlessURLRequestContextGetter::GetURLRequestContext() {
} else {
builder.set_proxy_config_service(std::move(proxy_config_service_));
}
- builder.set_network_delegate(
- base::MakeUnique<HeadlessNetworkDelegate>(headless_browser_context_));
+
+ {
+ base::AutoLock lock(lock_);
+ builder.set_network_delegate(
+ base::MakeUnique<HeadlessNetworkDelegate>(headless_browser_context_));
+ }
if (!host_resolver_rules_.empty()) {
std::unique_ptr<net::HostResolver> host_resolver(
@@ -108,4 +122,9 @@ net::HostResolver* HeadlessURLRequestContextGetter::host_resolver() const {
return url_request_context_->host_resolver();
}
+void HeadlessURLRequestContextGetter::OnHeadlessBrowserContextDestruct() {
+ base::AutoLock lock(lock_);
+ headless_browser_context_ = nullptr;
+}
+
} // namespace headless
diff --git a/chromium/headless/lib/browser/headless_url_request_context_getter.h b/chromium/headless/lib/browser/headless_url_request_context_getter.h
index 5ee7c7fc36a..92341b3b497 100644
--- a/chromium/headless/lib/browser/headless_url_request_context_getter.h
+++ b/chromium/headless/lib/browser/headless_url_request_context_getter.h
@@ -30,7 +30,9 @@ namespace headless {
class HeadlessBrowserContextOptions;
class HeadlessBrowserContextImpl;
-class HeadlessURLRequestContextGetter : public net::URLRequestContextGetter {
+class HeadlessURLRequestContextGetter
+ : public net::URLRequestContextGetter,
+ public HeadlessBrowserContext::Observer {
public:
HeadlessURLRequestContextGetter(
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
@@ -48,6 +50,9 @@ class HeadlessURLRequestContextGetter : public net::URLRequestContextGetter {
net::HostResolver* host_resolver() const;
+ // HeadlessBrowserContext::Observer implementation:
+ void OnHeadlessBrowserContextDestruct() override;
+
protected:
~HeadlessURLRequestContextGetter() override;
@@ -57,6 +62,7 @@ class HeadlessURLRequestContextGetter : public net::URLRequestContextGetter {
// The |options| object given to the constructor is not guaranteed to outlive
// this class, so we make copies of the parts we need to access on the IO
// thread.
+ std::string accept_language_;
std::string user_agent_;
std::string host_resolver_rules_;
const net::ProxyConfig* proxy_config_; // Not owned.
@@ -65,7 +71,9 @@ class HeadlessURLRequestContextGetter : public net::URLRequestContextGetter {
std::unique_ptr<net::URLRequestContext> url_request_context_;
content::ProtocolHandlerMap protocol_handlers_;
content::URLRequestInterceptorScopedVector request_interceptors_;
- net::NetLog* net_log_; // Not owned.
+ net::NetLog* net_log_; // Not owned
+
+ base::Lock lock_; // Protects |headless_browser_context_|.
HeadlessBrowserContextImpl* headless_browser_context_; // Not owned.
DISALLOW_COPY_AND_ASSIGN(HeadlessURLRequestContextGetter);
diff --git a/chromium/headless/lib/browser/headless_web_contents_impl.cc b/chromium/headless/lib/browser/headless_web_contents_impl.cc
index b5bfb40b137..82474bc2c48 100644
--- a/chromium/headless/lib/browser/headless_web_contents_impl.cc
+++ b/chromium/headless/lib/browser/headless_web_contents_impl.cc
@@ -27,6 +27,7 @@
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/bindings_policy.h"
#include "content/public/common/origin_util.h"
+#include "content/public/common/renderer_preferences.h"
#include "headless/lib/browser/headless_browser_context_impl.h"
#include "headless/lib/browser/headless_browser_impl.h"
#include "headless/lib/browser/headless_browser_main_parts.h"
@@ -124,6 +125,63 @@ class HeadlessWebContentsImpl::Delegate : public content::WebContentsDelegate {
headless_contents->SetBounds(rect);
}
+ content::WebContents* OpenURLFromTab(
+ content::WebContents* source,
+ const content::OpenURLParams& params) override {
+ DCHECK_EQ(source, headless_web_contents_->web_contents());
+ content::WebContents* target = nullptr;
+ switch (params.disposition) {
+ case WindowOpenDisposition::CURRENT_TAB:
+ target = source;
+ break;
+
+ case WindowOpenDisposition::NEW_POPUP:
+ case WindowOpenDisposition::NEW_WINDOW:
+ case WindowOpenDisposition::NEW_BACKGROUND_TAB:
+ case WindowOpenDisposition::NEW_FOREGROUND_TAB: {
+ HeadlessWebContentsImpl* child_contents = HeadlessWebContentsImpl::From(
+ headless_web_contents_->browser_context()
+ ->CreateWebContentsBuilder()
+ .SetAllowTabSockets(
+ !!headless_web_contents_->GetHeadlessTabSocket())
+ .SetWindowSize(source->GetContainerBounds().size())
+ .Build());
+ headless_web_contents_->browser_context()->NotifyChildContentsCreated(
+ headless_web_contents_, child_contents);
+ target = child_contents->web_contents();
+ break;
+ }
+
+ // TODO(veluca): add support for other disposition types.
+ case WindowOpenDisposition::SINGLETON_TAB:
+ case WindowOpenDisposition::OFF_THE_RECORD:
+ case WindowOpenDisposition::SAVE_TO_DISK:
+ case WindowOpenDisposition::IGNORE_ACTION:
+ default:
+ return nullptr;
+ }
+
+ content::NavigationController::LoadURLParams load_url_params(params.url);
+ load_url_params.source_site_instance = params.source_site_instance;
+ load_url_params.transition_type = params.transition;
+ load_url_params.frame_tree_node_id = params.frame_tree_node_id;
+ load_url_params.referrer = params.referrer;
+ load_url_params.redirect_chain = params.redirect_chain;
+ load_url_params.extra_headers = params.extra_headers;
+ load_url_params.is_renderer_initiated = params.is_renderer_initiated;
+ load_url_params.should_replace_current_entry =
+ params.should_replace_current_entry;
+
+ if (params.uses_post) {
+ load_url_params.load_type =
+ content::NavigationController::LOAD_TYPE_HTTP_POST;
+ load_url_params.post_data = params.post_data;
+ }
+
+ target->GetController().LoadURLWithParams(load_url_params);
+ return target;
+ }
+
private:
HeadlessBrowserImpl* browser() { return headless_web_contents_->browser(); }
@@ -226,6 +284,8 @@ HeadlessWebContentsImpl::HeadlessWebContentsImpl(
#if BUILDFLAG(ENABLE_BASIC_PRINTING) && !defined(CHROME_MULTIPLE_DLL_CHILD)
HeadlessPrintManager::CreateForWebContents(web_contents);
#endif
+ web_contents->GetMutableRendererPrefs()->accept_languages =
+ browser_context->options()->accept_language();
web_contents_->SetDelegate(web_contents_delegate_.get());
render_process_host_->AddObserver(this);
agent_host_->AddObserver(this);
@@ -250,11 +310,8 @@ void HeadlessWebContentsImpl::CreateMojoService(
void HeadlessWebContentsImpl::RenderFrameCreated(
content::RenderFrameHost* render_frame_host) {
- service_manager::BinderRegistry* interface_registry =
- render_frame_host->GetInterfaceRegistry();
-
for (const MojoService& service : mojo_services_) {
- interface_registry->AddInterface(
+ registry_.AddInterface(
service.service_name,
base::Bind(&HeadlessWebContentsImpl::CreateMojoService,
base::Unretained(this), service.service_factory),
@@ -268,6 +325,13 @@ void HeadlessWebContentsImpl::RenderFrameCreated(
headless_tab_socket_->RenderFrameCreated(render_frame_host);
}
+void HeadlessWebContentsImpl::OnInterfaceRequestFromFrame(
+ content::RenderFrameHost* render_frame_host,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle* interface_pipe) {
+ registry_.TryBindInterface(interface_name, interface_pipe);
+}
+
void HeadlessWebContentsImpl::RenderFrameDeleted(
content::RenderFrameHost* render_frame_host) {
if (headless_tab_socket_)
@@ -293,10 +357,19 @@ HeadlessWebContentsImpl::GetUntrustedDevToolsFrameIdForFrameTreeNodeId(
frame_tree_node_id);
}
+int HeadlessWebContentsImpl::GetFrameTreeNodeIdForDevToolsFrameId(
+ const std::string& devtools_id) const {
+ return browser_context_->GetFrameTreeNodeIdForDevToolsFrameId(devtools_id);
+}
+
int HeadlessWebContentsImpl::GetMainFrameRenderProcessId() const {
return web_contents()->GetMainFrame()->GetProcess()->GetID();
}
+int HeadlessWebContentsImpl::GetMainFrameTreeNodeId() const {
+ return web_contents()->GetMainFrame()->GetFrameTreeNodeId();
+}
+
bool HeadlessWebContentsImpl::OpenURL(const GURL& url) {
if (!url.is_valid())
return false;
diff --git a/chromium/headless/lib/browser/headless_web_contents_impl.h b/chromium/headless/lib/browser/headless_web_contents_impl.h
index 6ea8441bbcc..0b15f0f1578 100644
--- a/chromium/headless/lib/browser/headless_web_contents_impl.h
+++ b/chromium/headless/lib/browser/headless_web_contents_impl.h
@@ -18,6 +18,7 @@
#include "headless/public/headless_devtools_target.h"
#include "headless/public/headless_export.h"
#include "headless/public/headless_web_contents.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
namespace content {
class DevToolsAgentHost;
@@ -63,7 +64,10 @@ class HEADLESS_EXPORT HeadlessWebContentsImpl
std::string GetUntrustedDevToolsFrameIdForFrameTreeNodeId(
int process_id,
int frame_tree_node_id) const override;
+ int GetFrameTreeNodeIdForDevToolsFrameId(
+ const std::string& devtools_id) const override;
int GetMainFrameRenderProcessId() const override;
+ int GetMainFrameTreeNodeId() const override;
// HeadlessDevToolsTarget implementation:
bool AttachClient(HeadlessDevToolsClient* client) override;
@@ -87,6 +91,10 @@ class HEADLESS_EXPORT HeadlessWebContentsImpl
void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
void RenderViewReady() override;
+ void OnInterfaceRequestFromFrame(
+ content::RenderFrameHost* render_frame_host,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle* interface_pipe) override;
content::WebContents* web_contents() const;
bool OpenURL(const GURL& url);
@@ -147,6 +155,8 @@ class HEADLESS_EXPORT HeadlessWebContentsImpl
base::ObserverList<HeadlessWebContents::Observer> observers_;
+ service_manager::BinderRegistry registry_;
+
base::WeakPtrFactory<HeadlessWebContentsImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(HeadlessWebContentsImpl);
diff --git a/chromium/headless/lib/dom_tree_extraction_expected_nodes.txt b/chromium/headless/lib/dom_tree_extraction_expected_nodes.txt
index 1c3b2ee73db..5799ee09c77 100644
--- a/chromium/headless/lib/dom_tree_extraction_expected_nodes.txt
+++ b/chromium/headless/lib/dom_tree_extraction_expected_nodes.txt
@@ -8,7 +8,9 @@
"y": 0.0
},
"childNodeIndexes": [ 1 ],
+ "documentEncoding": "windows-1252",
"documentURL": "http://127.0.0.1/dom_tree_test.html",
+ "frameId": "?",
"layoutNodeIndex": 0,
"nodeName": "#document",
"nodeType": 9,
@@ -222,7 +224,9 @@
"y": 0.0
},
"childNodeIndexes": [ 19 ],
+ "documentEncoding": "windows-1252",
"documentURL": "http://127.0.0.1/iframe.html",
+ "frameId": "?",
"layoutNodeIndex": 7,
"nodeName": "#document",
"nodeType": 9,
diff --git a/chromium/headless/lib/frame_id_browsertest.cc b/chromium/headless/lib/frame_id_browsertest.cc
index 5a03b396b2b..e68f70b2206 100644
--- a/chromium/headless/lib/frame_id_browsertest.cc
+++ b/chromium/headless/lib/frame_id_browsertest.cc
@@ -31,7 +31,7 @@ class TestProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler {
public:
explicit TestProtocolHandler(
scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner)
- : test_delegate_(new TestDelegate(this)),
+ : test_delegate_(new TestDelegate()),
dispatcher_(new ExpeditedDispatcher(io_thread_task_runner)),
headless_browser_context_(nullptr) {}
@@ -65,49 +65,42 @@ class TestProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler {
class MockURLFetcher : public URLFetcher {
public:
- explicit MockURLFetcher(const TestProtocolHandler* protocol_handler)
+ explicit MockURLFetcher(TestProtocolHandler* protocol_handler)
: protocol_handler_(protocol_handler) {}
~MockURLFetcher() override {}
// URLFetcher implementation:
- void StartFetch(const GURL& url,
- const std::string& method,
- const std::string& post_data,
- const net::HttpRequestHeaders& request_headers,
+ void StartFetch(const Request* request,
ResultListener* result_listener) override {
- EXPECT_EQ("GET", method);
+ GURL url = request->GetURLRequest()->url();
+ EXPECT_EQ("GET", request->GetURLRequest()->method());
const Response* response = protocol_handler_->GetResponse(url.spec());
if (!response)
result_listener->OnFetchStartError(net::ERR_FILE_NOT_FOUND);
+ net::LoadTimingInfo load_timing_info;
result_listener->OnFetchCompleteExtractHeaders(
- url, response->data.c_str(), response->data.size());
+ url, response->data.c_str(), response->data.size(), load_timing_info);
+
+ int frame_tree_node_id = request->GetFrameTreeNodeId();
+ DCHECK_NE(frame_tree_node_id, -1) << " For url " << url;
+ protocol_handler_->url_to_frame_tree_node_id_[url.spec()] =
+ frame_tree_node_id;
}
private:
- const TestProtocolHandler* protocol_handler_;
+ TestProtocolHandler* protocol_handler_;
DISALLOW_COPY_AND_ASSIGN(MockURLFetcher);
};
class TestDelegate : public GenericURLRequestJob::Delegate {
public:
- explicit TestDelegate(TestProtocolHandler* protocol_handler)
- : protocol_handler_(protocol_handler) {}
-
+ TestDelegate() {}
~TestDelegate() override {}
// GenericURLRequestJob::Delegate implementation:
- void OnPendingRequest(PendingRequest* pending_request) override {
- const Request* request = pending_request->GetRequest();
- std::string url = request->GetURLRequest()->url().spec();
- int frame_tree_node_id = request->GetFrameTreeNodeId();
- DCHECK_NE(frame_tree_node_id, -1) << " For url " << url;
- protocol_handler_->url_to_frame_tree_node_id_[url] = frame_tree_node_id;
- pending_request->AllowRequest();
- }
-
void OnResourceLoadFailed(const Request* request,
net::Error error) override {}
@@ -119,7 +112,6 @@ class TestProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler {
size_t body_size) override {}
private:
- TestProtocolHandler* protocol_handler_; // NOT OWNED
scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner_;
DISALLOW_COPY_AND_ASSIGN(TestDelegate);
@@ -131,8 +123,9 @@ class TestProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler {
net::NetworkDelegate* network_delegate) const override {
return new GenericURLRequestJob(
request, network_delegate, dispatcher_.get(),
- base::MakeUnique<MockURLFetcher>(this), test_delegate_.get(),
- headless_browser_context_);
+ base::MakeUnique<MockURLFetcher>(
+ const_cast<TestProtocolHandler*>(this)),
+ test_delegate_.get(), headless_browser_context_);
}
std::map<std::string, int> url_to_frame_tree_node_id_;
@@ -256,6 +249,10 @@ class FrameIdTest : public HeadlessAsyncDevTooledBrowserTest,
protocol_handler_url_to_frame_id_[pair.first] =
web_contents_->GetUntrustedDevToolsFrameIdForFrameTreeNodeId(
web_contents_->GetMainFrameRenderProcessId(), pair.second);
+
+ EXPECT_EQ(pair.second,
+ web_contents_->GetFrameTreeNodeIdForDevToolsFrameId(
+ protocol_handler_url_to_frame_id_[pair.first]));
}
EXPECT_THAT(url_to_frame_id_, protocol_handler_url_to_frame_id_);
diff --git a/chromium/headless/lib/headless_browser_browsertest.cc b/chromium/headless/lib/headless_browser_browsertest.cc
index 1206725fb4a..86a5dacd1a6 100644
--- a/chromium/headless/lib/headless_browser_browsertest.cc
+++ b/chromium/headless/lib/headless_browser_browsertest.cc
@@ -11,8 +11,11 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
#include "content/public/browser/permission_manager.h"
#include "content/public/browser/permission_type.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test.h"
#include "headless/lib/browser/headless_browser_context_impl.h"
@@ -187,7 +190,6 @@ class HeadlessBrowserTestWithProxy : public HeadlessBrowserTest {
public:
HeadlessBrowserTestWithProxy()
: proxy_server_(net::SpawnedTestServer::TYPE_HTTP,
- net::SpawnedTestServer::kLocalhost,
base::FilePath(FILE_PATH_LITERAL("headless/test/data"))) {
}
@@ -456,7 +458,7 @@ void URLRequestJobWithCookies::Start() {
// See net::URLRequestHttpJob::AddCookieHeaderAndStart().
url::Origin requested_origin(request_->url());
- url::Origin site_for_cookies(request_->first_party_for_cookies());
+ url::Origin site_for_cookies(request_->site_for_cookies());
if (net::registry_controlled_domains::SameDomainOrHost(
requested_origin, site_for_cookies,
@@ -609,7 +611,7 @@ IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, SetCookiesWithDevTools) {
.SetSecure(true)
.SetHttpOnly(true)
.SetSameSite(network::CookieSameSite::EXACT)
- .SetExpirationDate(0)
+ .SetExpires(0)
.Build();
CookieSetter cookie_setter(this, web_contents,
std::move(set_cookie_params));
@@ -644,9 +646,11 @@ IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, RendererCommandPrefixTest) {
fprintf(launcher_file, "echo $@ > %s\n", launcher_stamp.value().c_str());
fprintf(launcher_file, "exec $@\n");
fclose(launcher_file);
+#if !defined(OS_FUCHSIA)
base::SetPosixFilePermissions(launcher_script,
base::FILE_PERMISSION_READ_BY_USER |
base::FILE_PERMISSION_EXECUTE_BY_USER);
+#endif // !defined(OS_FUCHSIA)
base::CommandLine::ForCurrentProcess()->AppendSwitch("--no-sandbox");
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
@@ -913,4 +917,26 @@ IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, WindowPrint) {
EvaluateScript(web_contents, "window.print()")->HasExceptionDetails());
}
+IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, AllowInsecureLocalhostFlag) {
+ net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
+ https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED);
+ https_server.ServeFilesFromSourceDirectory("headless/test/data");
+ ASSERT_TRUE(https_server.Start());
+ GURL test_url = https_server.GetURL("/hello.html");
+
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kAllowInsecureLocalhost);
+
+ HeadlessBrowserContext* browser_context =
+ browser()->CreateBrowserContextBuilder().Build();
+
+ HeadlessWebContentsImpl* web_contents =
+ HeadlessWebContentsImpl::From(browser_context->CreateWebContentsBuilder()
+ .SetInitialURL(test_url)
+ .Build());
+
+ // If the certificate fails to validate, this should fail.
+ EXPECT_TRUE(WaitForLoad(web_contents));
+}
+
} // namespace headless
diff --git a/chromium/headless/lib/headless_content_main_delegate.cc b/chromium/headless/lib/headless_content_main_delegate.cc
index 645b8ad3930..195ee8027d1 100644
--- a/chromium/headless/lib/headless_content_main_delegate.cc
+++ b/chromium/headless/lib/headless_content_main_delegate.cc
@@ -15,6 +15,7 @@
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
#include "components/crash/content/app/breakpad_linux.h"
#include "content/public/browser/browser_main_runner.h"
#include "content/public/common/content_switches.h"
@@ -22,6 +23,7 @@
#include "headless/lib/browser/headless_content_browser_client.h"
#include "headless/lib/headless_crash_reporter_client.h"
#include "headless/lib/headless_macros.h"
+#include "headless/lib/utility/headless_content_utility_client.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_switches.h"
#include "ui/gfx/switches.h"
@@ -50,8 +52,10 @@ const int kTraceEventBrowserProcessSortIndex = -6;
HeadlessContentMainDelegate* g_current_headless_content_main_delegate = nullptr;
+#if !defined(OS_FUCHSIA)
base::LazyInstance<HeadlessCrashReporterClient>::Leaky g_headless_crash_client =
LAZY_INSTANCE_INITIALIZER;
+#endif
const char kLogFileName[] = "CHROME_LOG_FILE";
} // namespace
@@ -165,8 +169,14 @@ void HeadlessContentMainDelegate::InitLogging(
DCHECK(success);
}
+
void HeadlessContentMainDelegate::InitCrashReporter(
const base::CommandLine& command_line) {
+#if defined(OS_FUCHSIA)
+ // TODO(fuchsia): Implement this when crash reporting/Breakpad are available
+ // in Fuchsia. (crbug.com/753619)
+ NOTIMPLEMENTED();
+#else
const std::string process_type =
command_line.GetSwitchValueASCII(switches::kProcessType);
crash_reporter::SetCrashReporterClient(g_headless_crash_client.Pointer());
@@ -187,10 +197,12 @@ void HeadlessContentMainDelegate::InitCrashReporter(
// TODO(dvallet): Ideally we would also want to avoid this for component builds.
#elif defined(OS_WIN) && !defined(CHROME_MULTIPLE_DLL)
crash_reporter::InitializeCrashpadWithEmbeddedHandler(process_type.empty(),
- process_type);
+ process_type, "");
#endif // defined(HEADLESS_USE_BREAKPAD)
+#endif // defined(OS_FUCHSIA)
}
+
void HeadlessContentMainDelegate::PreSandboxStartup() {
const base::CommandLine& command_line(
*base::CommandLine::ForCurrentProcess());
@@ -202,6 +214,7 @@ void HeadlessContentMainDelegate::PreSandboxStartup() {
if (command_line.HasSwitch(switches::kEnableLogging))
InitLogging(command_line);
#endif // defined(OS_WIN)
+
InitCrashReporter(command_line);
InitializeResourceBundle();
}
@@ -257,11 +270,6 @@ HeadlessContentMainDelegate* HeadlessContentMainDelegate::GetInstance() {
// static
void HeadlessContentMainDelegate::InitializeResourceBundle() {
- base::FilePath dir_module;
- base::FilePath pak_file;
- bool result = PathService::Get(base::DIR_MODULE, &dir_module);
- DCHECK(result);
-
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
const std::string locale = command_line->GetSwitchValueASCII(switches::kLang);
ui::ResourceBundle::InitSharedInstanceWithLocale(
@@ -273,21 +281,51 @@ void HeadlessContentMainDelegate::InitializeResourceBundle() {
reinterpret_cast<const char*>(kHeadlessResourcePak.contents),
kHeadlessResourcePak.length),
ui::SCALE_FACTOR_NONE);
+
#else
+
+ base::FilePath dir_module;
+ bool result = PathService::Get(base::DIR_MODULE, &dir_module);
+ DCHECK(result);
+
// Try loading the headless library pak file first. If it doesn't exist (i.e.,
// when we're running with the --headless switch), fall back to the browser's
// resource pak.
- pak_file = dir_module.Append(FILE_PATH_LITERAL("headless_lib.pak"));
- if (!base::PathExists(pak_file))
- pak_file = dir_module.Append(FILE_PATH_LITERAL("resources.pak"));
+ base::FilePath headless_pak =
+ dir_module.Append(FILE_PATH_LITERAL("headless_lib.pak"));
+ if (base::PathExists(headless_pak)) {
+ ResourceBundle::GetSharedInstance().AddDataPackFromPath(
+ headless_pak, ui::SCALE_FACTOR_NONE);
+ return;
+ }
+
+ // Otherwise, load resources.pak, chrome_100 and chrome_200.
+ base::FilePath resources_pak =
+ dir_module.Append(FILE_PATH_LITERAL("resources.pak"));
+ base::FilePath chrome_100_pak =
+ dir_module.Append(FILE_PATH_LITERAL("chrome_100_percent.pak"));
+ base::FilePath chrome_200_pak =
+ dir_module.Append(FILE_PATH_LITERAL("chrome_200_percent.pak"));
+
#if defined(OS_MACOSX) && !defined(COMPONENT_BUILD)
// In non component builds, check if fall back in Resources/ folder is
// available.
- if (!base::PathExists(pak_file))
- pak_file = dir_module.Append(FILE_PATH_LITERAL("Resources/resources.pak"));
+ if (!base::PathExists(resources_pak)) {
+ resources_pak =
+ dir_module.Append(FILE_PATH_LITERAL("Resources/resources.pak"));
+ chrome_100_pak = dir_module.Append(
+ FILE_PATH_LITERAL("Resources/chrome_100_percent.pak"));
+ chrome_200_pak = dir_module.Append(
+ FILE_PATH_LITERAL("Resources/chrome_200_percent.pak"));
+ }
#endif
+
+ ResourceBundle::GetSharedInstance().AddDataPackFromPath(
+ resources_pak, ui::SCALE_FACTOR_NONE);
ResourceBundle::GetSharedInstance().AddDataPackFromPath(
- pak_file, ui::SCALE_FACTOR_NONE);
+ chrome_100_pak, ui::SCALE_FACTOR_100P);
+ ResourceBundle::GetSharedInstance().AddDataPackFromPath(
+ chrome_200_pak, ui::SCALE_FACTOR_200P);
#endif
}
@@ -306,6 +344,13 @@ HeadlessContentMainDelegate::CreateContentRendererClient() {
renderer_client_ = base::MakeUnique<HeadlessContentRendererClient>();
return renderer_client_.get();
}
+
+content::ContentUtilityClient*
+HeadlessContentMainDelegate::CreateContentUtilityClient() {
+ utility_client_ = base::MakeUnique<HeadlessContentUtilityClient>(
+ browser_->options()->user_agent);
+ return utility_client_.get();
+}
#endif // !defined(CHROME_MULTIPLE_DLL_BROWSER)
} // namespace headless
diff --git a/chromium/headless/lib/headless_content_main_delegate.h b/chromium/headless/lib/headless_content_main_delegate.h
index eb8cd61eea6..37d935177fc 100644
--- a/chromium/headless/lib/headless_content_main_delegate.h
+++ b/chromium/headless/lib/headless_content_main_delegate.h
@@ -10,6 +10,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "build/build_config.h"
#include "content/public/app/content_main_delegate.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/renderer/content_renderer_client.h"
@@ -40,6 +41,7 @@ class HEADLESS_EXPORT HeadlessContentMainDelegate
const std::string& process_type,
const content::MainFunctionParams& main_function_params) override;
content::ContentBrowserClient* CreateContentBrowserClient() override;
+ content::ContentUtilityClient* CreateContentUtilityClient() override;
content::ContentRendererClient* CreateContentRendererClient() override;
HeadlessBrowserImpl* browser() const { return browser_.get(); }
@@ -51,14 +53,15 @@ class HEADLESS_EXPORT HeadlessContentMainDelegate
private:
friend class HeadlessBrowserTest;
- void InitLogging(const base::CommandLine& command_line);
- void InitCrashReporter(const base::CommandLine& command_line);
static void InitializeResourceBundle();
-
static HeadlessContentMainDelegate* GetInstance();
+ void InitLogging(const base::CommandLine& command_line);
+ void InitCrashReporter(const base::CommandLine& command_line);
+
std::unique_ptr<content::ContentRendererClient> renderer_client_;
std::unique_ptr<content::ContentBrowserClient> browser_client_;
+ std::unique_ptr<content::ContentUtilityClient> utility_client_;
HeadlessContentClient content_client_;
HeadlessPlatformEventSource platform_event_source_;
diff --git a/chromium/headless/lib/headless_content_main_delegate_win.cc b/chromium/headless/lib/headless_content_main_delegate_win.cc
index 084683204ba..90460197995 100644
--- a/chromium/headless/lib/headless_content_main_delegate_win.cc
+++ b/chromium/headless/lib/headless_content_main_delegate_win.cc
@@ -30,6 +30,11 @@ content::ContentRendererClient*
HeadlessContentMainDelegate::CreateContentRendererClient() {
return nullptr;
}
+
+content::ContentUtilityClient*
+HeadlessContentMainDelegate::CreateContentUtilityClient() {
+ return nullptr;
+}
#endif // defined(CHROME_MULTIPLE_DLL_BROWSER)
} // namespace headless
diff --git a/chromium/headless/lib/headless_devtools_client_browsertest.cc b/chromium/headless/lib/headless_devtools_client_browsertest.cc
index 8a4e5491cc2..1e97640027c 100644
--- a/chromium/headless/lib/headless_devtools_client_browsertest.cc
+++ b/chromium/headless/lib/headless_devtools_client_browsertest.cc
@@ -459,11 +459,7 @@ class TargetDomainCreateAndDeletePageTest
}
};
-#if defined(OS_WIN)
-DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(TargetDomainCreateAndDeletePageTest);
-#else
HEADLESS_ASYNC_DEVTOOLED_TEST_F(TargetDomainCreateAndDeletePageTest);
-#endif
class TargetDomainCreateAndDeleteBrowserContextTest
: public HeadlessAsyncDevTooledBrowserTest {
@@ -531,12 +527,7 @@ class TargetDomainCreateAndDeleteBrowserContextTest
std::string browser_context_id_;
};
-#if defined(OS_WIN)
-DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(
- TargetDomainCreateAndDeleteBrowserContextTest);
-#else
HEADLESS_ASYNC_DEVTOOLED_TEST_F(TargetDomainCreateAndDeleteBrowserContextTest);
-#endif
class TargetDomainDisposeContextFailsIfInUse
: public HeadlessAsyncDevTooledBrowserTest {
@@ -612,12 +603,7 @@ class TargetDomainDisposeContextFailsIfInUse
std::string page_id_;
};
-#if defined(OS_WIN)
-DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(
- TargetDomainDisposeContextFailsIfInUse);
-#else
HEADLESS_ASYNC_DEVTOOLED_TEST_F(TargetDomainDisposeContextFailsIfInUse);
-#endif
class TargetDomainCreateTwoContexts : public HeadlessAsyncDevTooledBrowserTest,
public target::ExperimentalObserver,
@@ -889,41 +875,44 @@ class TargetDomainCreateTwoContexts : public HeadlessAsyncDevTooledBrowserTest,
int context_closed_count_ = 0;
};
-#if defined(OS_WIN)
-DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(TargetDomainCreateTwoContexts);
-#else
HEADLESS_ASYNC_DEVTOOLED_TEST_F(TargetDomainCreateTwoContexts);
-#endif
class HeadlessDevToolsNavigationControlTest
: public HeadlessAsyncDevTooledBrowserTest,
+ network::ExperimentalObserver,
page::ExperimentalObserver {
public:
void RunDevTooledTest() override {
EXPECT_TRUE(embedded_test_server()->Start());
base::RunLoop run_loop;
devtools_client_->GetPage()->GetExperimental()->AddObserver(this);
+ devtools_client_->GetNetwork()->GetExperimental()->AddObserver(this);
devtools_client_->GetPage()->Enable(run_loop.QuitClosure());
base::MessageLoop::ScopedNestableTaskAllower nest_loop(
base::MessageLoop::current());
run_loop.Run();
- devtools_client_->GetPage()->GetExperimental()->SetControlNavigations(
- headless::page::SetControlNavigationsParams::Builder()
- .SetEnabled(true)
- .Build());
+ devtools_client_->GetNetwork()->Enable();
+ devtools_client_->GetNetwork()
+ ->GetExperimental()
+ ->SetRequestInterceptionEnabled(
+ headless::network::SetRequestInterceptionEnabledParams::Builder()
+ .SetEnabled(true)
+ .Build());
devtools_client_->GetPage()->Navigate(
embedded_test_server()->GetURL("/hello.html").spec());
}
- void OnNavigationRequested(
- const headless::page::NavigationRequestedParams& params) override {
- navigation_requested_ = true;
+ void OnRequestIntercepted(
+ const network::RequestInterceptedParams& params) override {
+ if (params.GetIsNavigationRequest())
+ navigation_requested_ = true;
// Allow the navigation to proceed.
- devtools_client_->GetPage()->GetExperimental()->ProcessNavigation(
- headless::page::ProcessNavigationParams::Builder()
- .SetNavigationId(params.GetNavigationId())
- .SetResponse(headless::page::NavigationResponse::PROCEED)
- .Build());
+ devtools_client_->GetNetwork()
+ ->GetExperimental()
+ ->ContinueInterceptedRequest(
+ headless::network::ContinueInterceptedRequestParams::Builder()
+ .SetInterceptionId(params.GetInterceptionId())
+ .Build());
}
void OnFrameStoppedLoading(
@@ -1386,7 +1375,7 @@ class DomTreeExtractionBrowserTest : public HeadlessAsyncDevTooledBrowserTest,
HEADLESS_ASYNC_DEVTOOLED_TEST_F(DomTreeExtractionBrowserTest);
-class FailedUrlRequestTest : public HeadlessAsyncDevTooledBrowserTest,
+class UrlRequestFailedTest : public HeadlessAsyncDevTooledBrowserTest,
public HeadlessBrowserContext::Observer,
public network::ExperimentalObserver,
public page::Observer {
@@ -1413,49 +1402,77 @@ class FailedUrlRequestTest : public HeadlessAsyncDevTooledBrowserTest,
run_loop.Run();
devtools_client_->GetPage()->Navigate(
- embedded_test_server()->GetURL("/dom_tree_test.html").spec());
+ embedded_test_server()->GetURL("/resource_cancel_test.html").spec());
+ }
+
+ bool ShouldCancel(const std::string& url) {
+ if (EndsWith(url, "/iframe.html", base::CompareCase::INSENSITIVE_ASCII))
+ return true;
+
+ if (EndsWith(url, "/test.jpg", base::CompareCase::INSENSITIVE_ASCII))
+ return true;
+
+ return false;
}
void OnRequestIntercepted(
const network::RequestInterceptedParams& params) override {
- if (EndsWith(params.GetRequest()->GetUrl(), "/iframe.html",
- base::CompareCase::INSENSITIVE_ASCII)) {
- // Block the iframe resource load.
- devtools_client_->GetNetwork()
- ->GetExperimental()
- ->ContinueInterceptedRequest(
- network::ContinueInterceptedRequestParams::Builder()
- .SetInterceptionId(params.GetInterceptionId())
- .SetErrorReason(network::ErrorReason::ABORTED)
- .Build());
- } else {
- // Allow everything else to continue.
- devtools_client_->GetNetwork()
- ->GetExperimental()
- ->ContinueInterceptedRequest(
- network::ContinueInterceptedRequestParams::Builder()
- .SetInterceptionId(params.GetInterceptionId())
- .Build());
- }
+ urls_seen_.push_back(GURL(params.GetRequest()->GetUrl()).ExtractFileName());
+ auto continue_intercept_params =
+ network::ContinueInterceptedRequestParams::Builder()
+ .SetInterceptionId(params.GetInterceptionId())
+ .Build();
+ if (ShouldCancel(params.GetRequest()->GetUrl()))
+ continue_intercept_params->SetErrorReason(GetErrorReason());
+
+ devtools_client_->GetNetwork()
+ ->GetExperimental()
+ ->ContinueInterceptedRequest(std::move(continue_intercept_params));
}
void OnLoadEventFired(const page::LoadEventFiredParams&) override {
+ browser_context_->RemoveObserver(this);
+
base::AutoLock lock(lock_);
- EXPECT_EQ("iframe.html", url_that_failed_to_load_);
+ EXPECT_THAT(urls_that_failed_to_load_,
+ ElementsAre("test.jpg", "iframe.html"));
+ EXPECT_THAT(
+ urls_seen_,
+ ElementsAre("resource_cancel_test.html", "dom_tree_test.css",
+ "test.jpg", "iframe.html", "iframe2.html", "Ahem.ttf"));
FinishAsynchronousTest();
}
void UrlRequestFailed(net::URLRequest* request, int net_error) override {
base::AutoLock lock(lock_);
- url_that_failed_to_load_ = request->url().ExtractFileName();
+ urls_that_failed_to_load_.push_back(request->url().ExtractFileName());
}
+ virtual network::ErrorReason GetErrorReason() = 0;
+
private:
base::Lock lock_;
- std::string url_that_failed_to_load_;
+ std::vector<std::string> urls_seen_;
+ std::vector<std::string> urls_that_failed_to_load_;
+};
+
+class UrlRequestFailedTest_Failed : public UrlRequestFailedTest {
+ public:
+ network::ErrorReason GetErrorReason() override {
+ return network::ErrorReason::FAILED;
+ }
};
-HEADLESS_ASYNC_DEVTOOLED_TEST_F(FailedUrlRequestTest);
+HEADLESS_ASYNC_DEVTOOLED_TEST_F(UrlRequestFailedTest_Failed);
+
+class UrlRequestFailedTest_Abort : public UrlRequestFailedTest {
+ public:
+ network::ErrorReason GetErrorReason() override {
+ return network::ErrorReason::ABORTED;
+ }
+};
+
+HEADLESS_ASYNC_DEVTOOLED_TEST_F(UrlRequestFailedTest_Abort);
class DevToolsSetCookieTest : public HeadlessAsyncDevTooledBrowserTest,
public network::Observer {
@@ -1491,7 +1508,6 @@ class DevtoolsInterceptionWithAuthProxyTest
public:
DevtoolsInterceptionWithAuthProxyTest()
: proxy_server_(net::SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
- net::SpawnedTestServer::kLocalhost,
base::FilePath(FILE_PATH_LITERAL("headless/test/data"))) {
}
@@ -1560,11 +1576,12 @@ class DevtoolsInterceptionWithAuthProxyTest
FinishAsynchronousTest();
}
- std::unique_ptr<net::ProxyConfig> GetProxyConfig() override {
+ void CustomizeHeadlessBrowserContext(
+ HeadlessBrowserContext::Builder& builder) override {
std::unique_ptr<net::ProxyConfig> proxy_config(new net::ProxyConfig);
proxy_config->proxy_rules().ParseFromString(
proxy_server_.host_port_pair().ToString());
- return proxy_config;
+ builder.SetProxyConfig(std::move(proxy_config));
}
private:
@@ -1575,4 +1592,28 @@ class DevtoolsInterceptionWithAuthProxyTest
HEADLESS_ASYNC_DEVTOOLED_TEST_F(DevtoolsInterceptionWithAuthProxyTest);
+class NavigatorLanguages : public HeadlessAsyncDevTooledBrowserTest {
+ public:
+ void RunDevTooledTest() override {
+ devtools_client_->GetRuntime()->Evaluate(
+ "JSON.stringify(navigator.languages)",
+ base::Bind(&NavigatorLanguages::OnResult, base::Unretained(this)));
+ }
+
+ void OnResult(std::unique_ptr<runtime::EvaluateResult> result) {
+ std::string value;
+ EXPECT_TRUE(result->GetResult()->HasValue());
+ EXPECT_TRUE(result->GetResult()->GetValue()->GetAsString(&value));
+ EXPECT_EQ("[\"en-UK\",\"DE\",\"FR\"]", value);
+ FinishAsynchronousTest();
+ }
+
+ void CustomizeHeadlessBrowserContext(
+ HeadlessBrowserContext::Builder& builder) override {
+ builder.SetAcceptLanguage("en-UK, DE, FR");
+ }
+};
+
+HEADLESS_ASYNC_DEVTOOLED_TEST_F(NavigatorLanguages);
+
} // namespace headless
diff --git a/chromium/headless/lib/headless_macros.h b/chromium/headless/lib/headless_macros.h
index 4b7bedb7a9c..f0dea81eb17 100644
--- a/chromium/headless/lib/headless_macros.h
+++ b/chromium/headless/lib/headless_macros.h
@@ -5,8 +5,10 @@
#ifndef HEADLESS_LIB_HEADLESS_MACROS_H_
#define HEADLESS_LIB_HEADLESS_MACROS_H_
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#include "build/build_config.h"
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_FUCHSIA)
#define HEADLESS_USE_BREAKPAD
-#endif // defined(OS_POSIX) && !defined(OS_MACOSX)
+#endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_FUCHSIA)
#endif // HEADLESS_LIB_HEADLESS_MACROS_H_
diff --git a/chromium/headless/lib/headless_web_contents_browsertest.cc b/chromium/headless/lib/headless_web_contents_browsertest.cc
index 0f2ed053beb..d852948ecca 100644
--- a/chromium/headless/lib/headless_web_contents_browsertest.cc
+++ b/chromium/headless/lib/headless_web_contents_browsertest.cc
@@ -8,6 +8,8 @@
#include "base/base64.h"
#include "base/json/json_writer.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "content/public/browser/web_contents.h"
@@ -117,6 +119,8 @@ IN_PROC_BROWSER_TEST_F(HeadlessWebContentsTest, WindowOpen) {
EXPECT_EQ(expected_bounds.size(),
child->web_contents()->GetContainerBounds().size());
#endif // !defined(OS_MACOSX)
+
+ browser_context->RemoveObserver(&observer);
}
class HeadlessWindowOpenTabSocketTest : public HeadlessBrowserTest,
@@ -239,6 +243,8 @@ IN_PROC_BROWSER_TEST_F(HeadlessWindowOpenTabSocketTest,
RunAsynchronousTest();
EXPECT_EQ("Embedder sent us: One", message_);
+
+ browser_context->RemoveObserver(this);
}
class HeadlessNoDevToolsTabSocketTest : public HeadlessBrowserTest,
@@ -860,4 +866,51 @@ class HeadlessWebContentsRequestStorageQuotaTest
HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessWebContentsRequestStorageQuotaTest);
+IN_PROC_BROWSER_TEST_F(HeadlessWebContentsTest, BrowserTabChangeContent) {
+ EXPECT_TRUE(embedded_test_server()->Start());
+
+ HeadlessBrowserContext* browser_context =
+ browser()->CreateBrowserContextBuilder().Build();
+
+ HeadlessWebContents* web_contents =
+ browser_context->CreateWebContentsBuilder().Build();
+ EXPECT_TRUE(WaitForLoad(web_contents));
+
+ std::string script = "window.location = '" +
+ embedded_test_server()->GetURL("/hello.html").spec() +
+ "';";
+ EXPECT_FALSE(EvaluateScript(web_contents, script)->HasExceptionDetails());
+
+ // This will time out if the previous script did not work.
+ EXPECT_TRUE(WaitForLoad(web_contents));
+}
+
+IN_PROC_BROWSER_TEST_F(HeadlessWebContentsTest, BrowserOpenInTab) {
+ EXPECT_TRUE(embedded_test_server()->Start());
+
+ HeadlessBrowserContext* browser_context =
+ browser()->CreateBrowserContextBuilder().Build();
+
+ MockHeadlessBrowserContextObserver observer;
+ browser_context->AddObserver(&observer);
+ EXPECT_CHILD_CONTENTS_CREATED(observer);
+
+ HeadlessWebContents* web_contents =
+ browser_context->CreateWebContentsBuilder()
+ .SetInitialURL(embedded_test_server()->GetURL("/link.html"))
+ .Build();
+ EXPECT_TRUE(WaitForLoad(web_contents));
+
+ EXPECT_EQ(1u, browser_context->GetAllWebContents().size());
+ // Simulates a middle-button click on a link to ensure that the
+ // link is opened in a new tab by the browser and not by the renderer.
+ std::string script =
+ "var event = new MouseEvent('click', {'button': 1});"
+ "document.getElementsByTagName('a')[0].dispatchEvent(event);";
+ EXPECT_FALSE(EvaluateScript(web_contents, script)->HasExceptionDetails());
+
+ // Check that we have a new tab.
+ EXPECT_EQ(2u, browser_context->GetAllWebContents().size());
+ browser_context->RemoveObserver(&observer);
+}
} // namespace headless
diff --git a/chromium/headless/lib/renderer/OWNERS b/chromium/headless/lib/renderer/OWNERS
new file mode 100644
index 00000000000..b81b2a7da6e
--- /dev/null
+++ b/chromium/headless/lib/renderer/OWNERS
@@ -0,0 +1,2 @@
+per-file headless_renderer_manifest_overlay.json=set noparent
+per-file headless_renderer_manifest_overlay.json=file://ipc/SECURITY_OWNERS
diff --git a/chromium/headless/lib/renderer/headless_content_renderer_client.cc b/chromium/headless/lib/renderer/headless_content_renderer_client.cc
index a438df42a2e..ce73e4d1ac9 100644
--- a/chromium/headless/lib/renderer/headless_content_renderer_client.cc
+++ b/chromium/headless/lib/renderer/headless_content_renderer_client.cc
@@ -9,8 +9,8 @@
#include "printing/features/features.h"
#if BUILDFLAG(ENABLE_BASIC_PRINTING)
-#include "components/printing/renderer/print_web_view_helper.h"
-#include "headless/lib/renderer/headless_print_web_view_helper_delegate.h"
+#include "components/printing/renderer/print_render_frame_helper.h"
+#include "headless/lib/renderer/headless_print_render_frame_helper_delegate.h"
#endif
namespace headless {
@@ -22,8 +22,8 @@ HeadlessContentRendererClient::~HeadlessContentRendererClient() {}
void HeadlessContentRendererClient::RenderFrameCreated(
content::RenderFrame* render_frame) {
#if BUILDFLAG(ENABLE_BASIC_PRINTING)
- new printing::PrintWebViewHelper(
- render_frame, base::MakeUnique<HeadlessPrintWebViewHelperDelegate>());
+ new printing::PrintRenderFrameHelper(
+ render_frame, base::MakeUnique<HeadlessPrintRenderFrameHelperDelegate>());
#endif
new HeadlessRenderFrameControllerImpl(render_frame);
}
diff --git a/chromium/headless/lib/renderer/headless_print_render_frame_helper_delegate.cc b/chromium/headless/lib/renderer/headless_print_render_frame_helper_delegate.cc
new file mode 100644
index 00000000000..b3dc8acf2dc
--- /dev/null
+++ b/chromium/headless/lib/renderer/headless_print_render_frame_helper_delegate.cc
@@ -0,0 +1,46 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "headless/lib/renderer/headless_print_render_frame_helper_delegate.h"
+
+#include "third_party/WebKit/public/web/WebElement.h"
+
+namespace headless {
+
+HeadlessPrintRenderFrameHelperDelegate::
+ HeadlessPrintRenderFrameHelperDelegate() {}
+
+HeadlessPrintRenderFrameHelperDelegate::
+ ~HeadlessPrintRenderFrameHelperDelegate() {}
+
+bool HeadlessPrintRenderFrameHelperDelegate::CancelPrerender(
+ content::RenderFrame* render_frame) {
+ return false;
+}
+
+blink::WebElement HeadlessPrintRenderFrameHelperDelegate::GetPdfElement(
+ blink::WebLocalFrame* frame) {
+ return blink::WebElement();
+}
+
+bool HeadlessPrintRenderFrameHelperDelegate::IsPrintPreviewEnabled() {
+ return false;
+}
+
+bool HeadlessPrintRenderFrameHelperDelegate::OverridePrint(
+ blink::WebLocalFrame* frame) {
+ return false;
+}
+
+bool HeadlessPrintRenderFrameHelperDelegate::IsAskPrintSettingsEnabled() {
+ return true;
+}
+
+#if defined(OS_MACOSX)
+bool HeadlessPrintRenderFrameHelperDelegate::UseSingleMetafile() {
+ return true;
+}
+#endif
+
+} // namespace headless
diff --git a/chromium/headless/lib/renderer/headless_print_render_frame_helper_delegate.h b/chromium/headless/lib/renderer/headless_print_render_frame_helper_delegate.h
new file mode 100644
index 00000000000..7e7b3136325
--- /dev/null
+++ b/chromium/headless/lib/renderer/headless_print_render_frame_helper_delegate.h
@@ -0,0 +1,33 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef HEADLESS_LIB_RENDERER_HEADLESS_PRINT_RENDER_FRAME_HELPER_DELEGATE_H_
+#define HEADLESS_LIB_RENDERER_HEADLESS_PRINT_RENDER_FRAME_HELPER_DELEGATE_H_
+
+#include "build/build_config.h"
+#include "components/printing/renderer/print_render_frame_helper.h"
+
+namespace headless {
+
+class HeadlessPrintRenderFrameHelperDelegate
+ : public printing::PrintRenderFrameHelper::Delegate {
+ public:
+ HeadlessPrintRenderFrameHelperDelegate();
+ ~HeadlessPrintRenderFrameHelperDelegate() override;
+
+ // PrintRenderFrameHelper Delegate implementation.
+ bool CancelPrerender(content::RenderFrame* render_frame) override;
+ bool IsPrintPreviewEnabled() override;
+ bool OverridePrint(blink::WebLocalFrame* frame) override;
+ bool IsAskPrintSettingsEnabled() override;
+ blink::WebElement GetPdfElement(blink::WebLocalFrame* frame) override;
+
+#if defined(OS_MACOSX)
+ bool UseSingleMetafile() override;
+#endif
+};
+
+} // namespace headless
+
+#endif // HEADLESS_LIB_RENDERER_HEADLESS_PRINT_RENDER_FRAME_HELPER_DELEGATE_H_
diff --git a/chromium/headless/lib/renderer/headless_print_web_view_helper_delegate.cc b/chromium/headless/lib/renderer/headless_print_web_view_helper_delegate.cc
deleted file mode 100644
index 4d78ea29b70..00000000000
--- a/chromium/headless/lib/renderer/headless_print_web_view_helper_delegate.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "headless/lib/renderer/headless_print_web_view_helper_delegate.h"
-
-#include "third_party/WebKit/public/web/WebElement.h"
-
-namespace headless {
-
-HeadlessPrintWebViewHelperDelegate::HeadlessPrintWebViewHelperDelegate() {}
-
-HeadlessPrintWebViewHelperDelegate::~HeadlessPrintWebViewHelperDelegate() {}
-
-bool HeadlessPrintWebViewHelperDelegate::CancelPrerender(
- content::RenderFrame* render_frame) {
- return false;
-}
-
-blink::WebElement HeadlessPrintWebViewHelperDelegate::GetPdfElement(
- blink::WebLocalFrame* frame) {
- return blink::WebElement();
-}
-
-bool HeadlessPrintWebViewHelperDelegate::IsPrintPreviewEnabled() {
- return false;
-}
-
-bool HeadlessPrintWebViewHelperDelegate::OverridePrint(
- blink::WebLocalFrame* frame) {
- return false;
-}
-
-bool HeadlessPrintWebViewHelperDelegate::IsAskPrintSettingsEnabled() {
- return true;
-}
-
-#if defined(OS_MACOSX)
-bool HeadlessPrintWebViewHelperDelegate::UseSingleMetafile() {
- return true;
-}
-#endif
-
-} // namespace headless
diff --git a/chromium/headless/lib/renderer/headless_print_web_view_helper_delegate.h b/chromium/headless/lib/renderer/headless_print_web_view_helper_delegate.h
deleted file mode 100644
index 691974c029b..00000000000
--- a/chromium/headless/lib/renderer/headless_print_web_view_helper_delegate.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef HEADLESS_LIB_RENDERER_HEADLESS_PRINT_WEB_VIEW_HELPER_DELEGATE_H_
-#define HEADLESS_LIB_RENDERER_HEADLESS_PRINT_WEB_VIEW_HELPER_DELEGATE_H_
-
-#include "components/printing/renderer/print_web_view_helper.h"
-
-namespace headless {
-
-class HeadlessPrintWebViewHelperDelegate
- : public printing::PrintWebViewHelper::Delegate {
- public:
- HeadlessPrintWebViewHelperDelegate();
- ~HeadlessPrintWebViewHelperDelegate() override;
-
- // PrintWebViewHelper Delegate implementation.
- bool CancelPrerender(content::RenderFrame* render_frame) override;
- bool IsPrintPreviewEnabled() override;
- bool OverridePrint(blink::WebLocalFrame* frame) override;
- bool IsAskPrintSettingsEnabled() override;
- blink::WebElement GetPdfElement(blink::WebLocalFrame* frame) override;
-
-#if defined(OS_MACOSX)
- bool UseSingleMetafile() override;
-#endif
-};
-
-} // namespace headless
-
-#endif // HEADLESS_LIB_RENDERER_HEADLESS_PRINT_WEB_VIEW_HELPER_DELEGATE_H_
diff --git a/chromium/headless/lib/renderer/headless_render_frame_controller_impl.cc b/chromium/headless/lib/renderer/headless_render_frame_controller_impl.cc
index 3ec1b4c5748..18b980b4749 100644
--- a/chromium/headless/lib/renderer/headless_render_frame_controller_impl.cc
+++ b/chromium/headless/lib/renderer/headless_render_frame_controller_impl.cc
@@ -16,7 +16,7 @@ HeadlessRenderFrameControllerImpl::HeadlessRenderFrameControllerImpl(
: content::RenderFrameObserver(render_frame),
render_frame_(render_frame),
weak_ptr_factory_(this) {
- render_frame->GetInterfaceRegistry()->AddInterface(base::Bind(
+ registry_.AddInterface(base::Bind(
&HeadlessRenderFrameControllerImpl::OnRenderFrameControllerRequest,
base::Unretained(this)));
}
@@ -68,6 +68,12 @@ void HeadlessRenderFrameControllerImpl::SendMessageToTabSocket(
find_it->second.OnMessageFromEmbedder(message);
}
+void HeadlessRenderFrameControllerImpl::OnInterfaceRequestForFrame(
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle* interface_pipe) {
+ registry_.TryBindInterface(interface_name, interface_pipe);
+}
+
void HeadlessRenderFrameControllerImpl::DidCreateScriptContext(
v8::Local<v8::Context> context,
int world_id) {
diff --git a/chromium/headless/lib/renderer/headless_render_frame_controller_impl.h b/chromium/headless/lib/renderer/headless_render_frame_controller_impl.h
index 5e106e8ef73..dba52acc74a 100644
--- a/chromium/headless/lib/renderer/headless_render_frame_controller_impl.h
+++ b/chromium/headless/lib/renderer/headless_render_frame_controller_impl.h
@@ -11,6 +11,7 @@
#include "headless/lib/renderer/headless_tab_socket_bindings.h"
#include "headless/lib/tab_socket.mojom.h"
#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
namespace headless {
@@ -33,6 +34,9 @@ class HeadlessRenderFrameControllerImpl : public HeadlessRenderFrameController,
int32_t world_id) override;
// content::RenderFrameObserver implementation:
+ void OnInterfaceRequestForFrame(
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle* interface_pipe) override;
void DidCreateScriptContext(v8::Local<v8::Context> context,
int world_id) override;
@@ -51,6 +55,7 @@ class HeadlessRenderFrameControllerImpl : public HeadlessRenderFrameController,
headless::TabSocketPtr tab_socket_ptr_;
InstallMainWorldTabSocketCallback
pending_install_main_world_tab_socket_callback_;
+ service_manager::BinderRegistry registry_;
base::WeakPtrFactory<HeadlessRenderFrameControllerImpl> weak_ptr_factory_;
};
diff --git a/chromium/headless/lib/resources/headless_lib_resources.grd b/chromium/headless/lib/resources/headless_lib_resources.grd
index 78f34cd1e84..9322c4ca31f 100644
--- a/chromium/headless/lib/resources/headless_lib_resources.grd
+++ b/chromium/headless/lib/resources/headless_lib_resources.grd
@@ -10,9 +10,11 @@
<release seq="1">
<includes>
<include name="IDR_HEADLESS_LIB_DEVTOOLS_DISCOVERY_PAGE" file="devtools_discovery_page.html" type="BINDATA" />
- <include name="IDR_HEADLESS_BROWSER_MANIFEST_OVERLAY_TEMPLATE" file="../browser/headless_browser_manifest_overlay_template.json" type="BINDATA" />
+ <include name="IDR_HEADLESS_BROWSER_MANIFEST_OVERLAY" file="${mojom_root}/headless/headless_browser_manifest_overlay.json" use_base_dir="false" type="BINDATA" />
<include name="IDR_HEADLESS_RENDERER_MANIFEST_OVERLAY" file="../renderer/headless_renderer_manifest_overlay.json" type="BINDATA" />
- <include name="IDR_HEADLESS_TAB_SOCKET_MOJOM_JS" file="${mojom_root}\headless\lib\tab_socket.mojom.js" use_base_dir="false" type="BINDATA" />
+ <include name="IDR_HEADLESS_PACKAGED_SERVICES_MANIFEST_OVERLAY" file="${mojom_root}/headless/headless_packaged_services_manifest_overlay.json" use_base_dir="false" type="BINDATA" />
+ <include name="IDR_HEADLESS_TAB_SOCKET_MOJOM_JS" file="${mojom_root}/headless/lib/tab_socket.mojom.js" use_base_dir="false" type="BINDATA" />
+ <include name="IDR_PDF_COMPOSITOR_MANIFEST" file="${mojom_root}/components/printing/service/pdf_compositor_manifest.json" use_base_dir="false" type="BINDATA" />
</includes>
</release>
</grit>
diff --git a/chromium/headless/lib/utility/DEPS b/chromium/headless/lib/utility/DEPS
new file mode 100644
index 00000000000..2d935b53099
--- /dev/null
+++ b/chromium/headless/lib/utility/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+components/printing/service/",
+ "+content/public/utility",
+]
diff --git a/chromium/headless/lib/utility/headless_content_utility_client.cc b/chromium/headless/lib/utility/headless_content_utility_client.cc
new file mode 100644
index 00000000000..a2ddaee3d87
--- /dev/null
+++ b/chromium/headless/lib/utility/headless_content_utility_client.cc
@@ -0,0 +1,32 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "headless/lib/utility/headless_content_utility_client.h"
+
+#include "printing/features/features.h"
+
+#if BUILDFLAG(ENABLE_BASIC_PRINTING)
+#include "components/printing/service/public/cpp/pdf_compositor_service_factory.h"
+#include "components/printing/service/public/interfaces/pdf_compositor.mojom.h"
+#endif
+
+namespace headless {
+
+HeadlessContentUtilityClient::HeadlessContentUtilityClient(
+ const std::string& user_agent)
+ : user_agent_(user_agent) {}
+
+HeadlessContentUtilityClient::~HeadlessContentUtilityClient() {}
+
+void HeadlessContentUtilityClient::RegisterServices(
+ HeadlessContentUtilityClient::StaticServiceMap* services) {
+#if BUILDFLAG(ENABLE_BASIC_PRINTING) && !defined(CHROME_MULTIPLE_DLL_BROWSER)
+ service_manager::EmbeddedServiceInfo pdf_compositor_info;
+ pdf_compositor_info.factory =
+ base::Bind(&printing::CreatePdfCompositorService, user_agent_);
+ services->emplace(printing::mojom::kServiceName, pdf_compositor_info);
+#endif
+}
+
+} // namespace headless
diff --git a/chromium/headless/lib/utility/headless_content_utility_client.h b/chromium/headless/lib/utility/headless_content_utility_client.h
new file mode 100644
index 00000000000..f577dc2c7c6
--- /dev/null
+++ b/chromium/headless/lib/utility/headless_content_utility_client.h
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef HEADLESS_LIB_HEADLESS_CONTENT_UTILITY_CLIENT_H_
+#define HEADLESS_LIB_HEADLESS_CONTENT_UTILITY_CLIENT_H_
+
+#include <string>
+
+#include "content/public/utility/content_utility_client.h"
+
+namespace headless {
+
+class HeadlessContentUtilityClient : public content::ContentUtilityClient {
+ public:
+ explicit HeadlessContentUtilityClient(const std::string& user_agent);
+ ~HeadlessContentUtilityClient() override;
+
+ // content::ContentUtilityClient:
+ void RegisterServices(StaticServiceMap* services) override;
+
+ private:
+ const std::string user_agent_;
+
+ DISALLOW_COPY_AND_ASSIGN(HeadlessContentUtilityClient);
+};
+
+} // namespace headless
+
+#endif // HEADLESS_LIB_HEADLESS_CONTENT_UTILITY_CLIENT_H_
diff --git a/chromium/headless/lib/virtual_time_browsertest.cc b/chromium/headless/lib/virtual_time_browsertest.cc
index 3da3d0f2a0d..b856a72ce78 100644
--- a/chromium/headless/lib/virtual_time_browsertest.cc
+++ b/chromium/headless/lib/virtual_time_browsertest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include <memory>
+#include "base/strings/stringprintf.h"
#include "content/public/test/browser_test.h"
#include "headless/public/devtools/domains/emulation.h"
#include "headless/public/devtools/domains/page.h"
@@ -51,20 +52,26 @@ class VirtualTimeBrowserTest : public HeadlessAsyncDevTooledBrowserTest,
std::string message;
if (args.size() == 1u && args[0]->HasValue() &&
args[0]->GetValue()->GetAsString(&message)) {
- console_logs_.push_back(message);
+ log_.push_back(message);
}
}
// emulation::Observer implementation:
void OnVirtualTimeBudgetExpired(
const emulation::VirtualTimeBudgetExpiredParams& params) override {
- EXPECT_THAT(console_logs_,
- ElementsAre("step1", "step2", "step3", "step4", "pass"));
-
+ EXPECT_THAT(log_,
+ ElementsAre("Paused @ 0ms", "step1", "step2", "Paused @ 100ms",
+ "step3", "Paused @ 200ms", "step4", "pass"));
FinishAsynchronousTest();
}
- std::vector<std::string> console_logs_;
+ void OnVirtualTimePaused(
+ const emulation::VirtualTimePausedParams& params) override {
+ log_.push_back(
+ base::StringPrintf("Paused @ %dms", params.GetVirtualTimeElapsed()));
+ }
+
+ std::vector<std::string> log_;
};
HEADLESS_ASYNC_DEVTOOLED_TEST_F(VirtualTimeBrowserTest);
diff --git a/chromium/headless/public/headless_browser.cc b/chromium/headless/public/headless_browser.cc
index d70edaf62c4..497a8c7721d 100644
--- a/chromium/headless/public/headless_browser.cc
+++ b/chromium/headless/public/headless_browser.cc
@@ -84,6 +84,11 @@ Builder& Builder::SetUserAgent(const std::string& user_agent) {
return *this;
}
+Builder& Builder::SetAcceptLanguage(const std::string& accept_language) {
+ options_.accept_language = accept_language;
+ return *this;
+}
+
Builder& Builder::EnableDevToolsServer(const net::IPEndPoint& endpoint) {
options_.devtools_endpoint = endpoint;
return *this;
diff --git a/chromium/headless/public/headless_browser.h b/chromium/headless/public/headless_browser.h
index 63f6c747027..352a22818d5 100644
--- a/chromium/headless/public/headless_browser.h
+++ b/chromium/headless/public/headless_browser.h
@@ -149,6 +149,7 @@ struct HEADLESS_EXPORT HeadlessBrowser::Options {
// Default per-context options, can be specialized on per-context basis.
std::string product_name_and_version;
+ std::string accept_language;
std::string user_agent;
// The ProxyConfig to use. The system proxy settings are used by default.
@@ -215,6 +216,7 @@ class HEADLESS_EXPORT HeadlessBrowser::Options::Builder {
Builder& SetProductNameAndVersion(
const std::string& product_name_and_version);
+ Builder& SetAcceptLanguage(const std::string& accept_language);
Builder& SetUserAgent(const std::string& user_agent);
Builder& SetProxyConfig(std::unique_ptr<net::ProxyConfig> proxy_config);
Builder& SetHostResolverRules(const std::string& host_resolver_rules);
diff --git a/chromium/headless/public/headless_browser_context.h b/chromium/headless/public/headless_browser_context.h
index 0b2a002d8fb..6cb289f29c7 100644
--- a/chromium/headless/public/headless_browser_context.h
+++ b/chromium/headless/public/headless_browser_context.h
@@ -88,6 +88,9 @@ class HEADLESS_EXPORT HeadlessBrowserContext::Observer {
// thread.
virtual void UrlRequestFailed(net::URLRequest* request, int net_error) {}
+ // Indicates the HeadlessBrowserContext is about to be deleted.
+ virtual void OnHeadlessBrowserContextDestruct() {}
+
protected:
virtual ~Observer() {}
};
@@ -120,6 +123,7 @@ class HEADLESS_EXPORT HeadlessBrowserContext::Builder {
// settings. See HeadlessBrowser::Options for their meaning.
Builder& SetProductNameAndVersion(
const std::string& product_name_and_version);
+ Builder& SetAcceptLanguage(const std::string& accept_language);
Builder& SetUserAgent(const std::string& user_agent);
Builder& SetProxyConfig(std::unique_ptr<net::ProxyConfig> proxy_config);
Builder& SetHostResolverRules(const std::string& host_resolver_rules);
diff --git a/chromium/headless/public/headless_web_contents.h b/chromium/headless/public/headless_web_contents.h
index dae0d72c515..96259c3a194 100644
--- a/chromium/headless/public/headless_web_contents.h
+++ b/chromium/headless/public/headless_web_contents.h
@@ -90,8 +90,15 @@ class HEADLESS_EXPORT HeadlessWebContents {
int process_id,
int frame_tree_node_id) const = 0;
+ // Returns the FrameTreeNode id corresponding to |devtools_id| or -1 if it
+ // can't be found. Must be called on the IO thread.
+ virtual int GetFrameTreeNodeIdForDevToolsFrameId(
+ const std::string& devtools_id) const = 0;
+
virtual int GetMainFrameRenderProcessId() const = 0;
+ virtual int GetMainFrameTreeNodeId() const = 0;
+
private:
friend class HeadlessWebContentsImpl;
HeadlessWebContents() {}
diff --git a/chromium/headless/public/util/deterministic_http_protocol_handler.cc b/chromium/headless/public/util/deterministic_http_protocol_handler.cc
index 6235855973b..8ff8e37df81 100644
--- a/chromium/headless/public/util/deterministic_http_protocol_handler.cc
+++ b/chromium/headless/public/util/deterministic_http_protocol_handler.cc
@@ -22,11 +22,6 @@ class DeterministicHttpProtocolHandler::NopGenericURLRequestJobDelegate
NopGenericURLRequestJobDelegate() {}
~NopGenericURLRequestJobDelegate() override {}
- // GenericURLRequestJob::Delegate methods:
- void OnPendingRequest(PendingRequest* pending_request) override {
- pending_request->AllowRequest();
- }
-
void OnResourceLoadFailed(const Request* request, net::Error error) override {
}
diff --git a/chromium/headless/public/util/fontconfig.cc b/chromium/headless/public/util/fontconfig.cc
index d859c19063f..2f3cd0b8d7e 100644
--- a/chromium/headless/public/util/fontconfig.cc
+++ b/chromium/headless/public/util/fontconfig.cc
@@ -70,8 +70,8 @@ void InitFonts(const char* fontconfig_path) {
// stable across runs, otherwise replacement font picks are random
// and cause flakiness.
std::set<std::string> fonts;
- struct dirent entry, *result;
- while (readdir_r(fc_dir, &entry, &result) == 0 && result != NULL) {
+ struct dirent *result;
+ while ((result = readdir(fc_dir))) {
fonts.insert(result->d_name);
}
for (const std::string& font : fonts) {
diff --git a/chromium/headless/public/util/generic_url_request_job.cc b/chromium/headless/public/util/generic_url_request_job.cc
index 84344322f37..046499ce98c 100644
--- a/chromium/headless/public/util/generic_url_request_job.cc
+++ b/chromium/headless/public/util/generic_url_request_job.cc
@@ -8,6 +8,8 @@
#include <algorithm>
#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/resource_request_info.h"
@@ -22,6 +24,7 @@
#include "net/cookies/cookie_store.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
+#include "net/url_request/http_user_agent_settings.h"
#include "net/url_request/url_request_context.h"
namespace headless {
@@ -55,19 +58,35 @@ void GenericURLRequestJob::SetExtraRequestHeaders(
const net::HttpRequestHeaders& headers) {
DCHECK(origin_task_runner_->RunsTasksInCurrentSequence());
extra_request_headers_ = headers;
+
+ if (!request_->referrer().empty()) {
+ extra_request_headers_.SetHeader(net::HttpRequestHeaders::kReferer,
+ request_->referrer());
+ }
+
+ const net::HttpUserAgentSettings* user_agent_settings =
+ request()->context()->http_user_agent_settings();
+ if (user_agent_settings) {
+ // If set the |user_agent_settings| accept language is a fallback.
+ extra_request_headers_.SetHeaderIfMissing(
+ net::HttpRequestHeaders::kAcceptLanguage,
+ user_agent_settings->GetAcceptLanguage());
+ // If set the |user_agent_settings| user agent is an override.
+ if (!user_agent_settings->GetUserAgent().empty()) {
+ extra_request_headers_.SetHeader(net::HttpRequestHeaders::kUserAgent,
+ user_agent_settings->GetUserAgent());
+ }
+ }
}
void GenericURLRequestJob::Start() {
PrepareCookies(request_->url(), request_->method(),
- url::Origin(request_->first_party_for_cookies()),
- base::Bind(&Delegate::OnPendingRequest,
- base::Unretained(delegate_), this));
+ url::Origin(request_->site_for_cookies()));
}
void GenericURLRequestJob::PrepareCookies(const GURL& rewritten_url,
const std::string& method,
- const url::Origin& site_for_cookies,
- const base::Closure& done_callback) {
+ const url::Origin& site_for_cookies) {
DCHECK(origin_task_runner_->RunsTasksInCurrentSequence());
net::CookieStore* cookie_store = request_->context()->cookie_store();
net::CookieOptions options;
@@ -92,14 +111,12 @@ void GenericURLRequestJob::PrepareCookies(const GURL& rewritten_url,
cookie_store->GetCookieListWithOptionsAsync(
rewritten_url, options,
base::Bind(&GenericURLRequestJob::OnCookiesAvailable,
- weak_factory_.GetWeakPtr(), rewritten_url, method,
- done_callback));
+ weak_factory_.GetWeakPtr(), rewritten_url, method));
}
void GenericURLRequestJob::OnCookiesAvailable(
const GURL& rewritten_url,
const std::string& method,
- const base::Closure& done_callback,
const net::CookieList& cookie_list) {
DCHECK(origin_task_runner_->RunsTasksInCurrentSequence());
// TODO(alexclarke): Set user agent.
@@ -108,12 +125,7 @@ void GenericURLRequestJob::OnCookiesAvailable(
if (!cookie.empty())
extra_request_headers_.SetHeader(net::HttpRequestHeaders::kCookie, cookie);
- if (!request_->referrer().empty()) {
- extra_request_headers_.SetHeader(net::HttpRequestHeaders::kReferer,
- request_->referrer());
- }
-
- done_callback.Run();
+ url_fetcher_->StartFetch(this, this);
}
void GenericURLRequestJob::OnFetchStartError(net::Error error) {
@@ -126,12 +138,13 @@ void GenericURLRequestJob::OnFetchComplete(
const GURL& final_url,
scoped_refptr<net::HttpResponseHeaders> response_headers,
const char* body,
- size_t body_size) {
+ size_t body_size,
+ const net::LoadTimingInfo& load_timing_info) {
DCHECK(origin_task_runner_->RunsTasksInCurrentSequence());
- response_time_ = base::TimeTicks::Now();
response_headers_ = response_headers;
body_ = body;
body_size_ = body_size;
+ load_timing_info_ = load_timing_info;
DispatchHeadersComplete();
@@ -155,6 +168,10 @@ int GenericURLRequestJob::ReadRawData(net::IOBuffer* buf, int buf_size) {
void GenericURLRequestJob::GetResponseInfo(net::HttpResponseInfo* info) {
info->headers = response_headers_;
+
+ // Important we need to set this so we can detect if a navigation request got
+ // canceled by DevTools.
+ info->network_accessed = true;
}
bool GenericURLRequestJob::GetMimeType(std::string* mime_type) const {
@@ -171,8 +188,7 @@ bool GenericURLRequestJob::GetCharset(std::string* charset) {
void GenericURLRequestJob::GetLoadTimingInfo(
net::LoadTimingInfo* load_timing_info) const {
- // TODO(alexclarke): Investigate setting the other members too where possible.
- load_timing_info->receive_headers_end = response_time_;
+ *load_timing_info = load_timing_info_;
}
uint64_t GenericURLRequestJob::GenericURLRequestJob::GetRequestId() const {
@@ -183,6 +199,11 @@ const net::URLRequest* GenericURLRequestJob::GetURLRequest() const {
return request_;
}
+const net::HttpRequestHeaders& GenericURLRequestJob::GetHttpRequestHeaders()
+ const {
+ return extra_request_headers_;
+}
+
int GenericURLRequestJob::GetFrameTreeNodeId() const {
// URLRequestUserData will be set for all renderer initiated resource
// requests, but not for browser side navigations.
@@ -265,6 +286,13 @@ bool GenericURLRequestJob::IsAsync() const {
return true;
}
+namespace {
+void CompletionCallback(int* dest, base::Closure* quit_closure, int value) {
+ *dest = value;
+ quit_closure->Run();
+}
+} // namespace
+
std::string GenericURLRequestJob::GetPostData() const {
if (!request_->has_upload())
return "";
@@ -277,76 +305,80 @@ std::string GenericURLRequestJob::GetPostData() const {
return "";
DCHECK_EQ(1u, stream->GetElementReaders()->size());
- const net::UploadBytesElementReader* reader =
- (*stream->GetElementReaders())[0]->AsBytesReader();
- if (!reader)
- return "";
- return std::string(reader->bytes(), reader->length());
-}
-
-const Request* GenericURLRequestJob::GetRequest() const {
- return this;
-}
+ const std::unique_ptr<net::UploadElementReader>& reader =
+ (*stream->GetElementReaders())[0];
+ // If |reader| is actually an UploadBytesElementReader we can get the data
+ // directly (should be faster than the horrible stuff below).
+ const net::UploadBytesElementReader* bytes_reader = reader->AsBytesReader();
+ if (bytes_reader)
+ return std::string(bytes_reader->bytes(), bytes_reader->length());
+
+ // TODO(alexclarke): Consider changing the interface of
+ // GenericURLRequestJob::GetPostData to use a callback which would let us
+ // avoid the nested run loops below.
+
+ // Initialize the reader.
+ {
+ base::Closure quit_closure;
+ int init_result = reader->Init(
+ base::Bind(&CompletionCallback, &init_result, &quit_closure));
+ if (init_result == net::ERR_IO_PENDING) {
+ base::RunLoop nested_run_loop;
+ base::MessageLoop::ScopedNestableTaskAllower allow_nested(
+ base::MessageLoop::current());
+ quit_closure = nested_run_loop.QuitClosure();
+ nested_run_loop.Run();
+ }
-void GenericURLRequestJob::AllowRequest() {
- if (!origin_task_runner_->RunsTasksInCurrentSequence()) {
- origin_task_runner_->PostTask(
- FROM_HERE, base::Bind(&GenericURLRequestJob::AllowRequest,
- weak_factory_.GetWeakPtr()));
- return;
+ if (init_result != net::OK)
+ return "";
}
- url_fetcher_->StartFetch(request_->url(), request_->method(), GetPostData(),
- extra_request_headers_, this);
-}
-
-void GenericURLRequestJob::BlockRequest(net::Error error) {
- if (!origin_task_runner_->RunsTasksInCurrentSequence()) {
- origin_task_runner_->PostTask(
- FROM_HERE, base::Bind(&GenericURLRequestJob::BlockRequest,
- weak_factory_.GetWeakPtr(), error));
- return;
- }
+ // Read the POST bytes.
+ uint64_t content_length = reader->GetContentLength();
+ std::string post_data;
+ post_data.reserve(content_length);
+ const size_t block_size = 1024;
+ scoped_refptr<net::IOBuffer> read_buffer(new net::IOBuffer(block_size));
+ while (post_data.size() < content_length) {
+ base::Closure quit_closure;
+ int bytes_read = reader->Read(
+ read_buffer.get(), block_size,
+ base::Bind(&CompletionCallback, &bytes_read, &quit_closure));
+
+ if (bytes_read == net::ERR_IO_PENDING) {
+ base::MessageLoop::ScopedNestableTaskAllower allow_nested(
+ base::MessageLoop::current());
+ base::RunLoop nested_run_loop;
+ quit_closure = nested_run_loop.QuitClosure();
+ nested_run_loop.Run();
+ }
- DispatchStartError(error);
-}
+ // Bail out if an error occured.
+ if (bytes_read < 0)
+ return "";
-void GenericURLRequestJob::ModifyRequest(
- const GURL& url,
- const std::string& method,
- const std::string& post_data,
- const net::HttpRequestHeaders& request_headers) {
- if (!origin_task_runner_->RunsTasksInCurrentSequence()) {
- origin_task_runner_->PostTask(
- FROM_HERE, base::Bind(&GenericURLRequestJob::ModifyRequest,
- weak_factory_.GetWeakPtr(), url, method,
- post_data, request_headers));
- return;
+ post_data.append(read_buffer->data(), bytes_read);
}
- extra_request_headers_ = request_headers;
- PrepareCookies(
- request_->url(), request_->method(),
- url::Origin(request_->first_party_for_cookies()),
- base::Bind(&URLFetcher::StartFetch, base::Unretained(url_fetcher_.get()),
- url, method, post_data, request_headers, this));
+ return post_data;
}
-void GenericURLRequestJob::MockResponse(
- std::unique_ptr<MockResponseData> mock_response) {
- if (!origin_task_runner_->RunsTasksInCurrentSequence()) {
- origin_task_runner_->PostTask(
- FROM_HERE, base::Bind(&GenericURLRequestJob::MockResponse,
- weak_factory_.GetWeakPtr(),
- base::Passed(std::move(mock_response))));
- return;
- }
+uint64_t GenericURLRequestJob::GetPostDataSize() const {
+ if (!request_->has_upload())
+ return 0;
- mock_response_ = std::move(mock_response);
+ const net::UploadDataStream* stream = request_->get_upload();
+ if (!stream->GetElementReaders())
+ return 0;
+
+ if (stream->GetElementReaders()->size() == 0)
+ return 0;
- OnFetchCompleteExtractHeaders(request_->url(),
- mock_response_->response_data.data(),
- mock_response_->response_data.size());
+ DCHECK_EQ(1u, stream->GetElementReaders()->size());
+ const std::unique_ptr<net::UploadElementReader>& reader =
+ (*stream->GetElementReaders())[0];
+ return reader->GetContentLength();
}
} // namespace headless
diff --git a/chromium/headless/public/util/generic_url_request_job.h b/chromium/headless/public/util/generic_url_request_job.h
index 434de842028..c05b452eac7 100644
--- a/chromium/headless/public/util/generic_url_request_job.h
+++ b/chromium/headless/public/util/generic_url_request_job.h
@@ -42,6 +42,8 @@ class HEADLESS_EXPORT Request {
virtual const net::URLRequest* GetURLRequest() const = 0;
+ virtual const net::HttpRequestHeaders& GetHttpRequestHeaders() const = 0;
+
// The frame from which the request came from.
virtual int GetFrameTreeNodeId() const = 0;
@@ -51,6 +53,9 @@ class HEADLESS_EXPORT Request {
// Gets the POST data, if any, from the net::URLRequest.
virtual std::string GetPostData() const = 0;
+ // Returns the size of the POST data, if any, from the net::URLRequest.
+ virtual uint64_t GetPostDataSize() const = 0;
+
enum class ResourceType {
MAIN_FRAME = 0,
SUB_FRAME = 1,
@@ -86,41 +91,6 @@ class HEADLESS_EXPORT Request {
DISALLOW_COPY_AND_ASSIGN(Request);
};
-// Details of a pending request received by GenericURLRequestJob which must be
-// either Allowed, Blocked, Modified or have it's response Mocked.
-class HEADLESS_EXPORT PendingRequest {
- public:
- virtual const Request* GetRequest() const = 0;
-
- // Allows the request to proceed as normal.
- virtual void AllowRequest() = 0;
-
- // Causes the request to fail with the specified |error|.
- virtual void BlockRequest(net::Error error) = 0;
-
- // Allows the request to be completely re-written.
- virtual void ModifyRequest(
- const GURL& url,
- const std::string& method,
- const std::string& post_data,
- const net::HttpRequestHeaders& request_headers) = 0;
-
- struct MockResponseData {
- std::string response_data;
- };
-
- // Instead of fetching the request, |mock_response| is returned instead.
- virtual void MockResponse(
- std::unique_ptr<MockResponseData> mock_response) = 0;
-
- protected:
- PendingRequest() {}
- virtual ~PendingRequest() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PendingRequest);
-};
-
// Intended for use in a protocol handler, this ManagedDispatchURLRequestJob has
// the following features:
//
@@ -130,16 +100,10 @@ class HEADLESS_EXPORT PendingRequest {
class HEADLESS_EXPORT GenericURLRequestJob
: public ManagedDispatchURLRequestJob,
public URLFetcher::ResultListener,
- public PendingRequest,
public Request {
public:
class HEADLESS_EXPORT Delegate {
public:
- // Notifies the delegate of an PendingRequest which must either be
- // allowed, blocked, modifed or it's response mocked. Called on an arbitrary
- // thread.
- virtual void OnPendingRequest(PendingRequest* pending_request) = 0;
-
// Notifies the delegate of any fetch failure. Called on an arbitrary
// thread.
virtual void OnResourceLoadFailed(const Request* request,
@@ -176,55 +140,45 @@ class HEADLESS_EXPORT GenericURLRequestJob
bool GetCharset(std::string* charset) override;
void GetLoadTimingInfo(net::LoadTimingInfo* load_timing_info) const override;
- // URLFetcher::FetchResultListener implementation:
+ // URLFetcher::ResultListener implementation:
void OnFetchStartError(net::Error error) override;
void OnFetchComplete(const GURL& final_url,
scoped_refptr<net::HttpResponseHeaders> response_headers,
const char* body,
- size_t body_size) override;
+ size_t body_size,
+ const net::LoadTimingInfo& load_timing_info) override;
protected:
// Request implementation:
uint64_t GetRequestId() const override;
+ const net::HttpRequestHeaders& GetHttpRequestHeaders() const override;
const net::URLRequest* GetURLRequest() const override;
int GetFrameTreeNodeId() const override;
std::string GetDevToolsAgentHostId() const override;
std::string GetPostData() const override;
+ uint64_t GetPostDataSize() const override;
ResourceType GetResourceType() const override;
bool IsAsync() const override;
- // PendingRequest implementation:
- const Request* GetRequest() const override;
- void AllowRequest() override;
- void BlockRequest(net::Error error) override;
- void ModifyRequest(const GURL& url,
- const std::string& method,
- const std::string& post_data,
- const net::HttpRequestHeaders& request_headers) override;
- void MockResponse(std::unique_ptr<MockResponseData> mock_response) override;
-
private:
void PrepareCookies(const GURL& rewritten_url,
const std::string& method,
- const url::Origin& site_for_cookies,
- const base::Closure& done_callback);
+ const url::Origin& site_for_cookies);
void OnCookiesAvailable(const GURL& rewritten_url,
const std::string& method,
- const base::Closure& done_callback,
const net::CookieList& cookie_list);
std::unique_ptr<URLFetcher> url_fetcher_;
net::HttpRequestHeaders extra_request_headers_;
scoped_refptr<net::HttpResponseHeaders> response_headers_;
scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
- std::unique_ptr<MockResponseData> mock_response_;
Delegate* delegate_; // Not owned.
HeadlessBrowserContext* headless_browser_context_; // Not owned.
const content::ResourceRequestInfo* request_resource_info_; // Not owned.
const char* body_ = nullptr; // Not owned.
size_t body_size_ = 0;
size_t read_offset_ = 0;
- base::TimeTicks response_time_;
+ net::LoadTimingInfo load_timing_info_;
const uint64_t request_id_;
static uint64_t next_request_id_;
diff --git a/chromium/headless/public/util/generic_url_request_job_test.cc b/chromium/headless/public/util/generic_url_request_job_test.cc
index faf0bd65845..23b3f34441f 100644
--- a/chromium/headless/public/util/generic_url_request_job_test.cc
+++ b/chromium/headless/public/util/generic_url_request_job_test.cc
@@ -23,13 +23,14 @@
#include "net/base/upload_bytes_element_reader.h"
#include "net/http/http_response_headers.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "net/url_request/static_http_user_agent_settings.h"
#include "net/url_request/url_request_job_factory_impl.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
-std::ostream& operator<<(std::ostream& os, const base::Value& value) {
+std::ostream& operator<<(std::ostream& os, const base::DictionaryValue& value) {
std::string json;
base::JSONWriter::WriteWithOptions(
value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
@@ -56,29 +57,34 @@ class MockDelegate : public MockGenericURLRequestJobDelegate {
class MockFetcher : public URLFetcher {
public:
MockFetcher(base::DictionaryValue* fetch_request,
- std::map<std::string, std::string>* json_fetch_reply_map)
+ std::map<std::string, std::string>* json_fetch_reply_map,
+ base::Callback<void(const Request*)>* on_request_callback)
: json_fetch_reply_map_(json_fetch_reply_map),
- fetch_request_(fetch_request) {}
+ fetch_request_(fetch_request),
+ on_request_callback_(on_request_callback) {}
~MockFetcher() override {}
- void StartFetch(const GURL& url,
- const std::string& method,
- const std::string& post_data,
- const net::HttpRequestHeaders& request_headers,
+ void StartFetch(const Request* request,
ResultListener* result_listener) override {
+ if (!on_request_callback_->is_null())
+ on_request_callback_->Run(request);
+
// Record the request.
- fetch_request_->SetString("url", url.spec());
- fetch_request_->SetString("method", method);
+ std::string url = request->GetURLRequest()->url().spec();
+ fetch_request_->SetString("url", url);
+ fetch_request_->SetString("method", request->GetURLRequest()->method());
std::unique_ptr<base::DictionaryValue> headers(new base::DictionaryValue);
- for (net::HttpRequestHeaders::Iterator it(request_headers); it.GetNext();) {
+ for (net::HttpRequestHeaders::Iterator it(request->GetHttpRequestHeaders());
+ it.GetNext();) {
headers->SetString(it.name(), it.value());
}
fetch_request_->Set("headers", std::move(headers));
+ std::string post_data = request->GetPostData();
if (!post_data.empty())
- fetch_request_->SetString("post_data", post_data);
+ fetch_request_->SetString("post_data", std::move(post_data));
- const auto find_it = json_fetch_reply_map_->find(url.spec());
+ const auto find_it = json_fetch_reply_map_->find(url);
if (find_it == json_fetch_reply_map_->end()) {
result_listener->OnFetchStartError(net::ERR_ADDRESS_UNREACHABLE);
return;
@@ -107,14 +113,20 @@ class MockFetcher : public URLFetcher {
base::StringPrintf("%s: %s", it.key().c_str(), value.c_str()));
}
+ // Set the fields needed for tracing, so that we can check
+ // if they are forwarded correctly.
+ net::LoadTimingInfo load_timing_info;
+ load_timing_info.send_start = base::TimeTicks::Max();
+ load_timing_info.receive_headers_end = base::TimeTicks::Max();
result_listener->OnFetchComplete(
GURL(final_url), std::move(response_headers), response_data_.c_str(),
- response_data_.size());
+ response_data_.size(), load_timing_info);
}
private:
std::map<std::string, std::string>* json_fetch_reply_map_; // NOT OWNED
- base::DictionaryValue* fetch_request_; // NOT OWNED
+ base::DictionaryValue* fetch_request_; // NOT OWNED
+ base::Callback<void(const Request*)>* on_request_callback_; // NOT OWNED
std::string response_data_; // Here to ensure the required lifetime.
};
@@ -125,11 +137,13 @@ class MockProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler {
MockProtocolHandler(base::DictionaryValue* fetch_request,
std::map<std::string, std::string>* json_fetch_reply_map,
URLRequestDispatcher* dispatcher,
- GenericURLRequestJob::Delegate* job_delegate)
+ GenericURLRequestJob::Delegate* job_delegate,
+ base::Callback<void(const Request*)>* on_request_callback)
: fetch_request_(fetch_request),
json_fetch_reply_map_(json_fetch_reply_map),
job_delegate_(job_delegate),
- dispatcher_(dispatcher) {}
+ dispatcher_(dispatcher),
+ on_request_callback_(on_request_callback) {}
// net::URLRequestJobFactory::ProtocolHandler override.
net::URLRequestJob* MaybeCreateJob(
@@ -137,15 +151,17 @@ class MockProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler {
net::NetworkDelegate* network_delegate) const override {
return new GenericURLRequestJob(
request, network_delegate, dispatcher_,
- base::MakeUnique<MockFetcher>(fetch_request_, json_fetch_reply_map_),
+ base::MakeUnique<MockFetcher>(fetch_request_, json_fetch_reply_map_,
+ on_request_callback_),
job_delegate_, nullptr);
}
private:
- base::DictionaryValue* fetch_request_; // NOT OWNED
- std::map<std::string, std::string>* json_fetch_reply_map_; // NOT OWNED
- GenericURLRequestJob::Delegate* job_delegate_; // NOT OWNED
- URLRequestDispatcher* dispatcher_; // NOT OWNED
+ base::DictionaryValue* fetch_request_; // NOT OWNED
+ std::map<std::string, std::string>* json_fetch_reply_map_; // NOT OWNED
+ GenericURLRequestJob::Delegate* job_delegate_; // NOT OWNED
+ URLRequestDispatcher* dispatcher_; // NOT OWNED
+ base::Callback<void(const Request*)>* on_request_callback_; // NOT OWNED
};
} // namespace
@@ -156,7 +172,7 @@ class GenericURLRequestJobTest : public testing::Test {
url_request_job_factory_.SetProtocolHandler(
"https", base::WrapUnique(new MockProtocolHandler(
&fetch_request_, &json_fetch_reply_map_, &dispatcher_,
- &job_delegate_)));
+ &job_delegate_, &on_request_callback_)));
url_request_context_.set_job_factory(&url_request_job_factory_);
url_request_context_.set_cookie_store(&cookie_store_);
}
@@ -206,9 +222,12 @@ class GenericURLRequestJobTest : public testing::Test {
std::map<std::string, std::string>
json_fetch_reply_map_; // Replies to be sent by MockFetcher.
MockDelegate job_delegate_;
+ base::Callback<void(const Request*)> on_request_callback_;
};
TEST_F(GenericURLRequestJobTest, BasicGetRequestParams) {
+ net::StaticHttpUserAgentSettings user_agent_settings("en-UK", "TestBrowser");
+
json_fetch_reply_map_["https://example.com/"] = R"(
{
"url": "https://example.com",
@@ -218,13 +237,12 @@ TEST_F(GenericURLRequestJobTest, BasicGetRequestParams) {
}
})";
+ url_request_context_.set_http_user_agent_settings(&user_agent_settings);
std::unique_ptr<net::URLRequest> request(url_request_context_.CreateRequest(
GURL("https://example.com"), net::DEFAULT_PRIORITY, &request_delegate_,
TRAFFIC_ANNOTATION_FOR_TESTS));
request->SetReferrer("https://referrer.example.com");
request->SetExtraRequestHeaderByName("Extra-Header", "Value", true);
- request->SetExtraRequestHeaderByName("User-Agent", "TestBrowser", true);
- request->SetExtraRequestHeaderByName("Accept", "text/plain", true);
request->Start();
base::RunLoop().RunUntilIdle();
@@ -233,7 +251,7 @@ TEST_F(GenericURLRequestJobTest, BasicGetRequestParams) {
"url": "https://example.com/",
"method": "GET",
"headers": {
- "Accept": "text/plain",
+ "Accept-Language": "en-UK",
"Extra-Header": "Value",
"Referer": "https://referrer.example.com/",
"User-Agent": "TestBrowser"
@@ -337,7 +355,10 @@ TEST_F(GenericURLRequestJobTest, BasicRequestContents) {
net::LoadTimingInfo load_timing_info;
request->GetLoadTimingInfo(&load_timing_info);
- EXPECT_FALSE(load_timing_info.receive_headers_end.is_null());
+ // Check that the send_start and receive_headers_end timings are
+ // forwarded correctly, as they are used by tracing.
+ EXPECT_EQ(base::TimeTicks::Max(), load_timing_info.send_start);
+ EXPECT_EQ(base::TimeTicks::Max(), load_timing_info.receive_headers_end);
}
TEST_F(GenericURLRequestJobTest, ReadInParts) {
@@ -451,159 +472,6 @@ TEST_F(GenericURLRequestJobTest, RequestWithCookies) {
EXPECT_THAT(fetch_request_, MatchesJson(expected_request_json));
}
-TEST_F(GenericURLRequestJobTest, DelegateBlocksLoading) {
- std::string reply = R"(
- {
- "url": "https://example.com",
- "data": "Reply",
- "headers": {
- "Content-Type": "text/html; charset=UTF-8"
- }
- })";
-
- job_delegate_.SetPolicy(base::Bind([](PendingRequest* pending_request) {
- pending_request->BlockRequest(net::ERR_FILE_NOT_FOUND);
- }));
-
- std::unique_ptr<net::URLRequest> request(
- CreateAndCompleteGetJob(GURL("https://example.com"), reply));
-
- EXPECT_EQ(net::URLRequestStatus::FAILED, request->status().status());
- EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request->status().error());
-}
-
-TEST_F(GenericURLRequestJobTest, DelegateModifiesRequest) {
- json_fetch_reply_map_["https://example.com/"] = R"(
- {
- "url": "https://example.com",
- "data": "Welcome to example.com",
- "headers": {
- "Content-Type": "text/html; charset=UTF-8"
- }
- })";
-
- json_fetch_reply_map_["https://othersite.com/"] = R"(
- {
- "url": "https://example.com",
- "data": "Welcome to othersite.com",
- "headers": {
- "Content-Type": "text/html; charset=UTF-8"
- }
- })";
-
- // Turn the GET into a POST to a different site.
- job_delegate_.SetPolicy(base::Bind([](PendingRequest* pending_request) {
- net::HttpRequestHeaders headers;
- headers.SetHeader("TestHeader", "Hello");
- pending_request->ModifyRequest(GURL("https://othersite.com"), "POST",
- "Some post data!", headers);
- }));
-
- std::unique_ptr<net::URLRequest> request(url_request_context_.CreateRequest(
- GURL("https://example.com"), net::DEFAULT_PRIORITY, &request_delegate_,
- TRAFFIC_ANNOTATION_FOR_TESTS));
- request->Start();
- base::RunLoop().RunUntilIdle();
-
- std::string expected_request_json = R"(
- {
- "url": "https://othersite.com/",
- "method": "POST",
- "post_data": "Some post data!",
- "headers": {
- "TestHeader": "Hello"
- }
- })";
-
- EXPECT_THAT(fetch_request_, MatchesJson(expected_request_json));
-
- EXPECT_EQ(200, request->GetResponseCode());
- // The modification should not be visible to the URlRequest.
- EXPECT_EQ("https://example.com/", request->url().spec());
- EXPECT_EQ("GET", request->method());
-
- const int kBufferSize = 256;
- scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));
- int bytes_read;
- EXPECT_TRUE(request->Read(buffer.get(), kBufferSize, &bytes_read));
- EXPECT_EQ(24, bytes_read);
- EXPECT_EQ("Welcome to othersite.com",
- std::string(buffer->data(), bytes_read));
-}
-
-TEST_F(GenericURLRequestJobTest, DelegateMocks404Response) {
- std::string reply = R"(
- {
- "url": "https://example.com",
- "data": "Reply",
- "headers": {
- "Content-Type": "text/html; charset=UTF-8"
- }
- })";
-
- job_delegate_.SetPolicy(base::Bind([](PendingRequest* pending_request) {
- std::unique_ptr<GenericURLRequestJob::MockResponseData> mock_response_data(
- new GenericURLRequestJob::MockResponseData());
- mock_response_data->response_data = "HTTP/1.1 404 Not Found\r\n\r\n";
- pending_request->MockResponse(std::move(mock_response_data));
- }));
-
- std::unique_ptr<net::URLRequest> request(
- CreateAndCompleteGetJob(GURL("https://example.com"), reply));
-
- EXPECT_EQ(404, request->GetResponseCode());
-}
-
-TEST_F(GenericURLRequestJobTest, DelegateMocks302Response) {
- job_delegate_.SetPolicy(base::Bind([](PendingRequest* pending_request) {
- if (pending_request->GetRequest()->GetURLRequest()->url().spec() ==
- "https://example.com/") {
- std::unique_ptr<GenericURLRequestJob::MockResponseData>
- mock_response_data(new GenericURLRequestJob::MockResponseData());
- mock_response_data->response_data =
- "HTTP/1.1 302 Found\r\n"
- "Location: https://foo.com/\r\n\r\n";
- pending_request->MockResponse(std::move(mock_response_data));
- } else {
- pending_request->AllowRequest();
- }
- }));
-
- json_fetch_reply_map_["https://example.com/"] = R"(
- {
- "url": "https://example.com",
- "data": "Welcome to example.com",
- "headers": {
- "Content-Type": "text/html; charset=UTF-8"
- }
- })";
-
- json_fetch_reply_map_["https://foo.com/"] = R"(
- {
- "url": "https://example.com",
- "data": "Welcome to foo.com",
- "headers": {
- "Content-Type": "text/html; charset=UTF-8"
- }
- })";
-
- std::unique_ptr<net::URLRequest> request(url_request_context_.CreateRequest(
- GURL("https://example.com"), net::DEFAULT_PRIORITY, &request_delegate_,
- TRAFFIC_ANNOTATION_FOR_TESTS));
- request->Start();
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(200, request->GetResponseCode());
- EXPECT_EQ("https://foo.com/", request->url().spec());
-
- const int kBufferSize = 256;
- scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));
- int bytes_read;
- EXPECT_TRUE(request->Read(buffer.get(), kBufferSize, &bytes_read));
- EXPECT_EQ(18, bytes_read);
- EXPECT_EQ("Welcome to foo.com", std::string(buffer->data(), bytes_read));
-}
-
TEST_F(GenericURLRequestJobTest, OnResourceLoadFailed) {
EXPECT_CALL(job_delegate_,
OnResourceLoadFailed(_, net::ERR_ADDRESS_UNREACHABLE));
@@ -627,12 +495,11 @@ TEST_F(GenericURLRequestJobTest, RequestsHaveDistinctIds) {
})";
std::set<uint64_t> ids;
- job_delegate_.SetPolicy(base::Bind(
- [](std::set<uint64_t>* ids, PendingRequest* pending_request) {
- ids->insert(pending_request->GetRequest()->GetRequestId());
- pending_request->AllowRequest();
+ on_request_callback_ = base::Bind(
+ [](std::set<uint64_t>* ids, const Request* request) {
+ ids->insert(request->GetRequestId());
},
- &ids));
+ &ids);
CreateAndCompleteGetJob(GURL("https://example.com"), reply);
CreateAndCompleteGetJob(GURL("https://example.com"), reply);
@@ -654,16 +521,105 @@ TEST_F(GenericURLRequestJobTest, GetPostData) {
})";
std::string post_data;
- job_delegate_.SetPolicy(base::Bind(
- [](std::string* post_data, PendingRequest* pending_request) {
- *post_data = pending_request->GetRequest()->GetPostData();
- pending_request->AllowRequest();
+ uint64_t post_data_size;
+ on_request_callback_ = base::Bind(
+ [](std::string* post_data, uint64_t* post_data_size,
+ const Request* request) {
+ *post_data = request->GetPostData();
+ *post_data_size = request->GetPostDataSize();
},
- &post_data));
+ &post_data, &post_data_size);
CreateAndCompletePostJob(GURL("https://example.com"), "payload", reply);
EXPECT_EQ("payload", post_data);
+ EXPECT_EQ(post_data_size, post_data.size());
+}
+
+namespace {
+class ByteAtATimeUploadElementReader : public net::UploadElementReader {
+ public:
+ explicit ByteAtATimeUploadElementReader(const std::string& content)
+ : content_(content) {}
+
+ // net::UploadElementReader implementation:
+ int Init(const net::CompletionCallback& callback) override {
+ offset_ = 0;
+ return net::OK;
+ }
+
+ uint64_t GetContentLength() const override { return content_.size(); }
+
+ uint64_t BytesRemaining() const override { return content_.size() - offset_; }
+
+ bool IsInMemory() const override { return false; }
+
+ int Read(net::IOBuffer* buf,
+ int buf_length,
+ const net::CompletionCallback& callback) override {
+ if (!BytesRemaining())
+ return net::OK;
+
+ base::MessageLoop::current()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&ByteAtATimeUploadElementReader::ReadImpl,
+ base::Unretained(this), make_scoped_refptr(buf),
+ buf_length, callback));
+ return net::ERR_IO_PENDING;
+ }
+
+ private:
+ void ReadImpl(scoped_refptr<net::IOBuffer> buf,
+ int buf_length,
+ const net::CompletionCallback callback) {
+ if (BytesRemaining()) {
+ *buf->data() = content_[offset_++];
+ callback.Run(1u);
+ } else {
+ callback.Run(0u);
+ }
+ }
+
+ std::string content_;
+ uint64_t offset_ = 0;
+};
+} // namespace
+
+TEST_F(GenericURLRequestJobTest, GetPostDataAsync) {
+ std::string json_reply = R"(
+ {
+ "url": "https://example.com",
+ "http_response_code": 200,
+ "data": "Reply",
+ "headers": {
+ "Content-Type": "text/html; charset=UTF-8"
+ }
+ })";
+
+ std::string post_data;
+ uint64_t post_data_size;
+ on_request_callback_ = base::Bind(
+ [](std::string* post_data, uint64_t* post_data_size,
+ const Request* request) {
+ *post_data = request->GetPostData();
+ *post_data_size = request->GetPostDataSize();
+ },
+ &post_data, &post_data_size);
+
+ GURL url("https://example.com");
+ std::unique_ptr<net::URLRequest> request(url_request_context_.CreateRequest(
+ url, net::DEFAULT_PRIORITY, &request_delegate_,
+ TRAFFIC_ANNOTATION_FOR_TESTS));
+ request->set_method("POST");
+
+ json_fetch_reply_map_[url.spec()] = json_reply;
+
+ request->set_upload(net::ElementsUploadDataStream::CreateWithReader(
+ base::MakeUnique<ByteAtATimeUploadElementReader>("payload"), 0));
+ request->Start();
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ("payload", post_data);
+ EXPECT_EQ(post_data_size, post_data.size());
}
} // namespace headless
diff --git a/chromium/headless/public/util/http_url_fetcher.cc b/chromium/headless/public/util/http_url_fetcher.cc
index 1781f3b7ae6..20e44ea93de 100644
--- a/chromium/headless/public/util/http_url_fetcher.cc
+++ b/chromium/headless/public/util/http_url_fetcher.cc
@@ -4,6 +4,7 @@
#include "headless/public/util/http_url_fetcher.h"
+#include "headless/public/util/generic_url_request_job.h"
#include "net/base/elements_upload_data_stream.h"
#include "net/base/io_buffer.h"
#include "net/base/upload_bytes_element_reader.h"
@@ -33,7 +34,7 @@ constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
destination: OTHER
}
policy {
- cookies_allowed: true
+ cookies_allowed: YES
cookies_store:
"Various, but cookies stores are deleted when session ends."
setting:
@@ -211,12 +212,16 @@ void HttpURLFetcher::Delegate::OnResponseCompleted(net::URLRequest* request,
return;
}
+ // Extract LoadTimingInfo from the request to pass to the result listener.
+ net::LoadTimingInfo load_timing_info;
+ request->GetLoadTimingInfo(&load_timing_info);
+
// TODO(alexclarke) apart from the headers there's a lot of stuff in
// |request->response_info()| that we drop here. Find a way to pipe it
// through.
result_listener_->OnFetchComplete(
request->url(), request->response_info().headers,
- bytes_read_so_far_.c_str(), bytes_read_so_far_.size());
+ bytes_read_so_far_.c_str(), bytes_read_so_far_.size(), load_timing_info);
}
HttpURLFetcher::HttpURLFetcher(
@@ -225,14 +230,12 @@ HttpURLFetcher::HttpURLFetcher(
HttpURLFetcher::~HttpURLFetcher() {}
-void HttpURLFetcher::StartFetch(const GURL& rewritten_url,
- const std::string& method,
- const std::string& post_data,
- const net::HttpRequestHeaders& request_headers,
+void HttpURLFetcher::StartFetch(const Request* request,
ResultListener* result_listener) {
- delegate_.reset(new Delegate(rewritten_url, method, post_data,
- request_headers, url_request_context_,
- result_listener));
+ delegate_.reset(new Delegate(
+ request->GetURLRequest()->url(), request->GetURLRequest()->method(),
+ request->GetPostData(), request->GetHttpRequestHeaders(),
+ url_request_context_, result_listener));
}
} // namespace headless
diff --git a/chromium/headless/public/util/http_url_fetcher.h b/chromium/headless/public/util/http_url_fetcher.h
index c69d9fb201e..70bb710ba5d 100644
--- a/chromium/headless/public/util/http_url_fetcher.h
+++ b/chromium/headless/public/util/http_url_fetcher.h
@@ -22,10 +22,7 @@ class HttpURLFetcher : public URLFetcher {
~HttpURLFetcher() override;
// URLFetcher implementation:
- void StartFetch(const GURL& rewritten_url,
- const std::string& method,
- const std::string& post_data,
- const net::HttpRequestHeaders& request_headers,
+ void StartFetch(const Request* request,
ResultListener* result_listener) override;
private:
diff --git a/chromium/headless/public/util/navigation_request.h b/chromium/headless/public/util/navigation_request.h
index cd28f10dd93..06e017f5e8b 100644
--- a/chromium/headless/public/util/navigation_request.h
+++ b/chromium/headless/public/util/navigation_request.h
@@ -10,8 +10,7 @@
namespace headless {
// While the actual details of the navigation processing are left undefined,
-// it's anticipated implementations will use devtools Page.setControlNavigations
-// and Page.processNavigation commands.
+// it's anticipated implementations will use Network.requestIntercepted event.
class NavigationRequest {
public:
NavigationRequest() {}
diff --git a/chromium/headless/public/util/testing/generic_url_request_mocks.cc b/chromium/headless/public/util/testing/generic_url_request_mocks.cc
index 844945c0a98..c811651ec15 100644
--- a/chromium/headless/public/util/testing/generic_url_request_mocks.cc
+++ b/chromium/headless/public/util/testing/generic_url_request_mocks.cc
@@ -22,28 +22,6 @@ MockGenericURLRequestJobDelegate::MockGenericURLRequestJobDelegate()
MockGenericURLRequestJobDelegate::~MockGenericURLRequestJobDelegate() {}
-// GenericURLRequestJob::Delegate methods:
-void MockGenericURLRequestJobDelegate::OnPendingRequest(
- PendingRequest* pending_request) {
- // Simulate the client acknowledging the callback from a different thread.
- main_thread_task_runner_->PostTask(
- FROM_HERE, base::Bind(&MockGenericURLRequestJobDelegate::ApplyPolicy,
- base::Unretained(this), pending_request));
-}
-
-void MockGenericURLRequestJobDelegate::SetPolicy(Policy policy) {
- policy_ = std::move(policy);
-}
-
-void MockGenericURLRequestJobDelegate::ApplyPolicy(
- PendingRequest* pending_request) {
- if (policy_.is_null()) {
- pending_request->AllowRequest();
- } else {
- policy_.Run(pending_request);
- }
-}
-
void MockGenericURLRequestJobDelegate::OnResourceLoadFailed(
const Request* request,
net::Error error) {}
@@ -159,6 +137,13 @@ MockCookieStore::AddCallbackForCookie(const GURL& url,
return nullptr;
}
+std::unique_ptr<net::CookieStore::CookieChangedSubscription>
+MockCookieStore::AddCallbackForAllChanges(
+ const CookieChangedCallback& callback) {
+ CHECK(false);
+ return nullptr;
+}
+
bool MockCookieStore::IsEphemeral() {
CHECK(false);
return true;
diff --git a/chromium/headless/public/util/testing/generic_url_request_mocks.h b/chromium/headless/public/util/testing/generic_url_request_mocks.h
index 96b49651deb..565a138a02d 100644
--- a/chromium/headless/public/util/testing/generic_url_request_mocks.h
+++ b/chromium/headless/public/util/testing/generic_url_request_mocks.h
@@ -26,7 +26,6 @@ class HEADLESS_EXPORT MockGenericURLRequestJobDelegate
~MockGenericURLRequestJobDelegate() override;
// GenericURLRequestJob::Delegate methods:
- void OnPendingRequest(PendingRequest* pending_request) override;
void OnResourceLoadFailed(const Request* request, net::Error error) override;
void OnResourceLoadComplete(
const Request* request,
@@ -35,14 +34,7 @@ class HEADLESS_EXPORT MockGenericURLRequestJobDelegate
const char* body,
size_t body_size) override;
- using Policy = base::Callback<void(PendingRequest* pending_request)>;
-
- void SetPolicy(Policy policy);
-
private:
- void ApplyPolicy(PendingRequest* pending_request);
-
- Policy policy_;
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
DISALLOW_COPY_AND_ASSIGN(MockGenericURLRequestJobDelegate);
@@ -117,6 +109,9 @@ class HEADLESS_EXPORT MockCookieStore : public net::CookieStore {
const std::string& name,
const CookieChangedCallback& callback) override;
+ std::unique_ptr<CookieChangedSubscription> AddCallbackForAllChanges(
+ const CookieChangedCallback& callback) override;
+
bool IsEphemeral() override;
net::CookieList* cookies() { return &cookies_; }
diff --git a/chromium/headless/public/util/url_fetcher.cc b/chromium/headless/public/util/url_fetcher.cc
index 70256e6ae90..c9a79f93e5a 100644
--- a/chromium/headless/public/util/url_fetcher.cc
+++ b/chromium/headless/public/util/url_fetcher.cc
@@ -15,7 +15,8 @@ namespace headless {
void URLFetcher::ResultListener::OnFetchCompleteExtractHeaders(
const GURL& final_url,
const char* response_data,
- size_t response_data_size) {
+ size_t response_data_size,
+ const net::LoadTimingInfo& load_timing_info) {
size_t read_offset = 0;
int header_size =
net::HttpUtil::LocateEndOfHeaders(response_data, response_data_size);
@@ -32,8 +33,8 @@ void URLFetcher::ResultListener::OnFetchCompleteExtractHeaders(
CHECK_LE(read_offset, response_data_size);
OnFetchComplete(final_url, std::move(response_headers),
- response_data + read_offset,
- response_data_size - read_offset);
+ response_data + read_offset, response_data_size - read_offset,
+ load_timing_info);
}
} // namespace headless
diff --git a/chromium/headless/public/util/url_fetcher.h b/chromium/headless/public/util/url_fetcher.h
index 9dfc08a6154..7dd7558b84f 100644
--- a/chromium/headless/public/util/url_fetcher.h
+++ b/chromium/headless/public/util/url_fetcher.h
@@ -12,15 +12,16 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "headless/public/headless_export.h"
+#include "net/base/load_timing_info.h"
#include "net/base/net_errors.h"
#include "url/gurl.h"
namespace net {
-class HttpRequestHeaders;
class HttpResponseHeaders;
} // namespace net
namespace headless {
+class Request;
// An interface for fetching URLs. Note these are only intended to be used once.
class HEADLESS_EXPORT URLFetcher {
@@ -43,13 +44,16 @@ class HEADLESS_EXPORT URLFetcher {
const GURL& final_url,
scoped_refptr<net::HttpResponseHeaders> response_headers,
const char* body,
- size_t body_size) = 0;
+ size_t body_size,
+ const net::LoadTimingInfo& load_timing_info) = 0;
// Helper function which extracts the headers from |response_data| and calls
// OnFetchComplete.
- void OnFetchCompleteExtractHeaders(const GURL& final_url,
- const char* response_data,
- size_t response_data_size);
+ void OnFetchCompleteExtractHeaders(
+ const GURL& final_url,
+ const char* response_data,
+ size_t response_data_size,
+ const net::LoadTimingInfo& load_timing_info);
protected:
virtual ~ResultListener() {}
@@ -58,10 +62,7 @@ class HEADLESS_EXPORT URLFetcher {
DISALLOW_COPY_AND_ASSIGN(ResultListener);
};
- virtual void StartFetch(const GURL& url,
- const std::string& method,
- const std::string& post_data,
- const net::HttpRequestHeaders& request_headers,
+ virtual void StartFetch(const Request* request,
ResultListener* result_listener) = 0;
private: