summaryrefslogtreecommitdiff
path: root/chromium/content/browser/loader
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-03-08 10:28:10 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-03-20 13:40:30 +0000
commite733310db58160074f574c429d48f8308c0afe17 (patch)
treef8aef4b7e62a69928dbcf880620eece20f98c6df /chromium/content/browser/loader
parent2f583e4aec1ae3a86fa047829c96b310dc12ecdf (diff)
downloadqtwebengine-chromium-e733310db58160074f574c429d48f8308c0afe17.tar.gz
BASELINE: Update Chromium to 56.0.2924.122
Change-Id: I4e04de8f47e47e501c46ed934c76a431c6337ced Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/content/browser/loader')
-rw-r--r--chromium/content/browser/loader/DEPS8
-rw-r--r--chromium/content/browser/loader/async_resource_handler.cc17
-rw-r--r--chromium/content/browser/loader/async_resource_handler.h3
-rw-r--r--chromium/content/browser/loader/async_resource_handler_browsertest.cc4
-rw-r--r--chromium/content/browser/loader/async_resource_handler_unittest.cc13
-rw-r--r--chromium/content/browser/loader/async_revalidation_driver.h4
-rw-r--r--chromium/content/browser/loader/async_revalidation_manager.cc4
-rw-r--r--chromium/content/browser/loader/async_revalidation_manager_browsertest.cc28
-rw-r--r--chromium/content/browser/loader/async_revalidation_manager_unittest.cc3
-rw-r--r--chromium/content/browser/loader/cross_site_resource_handler.cc388
-rw-r--r--chromium/content/browser/loader/cross_site_resource_handler.h97
-rw-r--r--chromium/content/browser/loader/cross_site_resource_handler_browsertest.cc3
-rw-r--r--chromium/content/browser/loader/intercepting_resource_handler.cc287
-rw-r--r--chromium/content/browser/loader/intercepting_resource_handler.h91
-rw-r--r--chromium/content/browser/loader/intercepting_resource_handler_unittest.cc584
-rw-r--r--chromium/content/browser/loader/mime_sniffing_resource_handler.cc2
-rw-r--r--chromium/content/browser/loader/mime_sniffing_resource_handler_unittest.cc172
-rw-r--r--chromium/content/browser/loader/mojo_async_resource_handler.cc122
-rw-r--r--chromium/content/browser/loader/mojo_async_resource_handler.h26
-rw-r--r--chromium/content/browser/loader/mojo_async_resource_handler_unittest.cc155
-rw-r--r--chromium/content/browser/loader/navigation_resource_handler.cc5
-rw-r--r--chromium/content/browser/loader/navigation_resource_throttle.cc83
-rw-r--r--chromium/content/browser/loader/navigation_resource_throttle.h11
-rw-r--r--chromium/content/browser/loader/navigation_url_loader.h1
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_impl_core.h3
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_unittest.cc3
-rw-r--r--chromium/content/browser/loader/reload_cache_control_browsertest.cc20
-rw-r--r--chromium/content/browser/loader/resource_dispatcher_host_browsertest.cc61
-rw-r--r--chromium/content/browser/loader/resource_dispatcher_host_impl.cc352
-rw-r--r--chromium/content/browser/loader/resource_dispatcher_host_impl.h86
-rw-r--r--chromium/content/browser/loader/resource_dispatcher_host_unittest.cc267
-rw-r--r--chromium/content/browser/loader/resource_handler.cc2
-rw-r--r--chromium/content/browser/loader/resource_handler.h7
-rw-r--r--chromium/content/browser/loader/resource_loader.cc38
-rw-r--r--chromium/content/browser/loader/resource_loader.h10
-rw-r--r--chromium/content/browser/loader/resource_loader_delegate.h2
-rw-r--r--chromium/content/browser/loader/resource_message_filter.cc44
-rw-r--r--chromium/content/browser/loader/resource_message_filter.h26
-rw-r--r--chromium/content/browser/loader/resource_request_info_impl.cc11
-rw-r--r--chromium/content/browser/loader/resource_request_info_impl.h26
-rw-r--r--chromium/content/browser/loader/resource_scheduler.cc78
-rw-r--r--chromium/content/browser/loader/resource_scheduler.h5
-rw-r--r--chromium/content/browser/loader/resource_scheduler_unittest.cc120
-rw-r--r--chromium/content/browser/loader/sync_resource_handler.cc24
-rw-r--r--chromium/content/browser/loader/sync_resource_handler.h11
-rw-r--r--chromium/content/browser/loader/test_resource_handler.cc111
-rw-r--r--chromium/content/browser/loader/test_resource_handler.h132
-rw-r--r--chromium/content/browser/loader/test_url_loader_client.cc59
-rw-r--r--chromium/content/browser/loader/test_url_loader_client.h38
-rw-r--r--chromium/content/browser/loader/upload_data_stream_builder.cc5
-rw-r--r--chromium/content/browser/loader/url_loader_factory_impl.cc64
-rw-r--r--chromium/content/browser/loader/url_loader_factory_impl.h29
-rw-r--r--chromium/content/browser/loader/url_loader_factory_impl_unittest.cc190
53 files changed, 2505 insertions, 1430 deletions
diff --git a/chromium/content/browser/loader/DEPS b/chromium/content/browser/loader/DEPS
index 1245eec0631..b655be17bdb 100644
--- a/chromium/content/browser/loader/DEPS
+++ b/chromium/content/browser/loader/DEPS
@@ -19,11 +19,11 @@ specific_include_rules = {
"+content/browser/loader/resource_message_filter.h",
"+content/browser/loader/resource_request_info_impl.h",
"+content/common/content_export.h",
+ "+content/public/browser/resource_controller.h",
"+content/public/browser/resource_dispatcher_host_delegate.h",
"+content/public/common/resource_response.h",
# TODO: these all have to be removed.
- "+content/browser/host_zoom_map_impl.h",
"+content/public/common/content_features.h",
# TODO: To be replaced by mojo.
@@ -88,6 +88,8 @@ specific_include_rules = {
"+content/browser/loader/resource_request_info_impl.h",
"+content/common/content_export.h",
"+content/common/resource_request_completion_status.h",
+ "+content/public/browser/global_request_id.h",
+ "+content/public/browser/resource_controller.h",
"+content/public/browser/resource_dispatcher_host_delegate.h",
"+content/public/common/resource_response.h",
"+content/common/url_loader.mojom.h",
@@ -177,6 +179,7 @@ specific_include_rules = {
"+content/browser/resource_context_impl.h",
"+content/browser/service_worker/foreign_fetch_request_handler.h",
"+content/browser/service_worker/link_header_support.h",
+ "+content/browser/service_worker/service_worker_navigation_handle_core.h",
"+content/browser/service_worker/service_worker_request_handler.h",
"+content/browser/streams/stream.h",
"+content/browser/streams/stream_context.h",
@@ -222,6 +225,7 @@ specific_include_rules = {
"+content/common/content_export.h",
"+content/public/browser/resource_controller.h",
"+content/public/browser/resource_dispatcher_host_login_delegate.h",
+ "+content/public/common/browser_side_navigation_policy.h",
"+content/public/common/resource_response.h",
"+content/public/common/resource_type.h",
@@ -255,6 +259,7 @@ specific_include_rules = {
# TODO: these all have to be removed.
"+content/browser/frame_host/frame_tree_node.h",
+ "+content/browser/service_worker/service_worker_context_wrapper.h",
"+content/browser/web_contents/web_contents_impl.h",
"+content/common/net/url_request_service_worker_data.h",
"+content/common/net/url_request_user_data.h",
@@ -306,6 +311,7 @@ specific_include_rules = {
"+content/browser/loader/test_url_loader_client.h",
"+content/common/resource_request_completion_status.h",
"+content/common/url_loader.mojom.h",
+ "+content/common/url_loader_factory.mojom.h",
"+content/public/common/resource_response.h",
],
"url_loader_factory_impl\.(cc|h)": [
diff --git a/chromium/content/browser/loader/async_resource_handler.cc b/chromium/content/browser/loader/async_resource_handler.cc
index 75d9289257d..69df9938434 100644
--- a/chromium/content/browser/loader/async_resource_handler.cc
+++ b/chromium/content/browser/loader/async_resource_handler.cc
@@ -17,7 +17,6 @@
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
-#include "content/browser/host_zoom_map_impl.h"
#include "content/browser/loader/netlog_observer.h"
#include "content/browser/loader/resource_buffer.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
@@ -26,6 +25,7 @@
#include "content/common/resource_messages.h"
#include "content/common/resource_request_completion_status.h"
#include "content/common/view_messages.h"
+#include "content/public/browser/resource_controller.h"
#include "content/public/browser/resource_dispatcher_host_delegate.h"
#include "content/public/common/content_features.h"
#include "content/public/common/resource_response.h"
@@ -351,21 +351,6 @@ bool AsyncResourceHandler::OnResponseStarted(ResourceResponse* response,
NetLogObserver::PopulateResponseInfo(request(), response);
response->head.encoded_data_length = request()->raw_header_size();
- const HostZoomMapImpl* host_zoom_map =
- static_cast<const HostZoomMapImpl*>(info->filter()->GetHostZoomMap());
-
- if (info->GetResourceType() == RESOURCE_TYPE_MAIN_FRAME && host_zoom_map) {
- const GURL& request_url = request()->url();
- int render_process_id = info->GetChildID();
- int render_view_id = info->GetRouteID();
-
- double zoom_level = host_zoom_map->GetZoomLevelForView(
- request_url, render_process_id, render_view_id);
-
- info->filter()->Send(new ViewMsg_SetZoomLevelForLoadingURL(
- render_view_id, request_url, zoom_level));
- }
-
// If the parent handler downloaded the resource to a file, grant the child
// read permissions on it.
if (!response->head.download_file_path.empty()) {
diff --git a/chromium/content/browser/loader/async_resource_handler.h b/chromium/content/browser/loader/async_resource_handler.h
index 023e262842d..c02a38c34aa 100644
--- a/chromium/content/browser/loader/async_resource_handler.h
+++ b/chromium/content/browser/loader/async_resource_handler.h
@@ -24,10 +24,7 @@ class URLRequest;
namespace content {
class ResourceBuffer;
-class ResourceContext;
class ResourceDispatcherHostImpl;
-class ResourceMessageFilter;
-class SharedIOBuffer;
// Used to complete an asynchronous resource request in response to resource
// load events from the resource dispatcher host.
diff --git a/chromium/content/browser/loader/async_resource_handler_browsertest.cc b/chromium/content/browser/loader/async_resource_handler_browsertest.cc
index d0e15f0bdb5..e1bc8fe68ab 100644
--- a/chromium/content/browser/loader/async_resource_handler_browsertest.cc
+++ b/chromium/content/browser/loader/async_resource_handler_browsertest.cc
@@ -69,9 +69,9 @@ class AsyncResourceHandlerBrowserTest : public ContentBrowserTest {
IN_PROC_BROWSER_TEST_F(AsyncResourceHandlerBrowserTest, UploadProgress) {
net::EmbeddedTestServer* test_server = embedded_test_server();
- ASSERT_TRUE(test_server->Start());
test_server->RegisterRequestHandler(
base::Bind(&HandlePostAndRedirectURLs, kPostPath));
+ ASSERT_TRUE(test_server->Start());
NavigateToURL(shell(),
test_server->GetURL("/loader/async_resource_handler.html"));
@@ -87,9 +87,9 @@ IN_PROC_BROWSER_TEST_F(AsyncResourceHandlerBrowserTest, UploadProgress) {
IN_PROC_BROWSER_TEST_F(AsyncResourceHandlerBrowserTest,
UploadProgressRedirect) {
net::EmbeddedTestServer* test_server = embedded_test_server();
- ASSERT_TRUE(test_server->Start());
test_server->RegisterRequestHandler(
base::Bind(&HandlePostAndRedirectURLs, kRedirectPostPath));
+ ASSERT_TRUE(test_server->Start());
NavigateToURL(shell(),
test_server->GetURL("/loader/async_resource_handler.html"));
diff --git a/chromium/content/browser/loader/async_resource_handler_unittest.cc b/chromium/content/browser/loader/async_resource_handler_unittest.cc
index 9764dfdc9b6..9662afd54b7 100644
--- a/chromium/content/browser/loader/async_resource_handler_unittest.cc
+++ b/chromium/content/browser/loader/async_resource_handler_unittest.cc
@@ -14,7 +14,6 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
-#include "base/feature_list.h"
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
@@ -23,6 +22,7 @@
#include "base/process/process.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
+#include "base/test/scoped_feature_list.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/loader/resource_loader.h"
#include "content/browser/loader/resource_loader_delegate.h"
@@ -97,7 +97,6 @@ class RecordingResourceMessageFilter : public ResourceMessageFilter {
nullptr,
nullptr,
nullptr,
- nullptr,
base::Bind(&RecordingResourceMessageFilter::GetContexts,
base::Unretained(this))),
resource_context_(resource_context),
@@ -143,6 +142,8 @@ class AsyncResourceHandlerTest : public ::testing::Test,
: thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP), context_(true) {}
void TearDown() override {
+ if (filter_)
+ filter_->OnChannelClosing();
// Prevent memory leaks.
filter_ = nullptr;
rdh_.Shutdown();
@@ -263,11 +264,9 @@ TEST_F(AsyncResourceHandlerTest, OneChunkLengths) {
TEST_F(AsyncResourceHandlerTest, InlinedChunkLengths) {
// TODO(ricea): Remove this Feature-enabling code once the feature is on by
// default.
- auto feature_list = base::MakeUnique<base::FeatureList>();
- feature_list->InitializeFromCommandLine(
- features::kOptimizeLoadingIPCForSmallResources.name, "");
- base::FeatureList::ClearInstanceForTesting();
- base::FeatureList::SetInstance(std::move(feature_list));
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ features::kOptimizeLoadingIPCForSmallResources);
// Smaller than kInlinedLeadingChunkSize.
StartRequestAndWaitWithResponseDataSize(8);
diff --git a/chromium/content/browser/loader/async_revalidation_driver.h b/chromium/content/browser/loader/async_revalidation_driver.h
index babd3f78e9d..a5bf1ec7c4e 100644
--- a/chromium/content/browser/loader/async_revalidation_driver.h
+++ b/chromium/content/browser/loader/async_revalidation_driver.h
@@ -19,10 +19,6 @@
#include "net/base/io_buffer.h"
#include "net/url_request/url_request.h"
-namespace net {
-class HttpCache;
-}
-
namespace content {
// This class is responsible for driving the URLRequest for an async
diff --git a/chromium/content/browser/loader/async_revalidation_manager.cc b/chromium/content/browser/loader/async_revalidation_manager.cc
index 53279fe1320..abdf659fd22 100644
--- a/chromium/content/browser/loader/async_revalidation_manager.cc
+++ b/chromium/content/browser/loader/async_revalidation_manager.cc
@@ -109,7 +109,7 @@ void AsyncRevalidationManager::BeginAsyncRevalidation(
// Construct the request.
std::unique_ptr<net::URLRequest> new_request = request_context->CreateRequest(
- for_request.url(), net::MINIMUM_PRIORITY, nullptr);
+ for_request.url(), net::IDLE, nullptr);
new_request->set_method(for_request.method());
new_request->set_first_party_for_cookies(
@@ -169,7 +169,7 @@ bool AsyncRevalidationManager::QualifiesForAsyncRevalidation(
const ResourceRequest& request) {
if (request.load_flags &
(net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE |
- net::LOAD_VALIDATE_CACHE | net::LOAD_PREFERRING_CACHE |
+ net::LOAD_VALIDATE_CACHE | net::LOAD_SKIP_CACHE_VALIDATION |
net::LOAD_ONLY_FROM_CACHE | net::LOAD_IGNORE_LIMITS |
net::LOAD_PREFETCH)) {
return false;
diff --git a/chromium/content/browser/loader/async_revalidation_manager_browsertest.cc b/chromium/content/browser/loader/async_revalidation_manager_browsertest.cc
index f02e6fca294..2646222c750 100644
--- a/chromium/content/browser/loader/async_revalidation_manager_browsertest.cc
+++ b/chromium/content/browser/loader/async_revalidation_manager_browsertest.cc
@@ -8,14 +8,15 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
-#include "base/feature_list.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "content/public/common/browser_side_navigation_policy.h"
+#include "content/public/common/content_features.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
@@ -43,20 +44,10 @@ class AsyncRevalidationManagerBrowserTest : public ContentBrowserTest {
~AsyncRevalidationManagerBrowserTest() override {}
void SetUp() override {
- base::FeatureList::ClearInstanceForTesting();
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- feature_list->InitializeFromCommandLine(
- "StaleWhileRevalidate2", std::string());
- base::FeatureList::SetInstance(std::move(feature_list));
-
- ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
+ scoped_feature_list_.InitAndEnableFeature(features::kStaleWhileRevalidate);
ContentBrowserTest::SetUp();
}
- void SetUpOnMainThread() override {
- embedded_test_server()->StartAcceptingConnections();
- }
-
base::RunLoop* run_loop() { return &run_loop_; }
int requests_counted() const { return requests_counted_; }
@@ -151,6 +142,7 @@ class AsyncRevalidationManagerBrowserTest : public ContentBrowserTest {
base::RunLoop run_loop_;
int requests_counted_ = 0;
+ base::test::ScopedFeatureList scoped_feature_list_;
DISALLOW_COPY_AND_ASSIGN(AsyncRevalidationManagerBrowserTest);
};
@@ -159,11 +151,13 @@ class AsyncRevalidationManagerBrowserTest : public ContentBrowserTest {
// triggers an async revalidation.
IN_PROC_BROWSER_TEST_F(AsyncRevalidationManagerBrowserTest,
StaleWhileRevalidateIsApplied) {
+ RegisterCountingRequestHandler();
+ ASSERT_TRUE(embedded_test_server()->Start());
+
// PlzNavigate: Stale while revalidate is disabled.
// TODO(clamy): Re-enable the test when there is support.
if (IsBrowserSideNavigationEnabled())
return;
- RegisterCountingRequestHandler();
GURL url(embedded_test_server()->GetURL(kCountedHtmlPath));
EXPECT_TRUE(TitleBecomes(url, "Version 1"));
@@ -186,12 +180,14 @@ IN_PROC_BROWSER_TEST_F(AsyncRevalidationManagerBrowserTest,
// The fresh cache entry must become visible once the async revalidation request
// has been sent.
IN_PROC_BROWSER_TEST_F(AsyncRevalidationManagerBrowserTest, CacheIsUpdated) {
+ RegisterCountingRequestHandler();
+ ASSERT_TRUE(embedded_test_server()->Start());
+
// PlzNavigate: Stale while revalidate is disabled.
// TODO(clamy): Re-enable the test when there is support.
if (IsBrowserSideNavigationEnabled())
return;
using base::ASCIIToUTF16;
- RegisterCountingRequestHandler();
GURL url(embedded_test_server()->GetURL(kCountedHtmlPath));
EXPECT_TRUE(TitleBecomes(url, "Version 1"));
@@ -218,11 +214,13 @@ IN_PROC_BROWSER_TEST_F(AsyncRevalidationManagerBrowserTest, CacheIsUpdated) {
// applied immediately.
IN_PROC_BROWSER_TEST_F(AsyncRevalidationManagerBrowserTest,
CookieSetAsynchronously) {
+ RegisterCookieRequestHandler();
+ ASSERT_TRUE(embedded_test_server()->Start());
+
// PlzNavigate: Stale while revalidate is disabled.
// TODO(clamy): Re-enable the test when there is support.
if (IsBrowserSideNavigationEnabled())
return;
- RegisterCookieRequestHandler();
GURL url(embedded_test_server()->GetURL(kCookieHtmlPath));
// Set cookie to version=1
diff --git a/chromium/content/browser/loader/async_revalidation_manager_unittest.cc b/chromium/content/browser/loader/async_revalidation_manager_unittest.cc
index 392760d5690..b06f63ce168 100644
--- a/chromium/content/browser/loader/async_revalidation_manager_unittest.cc
+++ b/chromium/content/browser/loader/async_revalidation_manager_unittest.cc
@@ -212,7 +212,6 @@ class BlackholeFilter : public ResourceMessageFilter {
nullptr,
nullptr,
nullptr,
- nullptr,
base::Bind(&BlackholeFilter::GetContexts, base::Unretained(this))),
resource_context_(resource_context) {
ChildProcessSecurityPolicyImpl::GetInstance()->Add(child_id());
@@ -248,6 +247,7 @@ ResourceRequest CreateResourceRequest(const char* method,
request.method = std::string(method);
request.url = url;
request.first_party_for_cookies = url; // Bypass third-party cookie blocking.
+ request.request_initiator = url::Origin(url); // Ensure initiator is set.
request.referrer_policy = blink::WebReferrerPolicyDefault;
request.load_flags = 0;
request.origin_pid = 0;
@@ -289,6 +289,7 @@ class AsyncRevalidationManagerTest : public ::testing::Test {
base::WrapUnique(new net::TestNetworkDelegate)) {}
void TearDown() override {
+ filter_->OnChannelClosing();
host_.CancelRequestsForProcess(filter_->child_id());
host_.Shutdown();
host_.CancelRequestsForContext(browser_context_->GetResourceContext());
diff --git a/chromium/content/browser/loader/cross_site_resource_handler.cc b/chromium/content/browser/loader/cross_site_resource_handler.cc
deleted file mode 100644
index ecffa2095fc..00000000000
--- a/chromium/content/browser/loader/cross_site_resource_handler.cc
+++ /dev/null
@@ -1,388 +0,0 @@
-// Copyright (c) 2012 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 "content/browser/loader/cross_site_resource_handler.h"
-
-#include <string>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "content/browser/appcache/appcache_interceptor.h"
-#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/frame_host/cross_site_transferring_request.h"
-#include "content/browser/frame_host/render_frame_host_impl.h"
-#include "content/browser/loader/resource_dispatcher_host_impl.h"
-#include "content/browser/loader/resource_request_info_impl.h"
-#include "content/browser/site_instance_impl.h"
-#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/common/site_isolation_policy.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/global_request_id.h"
-#include "content/public/browser/resource_controller.h"
-#include "content/public/browser/site_instance.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/common/resource_response.h"
-#include "content/public/common/url_constants.h"
-#include "net/http/http_response_headers.h"
-#include "net/url_request/url_request.h"
-
-namespace content {
-
-namespace {
-
-bool leak_requests_for_testing_ = false;
-
-// The parameters to OnCrossSiteResponseHelper exceed the number of arguments
-// base::Bind supports.
-struct CrossSiteResponseParams {
- CrossSiteResponseParams(
- int render_frame_id,
- const GlobalRequestID& global_request_id,
- const std::vector<GURL>& transfer_url_chain,
- const Referrer& referrer,
- ui::PageTransition page_transition,
- bool should_replace_current_entry)
- : render_frame_id(render_frame_id),
- global_request_id(global_request_id),
- transfer_url_chain(transfer_url_chain),
- referrer(referrer),
- page_transition(page_transition),
- should_replace_current_entry(should_replace_current_entry) {
- }
-
- int render_frame_id;
- GlobalRequestID global_request_id;
- std::vector<GURL> transfer_url_chain;
- Referrer referrer;
- ui::PageTransition page_transition;
- bool should_replace_current_entry;
-};
-
-void OnCrossSiteResponseHelper(const CrossSiteResponseParams& params) {
- std::unique_ptr<CrossSiteTransferringRequest> cross_site_transferring_request(
- new CrossSiteTransferringRequest(params.global_request_id));
-
- RenderFrameHostImpl* rfh =
- RenderFrameHostImpl::FromID(params.global_request_id.child_id,
- params.render_frame_id);
- if (rfh && rfh->is_active()) {
- if (rfh->GetParent()) {
- // We should only swap processes for subframes in --site-per-process mode.
- // CrossSiteResourceHandler is not installed on subframe requests in
- // default Chrome.
- CHECK(SiteIsolationPolicy::AreCrossProcessFramesPossible());
- }
- rfh->OnCrossSiteResponse(
- params.global_request_id, std::move(cross_site_transferring_request),
- params.transfer_url_chain, params.referrer, params.page_transition,
- params.should_replace_current_entry);
- } else if (leak_requests_for_testing_) {
- // Some unit tests expect requests to be leaked in this case, so they can
- // pass them along manually.
- cross_site_transferring_request->ReleaseRequest();
- }
-}
-
-// Returns whether a transfer is needed by doing a check on the UI thread.
-CrossSiteResourceHandler::NavigationDecision
-CheckNavigationPolicyOnUI(GURL real_url, int process_id, int render_frame_id) {
- CHECK(SiteIsolationPolicy::AreCrossProcessFramesPossible());
- RenderFrameHostImpl* rfh =
- RenderFrameHostImpl::FromID(process_id, render_frame_id);
-
- // Without a valid RFH against which to check, we must cancel the request,
- // to prevent the resource at |url| from being delivered to a potentially
- // unsuitable renderer process.
- if (!rfh || !rfh->is_active())
- return CrossSiteResourceHandler::NavigationDecision::CANCEL_REQUEST;
-
- RenderFrameHostManager* manager = rfh->frame_tree_node()->render_manager();
- if (manager->IsRendererTransferNeededForNavigation(rfh, real_url))
- return CrossSiteResourceHandler::NavigationDecision::TRANSFER_REQUIRED;
- else
- return CrossSiteResourceHandler::NavigationDecision::USE_EXISTING_RENDERER;
-}
-
-} // namespace
-
-CrossSiteResourceHandler::CrossSiteResourceHandler(
- std::unique_ptr<ResourceHandler> next_handler,
- net::URLRequest* request)
- : LayeredResourceHandler(request, std::move(next_handler)),
- has_started_response_(false),
- in_cross_site_transition_(false),
- completed_during_transition_(false),
- did_defer_(false),
- weak_ptr_factory_(this) {}
-
-CrossSiteResourceHandler::~CrossSiteResourceHandler() {
- // Cleanup back-pointer stored on the request info.
- GetRequestInfo()->set_cross_site_handler(NULL);
-}
-
-bool CrossSiteResourceHandler::OnRequestRedirected(
- const net::RedirectInfo& redirect_info,
- ResourceResponse* response,
- bool* defer) {
- // We should not have started the transition before being redirected.
- DCHECK(!in_cross_site_transition_);
- return next_handler_->OnRequestRedirected(redirect_info, response, defer);
-}
-
-bool CrossSiteResourceHandler::OnResponseStarted(
- ResourceResponse* response,
- bool* defer) {
- response_ = response;
- has_started_response_ = true;
-
- // Store this handler on the ExtraRequestInfo, so that RDH can call our
- // ResumeResponse method when we are ready to resume.
- ResourceRequestInfoImpl* info = GetRequestInfo();
- info->set_cross_site_handler(this);
-
- return OnNormalResponseStarted(response, defer);
-}
-
-bool CrossSiteResourceHandler::OnNormalResponseStarted(
- ResourceResponse* response,
- bool* defer) {
- // At this point, we know that the response is safe to send back to the
- // renderer: it is not a download, and it has passed the SSL and safe
- // browsing checks.
- // We should not have already started the transition before now.
- DCHECK(!in_cross_site_transition_);
-
- ResourceRequestInfoImpl* info = GetRequestInfo();
-
- // The content embedder can decide that a transfer to a different process is
- // required for this URL. If so, pause the response now. Other cross process
- // navigations can proceed immediately, since we run the unload handler at
- // commit time. Note that a process swap may no longer be necessary if we
- // transferred back into the original process due to a redirect.
- bool definitely_transfer =
- GetContentClient()->browser()->ShouldSwapProcessesForRedirect(
- info->GetContext(), request()->original_url(), request()->url());
-
- // If this is a download, just pass the response through without doing a
- // cross-site check. The renderer will see it is a download and abort the
- // request.
- //
- // Similarly, HTTP 204 (No Content) responses leave us showing the previous
- // page. We should allow the navigation to finish without running the unload
- // handler or swapping in the pending RenderFrameHost.
- //
- // In both cases, any pending RenderFrameHost (if one was created for this
- // navigation) will stick around until the next cross-site navigation, since
- // we are unable to tell when to destroy it.
- // See RenderFrameHostManager::RendererAbortedProvisionalLoad.
- //
- // TODO(davidben): Unify IsDownload() and is_stream(). Several places need to
- // check for both and remembering about streams is error-prone.
- if (info->IsDownload() || info->is_stream() ||
- (response->head.headers.get() &&
- response->head.headers->response_code() == 204)) {
- return next_handler_->OnResponseStarted(response, defer);
- }
-
- if (definitely_transfer) {
- // Now that we know a transfer is needed and we have something to commit, we
- // pause to let the UI thread set up the transfer.
- StartCrossSiteTransition(response);
-
- // Defer loading until after the new renderer process has issued a
- // corresponding request.
- *defer = true;
- OnDidDefer();
- return true;
- }
-
- // In the site-per-process model, we may also decide (independently from the
- // content embedder's ShouldSwapProcessesForRedirect decision above) that a
- // process transfer is needed. For that we need to consult the navigation
- // policy on the UI thread, so pause the response. Process transfers are
- // skipped for WebUI processes for now, since e.g. chrome://settings has
- // multiple "cross-site" chrome:// frames, and that doesn't yet work cross-
- // process.
- if (SiteIsolationPolicy::AreCrossProcessFramesPossible() &&
- !ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
- info->GetChildID())) {
- return DeferForNavigationPolicyCheck(info, response, defer);
- }
-
- // No deferral needed. Pass the response through.
- return next_handler_->OnResponseStarted(response, defer);
-}
-
-void CrossSiteResourceHandler::ResumeOrTransfer(NavigationDecision decision) {
- switch (decision) {
- case NavigationDecision::CANCEL_REQUEST:
- // TODO(nick): What kind of cleanup do we need here?
- controller()->Cancel();
- break;
- case NavigationDecision::USE_EXISTING_RENDERER:
- ResumeResponse();
- break;
- case NavigationDecision::TRANSFER_REQUIRED:
- StartCrossSiteTransition(response_.get());
- break;
- }
-}
-
-bool CrossSiteResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
- CHECK(!in_cross_site_transition_);
- return next_handler_->OnReadCompleted(bytes_read, defer);
-}
-
-void CrossSiteResourceHandler::OnResponseCompleted(
- const net::URLRequestStatus& status,
- bool* defer) {
- if (!in_cross_site_transition_) {
- // If we're not transferring, then we should pass this through.
- next_handler_->OnResponseCompleted(status, defer);
- return;
- }
-
- // We have to buffer the call until after the transition completes.
- completed_during_transition_ = true;
- completed_status_ = status;
-
- // Defer to tell RDH not to notify the world or clean up the pending request.
- // We will do so in ResumeResponse.
- *defer = true;
- OnDidDefer();
-}
-
-// We can now send the response to the new renderer, which will cause
-// WebContentsImpl to swap in the new renderer and destroy the old one.
-void CrossSiteResourceHandler::ResumeResponse() {
- TRACE_EVENT_ASYNC_END0(
- "navigation", "CrossSiteResourceHandler transition", this);
- DCHECK(request());
- in_cross_site_transition_ = false;
- ResourceRequestInfoImpl* info = GetRequestInfo();
-
- if (has_started_response_) {
- // Send OnResponseStarted to the new renderer.
- DCHECK(response_.get());
- bool defer = false;
- if (!next_handler_->OnResponseStarted(response_.get(), &defer)) {
- controller()->Cancel();
- } else if (!defer) {
- // Unpause the request to resume reading. Any further reads will be
- // directed toward the new renderer.
- ResumeIfDeferred();
- }
- }
-
- // Remove ourselves from the ExtraRequestInfo.
- info->set_cross_site_handler(NULL);
-
- // If the response completed during the transition, notify the next
- // event handler.
- if (completed_during_transition_) {
- bool defer = false;
- next_handler_->OnResponseCompleted(completed_status_,
- &defer);
- if (!defer)
- ResumeIfDeferred();
- }
-}
-
-// static
-void CrossSiteResourceHandler::SetLeakRequestsForTesting(
- bool leak_requests_for_testing) {
- leak_requests_for_testing_ = leak_requests_for_testing;
-}
-
-// Prepare to transfer the response to a new RenderFrameHost.
-void CrossSiteResourceHandler::StartCrossSiteTransition(
- ResourceResponse* response) {
- TRACE_EVENT_ASYNC_BEGIN0(
- "navigation", "CrossSiteResourceHandler transition", this);
- in_cross_site_transition_ = true;
- response_ = response;
-
- // Store this handler on the ExtraRequestInfo, so that RDH can call our
- // ResumeResponse method when we are ready to resume.
- ResourceRequestInfoImpl* info = GetRequestInfo();
- info->set_cross_site_handler(this);
-
- GlobalRequestID global_id(info->GetChildID(), info->GetRequestID());
-
- // Tell the contents responsible for this request that a cross-site response
- // is starting, so that it can tell its old renderer to run its onunload
- // handler now. We will wait until the unload is finished and (if a transfer
- // is needed) for the new renderer's request to arrive.
- // The |transfer_url_chain| contains any redirect URLs that have already
- // occurred, plus the destination URL at the end.
- std::vector<GURL> transfer_url_chain;
- Referrer referrer;
- int render_frame_id = info->GetRenderFrameID();
- transfer_url_chain = request()->url_chain();
- referrer = Referrer(GURL(request()->referrer()), info->GetReferrerPolicy());
- ResourceDispatcherHostImpl::Get()->MarkAsTransferredNavigation(global_id,
- response_);
-
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(
- &OnCrossSiteResponseHelper,
- CrossSiteResponseParams(render_frame_id,
- global_id,
- transfer_url_chain,
- referrer,
- info->GetPageTransition(),
- info->should_replace_current_entry())));
-}
-
-bool CrossSiteResourceHandler::DeferForNavigationPolicyCheck(
- ResourceRequestInfoImpl* info,
- ResourceResponse* response,
- bool* defer) {
- // Store the response_ object internally, since the navigation is deferred
- // regardless of whether it will be a transfer or not.
- response_ = response;
-
- // Always defer the navigation to the UI thread to make a policy decision.
- // It will send the result back to the IO thread to either resume or
- // transfer it to a new renderer.
- // TODO(nasko): If the UI thread result is that transfer is required, the
- // IO thread will defer to the UI thread again through
- // StartCrossSiteTransition. This is unnecessary and the policy check on the
- // UI thread should be refactored to avoid the extra hop.
- BrowserThread::PostTaskAndReplyWithResult(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&CheckNavigationPolicyOnUI,
- request()->url(),
- info->GetChildID(),
- info->GetRenderFrameID()),
- base::Bind(&CrossSiteResourceHandler::ResumeOrTransfer,
- weak_ptr_factory_.GetWeakPtr()));
-
- // Defer loading until it is known whether the navigation will transfer
- // to a new process or continue in the existing one.
- *defer = true;
- OnDidDefer();
- return true;
-}
-
-void CrossSiteResourceHandler::ResumeIfDeferred() {
- if (did_defer_) {
- request()->LogUnblocked();
- did_defer_ = false;
- controller()->Resume();
- }
-}
-
-void CrossSiteResourceHandler::OnDidDefer() {
- did_defer_ = true;
- request()->LogBlockedBy("CrossSiteResourceHandler");
-}
-
-} // namespace content
diff --git a/chromium/content/browser/loader/cross_site_resource_handler.h b/chromium/content/browser/loader/cross_site_resource_handler.h
deleted file mode 100644
index 9030468841b..00000000000
--- a/chromium/content/browser/loader/cross_site_resource_handler.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (c) 2012 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 CONTENT_BROWSER_LOADER_CROSS_SITE_RESOURCE_HANDLER_H_
-#define CONTENT_BROWSER_LOADER_CROSS_SITE_RESOURCE_HANDLER_H_
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "content/browser/loader/layered_resource_handler.h"
-#include "content/common/content_export.h"
-#include "net/url_request/url_request_status.h"
-
-namespace net {
-class URLRequest;
-}
-
-namespace content {
-
-struct TransitionLayerData;
-
-// Ensures that responses are delayed for navigations that must be transferred
-// to a different process. This handler wraps an AsyncEventHandler, and it sits
-// inside SafeBrowsing and Buffered event handlers. This is important, so that
-// it can intercept OnResponseStarted after we determine that a response is safe
-// and not a download.
-class CrossSiteResourceHandler : public LayeredResourceHandler {
- public:
- enum class NavigationDecision {
- TRANSFER_REQUIRED,
- USE_EXISTING_RENDERER,
- CANCEL_REQUEST
- };
-
- CrossSiteResourceHandler(std::unique_ptr<ResourceHandler> next_handler,
- net::URLRequest* request);
- ~CrossSiteResourceHandler() override;
-
- // ResourceHandler implementation:
- bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
- ResourceResponse* response,
- bool* defer) override;
- bool OnResponseStarted(ResourceResponse* response, bool* defer) override;
- bool OnReadCompleted(int bytes_read, bool* defer) override;
- void OnResponseCompleted(const net::URLRequestStatus& status,
- bool* defer) override;
-
- // We can now send the response to the new renderer, which will cause
- // WebContentsImpl to swap in the new renderer and destroy the old one.
- void ResumeResponse();
-
- // When set to true, requests are leaked when they can't be passed to a
- // RenderViewHost, for unit tests.
- CONTENT_EXPORT static void SetLeakRequestsForTesting(
- bool leak_requests_for_testing);
-
- private:
- // Prepare to transfer the cross-site response to a new RenderFrameHost, by
- // asking it to issue an identical request (on the UI thread).
- void StartCrossSiteTransition(ResourceResponse* response);
-
- // Defer the navigation to the UI thread to check whether transfer is required
- // or not. Currently only used in --site-per-process.
- bool DeferForNavigationPolicyCheck(ResourceRequestInfoImpl* info,
- ResourceResponse* response,
- bool* defer);
-
- bool OnNormalResponseStarted(ResourceResponse* response,
- bool* defer);
-
- void ResumeOrTransfer(NavigationDecision decision);
- void ResumeIfDeferred();
-
- // Called when about to defer a request. Sets |did_defer_| and logs the
- // defferral
- void OnDidDefer();
-
- bool has_started_response_;
- bool in_cross_site_transition_;
- bool completed_during_transition_;
- bool did_defer_;
- net::URLRequestStatus completed_status_;
- scoped_refptr<ResourceResponse> response_;
-
- // TODO(nasko): WeakPtr is needed in --site-per-process, since all navigations
- // are deferred to the UI thread and come back to IO thread via
- // PostTaskAndReplyWithResult. If a transfer is needed, it goes back to the UI
- // thread. This can be removed once the code is changed to only do one hop.
- base::WeakPtrFactory<CrossSiteResourceHandler> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(CrossSiteResourceHandler);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_LOADER_CROSS_SITE_RESOURCE_HANDLER_H_
diff --git a/chromium/content/browser/loader/cross_site_resource_handler_browsertest.cc b/chromium/content/browser/loader/cross_site_resource_handler_browsertest.cc
index d245cca7cfa..cfa809fb83a 100644
--- a/chromium/content/browser/loader/cross_site_resource_handler_browsertest.cc
+++ b/chromium/content/browser/loader/cross_site_resource_handler_browsertest.cc
@@ -12,6 +12,7 @@
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/frame_messages.h"
+#include "content/public/browser/resource_controller.h"
#include "content/public/browser/resource_dispatcher_host.h"
#include "content/public/browser/resource_dispatcher_host_delegate.h"
#include "content/public/browser/resource_throttle.h"
@@ -193,8 +194,8 @@ class CrossSiteResourceHandlerTest : public ContentBrowserTest {
&CrossSiteResourceHandlerTest::InjectResourceDispatcherHostDelegate,
base::Unretained(this)));
host_resolver()->AddRule("*", "127.0.0.1");
- ASSERT_TRUE(embedded_test_server()->Start());
content::SetupCrossSiteRedirector(embedded_test_server());
+ ASSERT_TRUE(embedded_test_server()->Start());
}
void TearDownOnMainThread() override {
diff --git a/chromium/content/browser/loader/intercepting_resource_handler.cc b/chromium/content/browser/loader/intercepting_resource_handler.cc
index 08907205397..7c8f4a99864 100644
--- a/chromium/content/browser/loader/intercepting_resource_handler.cc
+++ b/chromium/content/browser/loader/intercepting_resource_handler.cc
@@ -8,71 +8,58 @@
#include "base/strings/string_util.h"
#include "content/public/common/resource_response.h"
#include "net/base/io_buffer.h"
+#include "net/url_request/url_request.h"
namespace content {
InterceptingResourceHandler::InterceptingResourceHandler(
std::unique_ptr<ResourceHandler> next_handler,
net::URLRequest* request)
- : LayeredResourceHandler(request, std::move(next_handler)),
- state_(State::STARTING),
- first_read_buffer_size_(0) {}
+ : LayeredResourceHandler(request, std::move(next_handler)) {
+ next_handler_->SetController(this);
+}
InterceptingResourceHandler::~InterceptingResourceHandler() {}
+void InterceptingResourceHandler::SetController(
+ ResourceController* controller) {
+ if (state_ == State::PASS_THROUGH)
+ return LayeredResourceHandler::SetController(controller);
+ ResourceHandler::SetController(controller);
+}
+
bool InterceptingResourceHandler::OnResponseStarted(ResourceResponse* response,
bool* defer) {
// If there's no need to switch handlers, just start acting as a blind
// pass-through ResourceHandler.
if (!new_handler_) {
- state_ = State::DONE;
- first_read_buffer_ = nullptr;
+ state_ = State::PASS_THROUGH;
+ next_handler_->SetController(controller());
return next_handler_->OnResponseStarted(response, defer);
}
+ DCHECK_EQ(state_, State::STARTING);
// Otherwise, switch handlers. First, inform the original ResourceHandler
// that this will be handled entirely by the new ResourceHandler.
- // TODO(clamy): We will probably need to check the return values of these for
- // PlzNavigate.
bool defer_ignored = false;
- next_handler_->OnResponseStarted(response, &defer_ignored);
+ if (!next_handler_->OnResponseStarted(response, &defer_ignored))
+ return false;
// Although deferring OnResponseStarted is legal, the only downstream handler
// which does so is CrossSiteResourceHandler. Cross-site transitions should
// not trigger when switching handlers.
DCHECK(!defer_ignored);
- // Make a copy of the data in the first read buffer. Despite not having been
- // informed of any data being stored in first_read_buffer_, the
- // MimeSniffingResourceHandler has read the data, it's just holding it back.
- // This data should be passed to the alternate ResourceHandler and not to to
- // the current ResourceHandler.
- // TODO(clamy): see if doing the copy should be moved to the
- // MimeSniffingResourceHandler.
- if (first_read_buffer_) {
- first_read_buffer_copy_ = new net::IOBuffer(first_read_buffer_size_);
- memcpy(first_read_buffer_copy_->data(), first_read_buffer_->data(),
- first_read_buffer_size_);
- }
-
- // Send the payload to the old handler.
- SendPayloadToOldHandler();
- first_read_buffer_ = nullptr;
-
- // The original ResourceHandler is now no longer needed, so replace it with
- // the new one, before sending the response to the new one.
- next_handler_ = std::move(new_handler_);
-
- state_ =
- first_read_buffer_copy_ ? State::WAITING_FOR_BUFFER_COPY : State::DONE;
-
- return next_handler_->OnResponseStarted(response, defer);
+ // TODO(yhirano): Retaining ownership from a raw pointer is bad.
+ response_ = response;
+ state_ = State::SENDING_PAYLOAD_TO_OLD_HANDLER;
+ return DoLoop(defer);
}
bool InterceptingResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
int* buf_size,
int min_size) {
- if (state_ == State::DONE)
+ if (state_ == State::PASS_THROUGH)
return next_handler_->OnWillRead(buf, buf_size, min_size);
DCHECK_EQ(State::STARTING, state_);
@@ -83,81 +70,213 @@ bool InterceptingResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
first_read_buffer_ = *buf;
first_read_buffer_size_ = *buf_size;
+ first_read_buffer_double_ = new net::IOBuffer(static_cast<size_t>(*buf_size));
+ *buf = first_read_buffer_double_;
return true;
}
bool InterceptingResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
- DCHECK(bytes_read >= 0);
- if (state_ == State::DONE)
+ DCHECK_GE(bytes_read, 0);
+ if (state_ == State::PASS_THROUGH) {
+ if (first_read_buffer_double_) {
+ // |first_read_buffer_double_| was allocated and the user wrote data to
+ // the buffer, but switching has not been done after all.
+ memcpy(first_read_buffer_->data(), first_read_buffer_double_->data(),
+ bytes_read);
+ first_read_buffer_ = nullptr;
+ first_read_buffer_double_ = nullptr;
+ }
return next_handler_->OnReadCompleted(bytes_read, defer);
+ }
- DCHECK_EQ(State::WAITING_FOR_BUFFER_COPY, state_);
- state_ = State::DONE;
+ DCHECK_EQ(State::WAITING_FOR_ON_READ_COMPLETED, state_);
+ first_read_buffer_bytes_read_ = bytes_read;
+ state_ = State::SENDING_BUFFER_TO_NEW_HANDLER;
+ return DoLoop(defer);
+}
- // Copy the data from the first read to the new ResourceHandler.
- scoped_refptr<net::IOBuffer> buf;
- int buf_len = 0;
- if (!next_handler_->OnWillRead(&buf, &buf_len, bytes_read))
- return false;
+void InterceptingResourceHandler::OnResponseCompleted(
+ const net::URLRequestStatus& status,
+ bool* defer) {
+ if (state_ == State::PASS_THROUGH) {
+ LayeredResourceHandler::OnResponseCompleted(status, defer);
+ return;
+ }
+ if (!new_handler_) {
+ // Therer is only one ResourceHandler in this InterceptingResourceHandler.
+ state_ = State::PASS_THROUGH;
+ first_read_buffer_double_ = nullptr;
+ next_handler_->SetController(controller());
+ next_handler_->OnResponseCompleted(status, defer);
+ return;
+ }
- CHECK(buf_len >= bytes_read);
- CHECK_GE(first_read_buffer_size_, static_cast<size_t>(bytes_read));
- memcpy(buf->data(), first_read_buffer_copy_->data(), bytes_read);
+ // There are two ResourceHandlers in this InterceptingResourceHandler.
+ // |next_handler_| is the old handler and |new_handler_| is the new handler.
+ // As written in the class comment, this class assumes that the old handler
+ // will not set |*defer| in OnResponseCompleted.
+ next_handler_->SetController(controller());
+ next_handler_->OnResponseCompleted(status, defer);
+ DCHECK(!*defer);
- first_read_buffer_copy_ = nullptr;
+ state_ = State::PASS_THROUGH;
+ first_read_buffer_double_ = nullptr;
+ new_handler_->SetController(controller());
+ next_handler_ = std::move(new_handler_);
+ next_handler_->OnResponseCompleted(status, defer);
+}
- // TODO(clamy): Add a unit test to check that the deferral value is properly
- // passed to the caller.
- return next_handler_->OnReadCompleted(bytes_read, defer);
+void InterceptingResourceHandler::Cancel() {
+ DCHECK_NE(State::PASS_THROUGH, state_);
+ controller()->Cancel();
+}
+
+void InterceptingResourceHandler::CancelAndIgnore() {
+ DCHECK_NE(State::PASS_THROUGH, state_);
+ controller()->CancelAndIgnore();
+}
+
+void InterceptingResourceHandler::CancelWithError(int error_code) {
+ DCHECK_NE(State::PASS_THROUGH, state_);
+ controller()->CancelWithError(error_code);
+}
+
+void InterceptingResourceHandler::Resume() {
+ DCHECK_NE(State::PASS_THROUGH, state_);
+ if (state_ == State::STARTING ||
+ state_ == State::WAITING_FOR_ON_READ_COMPLETED) {
+ // Uninteresting Resume: just delegate to the original resource controller.
+ controller()->Resume();
+ return;
+ }
+ bool defer = false;
+ if (!DoLoop(&defer)) {
+ controller()->Cancel();
+ return;
+ }
+
+ if (!defer)
+ controller()->Resume();
}
void InterceptingResourceHandler::UseNewHandler(
std::unique_ptr<ResourceHandler> new_handler,
const std::string& payload_for_old_handler) {
new_handler_ = std::move(new_handler);
- new_handler_->SetController(controller());
+ new_handler_->SetController(this);
payload_for_old_handler_ = payload_for_old_handler;
}
-void InterceptingResourceHandler::SendPayloadToOldHandler() {
- bool defer_ignored = false;
+bool InterceptingResourceHandler::DoLoop(bool* defer) {
+ bool result = true;
+ do {
+ switch (state_) {
+ case State::STARTING:
+ case State::WAITING_FOR_ON_READ_COMPLETED:
+ case State::PASS_THROUGH:
+ NOTREACHED();
+ break;
+ case State::SENDING_ON_WILL_START_TO_NEW_HANDLER:
+ result = SendOnResponseStartedToNewHandler(defer);
+ break;
+ case State::SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER:
+ if (first_read_buffer_double_) {
+ // OnWillRead has been called, so copying the data from
+ // |first_read_buffer_double_| to |first_read_buffer_| will be needed
+ // when OnReadCompleted is called.
+ state_ = State::WAITING_FOR_ON_READ_COMPLETED;
+ } else {
+ // OnWillRead has not been called, so no special handling will be
+ // needed from now on.
+ state_ = State::PASS_THROUGH;
+ next_handler_->SetController(controller());
+ }
+ break;
+ case State::SENDING_PAYLOAD_TO_OLD_HANDLER:
+ result = SendPayloadToOldHandler(defer);
+ break;
+ case State::SENDING_BUFFER_TO_NEW_HANDLER:
+ result = SendFirstReadBufferToNewHandler(defer);
+ break;
+ }
+ } while (result && !*defer &&
+ state_ != State::WAITING_FOR_ON_READ_COMPLETED &&
+ state_ != State::PASS_THROUGH);
+ return result;
+}
+
+bool InterceptingResourceHandler::SendPayloadToOldHandler(bool* defer) {
+ DCHECK_EQ(State::SENDING_PAYLOAD_TO_OLD_HANDLER, state_);
+ while (payload_bytes_written_ < payload_for_old_handler_.size()) {
+ scoped_refptr<net::IOBuffer> buffer;
+ int size = 0;
+ if (first_read_buffer_) {
+ // |first_read_buffer_| is a buffer gotten from |next_handler_| via
+ // OnWillRead. Use the buffer.
+ buffer = first_read_buffer_;
+ size = first_read_buffer_size_;
+
+ first_read_buffer_ = nullptr;
+ first_read_buffer_size_ = 0;
+ } else {
+ if (!next_handler_->OnWillRead(&buffer, &size, -1))
+ return false;
+ }
+
+ size = std::min(size, static_cast<int>(payload_for_old_handler_.size() -
+ payload_bytes_written_));
+ memcpy(buffer->data(),
+ payload_for_old_handler_.data() + payload_bytes_written_, size);
+ if (!next_handler_->OnReadCompleted(size, defer))
+ return false;
+ payload_bytes_written_ += size;
+ if (*defer)
+ return true;
+ }
+
+ net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
if (payload_for_old_handler_.empty()) {
// If there is no payload, just finalize the request on the old handler.
- net::URLRequestStatus status(net::URLRequestStatus::CANCELED,
- net::ERR_ABORTED);
- next_handler_->OnResponseCompleted(status, &defer_ignored);
- DCHECK(!defer_ignored);
- return;
+ status = net::URLRequestStatus::FromError(net::ERR_ABORTED);
}
+ next_handler_->OnResponseCompleted(status, defer);
+ DCHECK(!*defer);
- // Ensure the old ResourceHandler has a buffer that can store the payload.
- scoped_refptr<net::IOBuffer> buf;
- int size = 0;
- if (first_read_buffer_) {
- // The first read buffer can be reused. The data inside it has been copied
- // before calling this function, so it can safely be overriden.
- buf = first_read_buffer_;
- size = first_read_buffer_size_;
- }
+ next_handler_ = std::move(new_handler_);
+ state_ = State::SENDING_ON_WILL_START_TO_NEW_HANDLER;
+ return next_handler_->OnWillStart(request()->url(), defer);
+}
- // If there is no first read buffer, ask the old ResourceHandler to create a
- // buffer that can contain payload.
- if (!buf)
- next_handler_->OnWillRead(&buf, &size, -1);
-
- DCHECK(buf);
- CHECK_GE(size, static_cast<int>(payload_for_old_handler_.length()));
- memcpy(buf->data(), payload_for_old_handler_.c_str(),
- payload_for_old_handler_.length());
- next_handler_->OnReadCompleted(payload_for_old_handler_.length(),
- &defer_ignored);
- payload_for_old_handler_ = std::string();
- DCHECK(!defer_ignored);
+bool InterceptingResourceHandler::SendOnResponseStartedToNewHandler(
+ bool* defer) {
+ state_ = State::SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER;
+ return next_handler_->OnResponseStarted(response_.get(), defer);
+}
- // Finalize the request.
- net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
- next_handler_->OnResponseCompleted(status, &defer_ignored);
- DCHECK(!defer_ignored);
+bool InterceptingResourceHandler::SendFirstReadBufferToNewHandler(bool* defer) {
+ DCHECK_EQ(state_, State::SENDING_BUFFER_TO_NEW_HANDLER);
+
+ while (first_read_buffer_bytes_written_ < first_read_buffer_bytes_read_) {
+ scoped_refptr<net::IOBuffer> buf;
+ int size = 0;
+ if (!next_handler_->OnWillRead(&buf, &size, -1))
+ return false;
+ size = std::min(size, static_cast<int>(first_read_buffer_bytes_read_ -
+ first_read_buffer_bytes_written_));
+ memcpy(buf->data(),
+ first_read_buffer_double_->data() + first_read_buffer_bytes_written_,
+ size);
+ if (!next_handler_->OnReadCompleted(size, defer))
+ return false;
+ first_read_buffer_bytes_written_ += size;
+ if (*defer)
+ return true;
+ }
+
+ state_ = State::PASS_THROUGH;
+ first_read_buffer_double_ = nullptr;
+ next_handler_->SetController(controller());
+ return true;
}
} // namespace content
diff --git a/chromium/content/browser/loader/intercepting_resource_handler.h b/chromium/content/browser/loader/intercepting_resource_handler.h
index 8729e5b271e..3c796a406f6 100644
--- a/chromium/content/browser/loader/intercepting_resource_handler.h
+++ b/chromium/content/browser/loader/intercepting_resource_handler.h
@@ -14,7 +14,9 @@
#include "content/browser/loader/layered_resource_handler.h"
#include "content/browser/loader/resource_handler.h"
#include "content/common/content_export.h"
+#include "content/public/browser/resource_controller.h"
#include "net/base/io_buffer.h"
+#include "net/url_request/url_request_status.h"
namespace net {
class URLRequest;
@@ -25,19 +27,34 @@ namespace content {
// ResourceHandler that initiates special handling of the response if needed,
// based on the response's MIME type (starts downloads, sends data to some
// plugin types via a special channel).
+//
+// An InterceptingResourceHandler holds two handlers (|next_handler| and
+// |new_handler|). It assumes the following:
+// - OnResponseStarted on |next_handler| never sets |*defer|.
+// - OnResponseCompleted on |next_handler| never sets |*defer|.
class CONTENT_EXPORT InterceptingResourceHandler
- : public LayeredResourceHandler {
+ : public LayeredResourceHandler,
+ public ResourceController {
public:
InterceptingResourceHandler(std::unique_ptr<ResourceHandler> next_handler,
net::URLRequest* request);
~InterceptingResourceHandler() override;
// ResourceHandler implementation:
+ void SetController(ResourceController* controller) override;
bool OnResponseStarted(ResourceResponse* response, bool* defer) override;
bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
int* buf_size,
int min_size) override;
bool OnReadCompleted(int bytes_read, bool* defer) override;
+ void OnResponseCompleted(const net::URLRequestStatus& status,
+ bool* defer) override;
+
+ // ResourceController implementation:
+ void Cancel() override;
+ void CancelAndIgnore() override;
+ void CancelWithError(int error_code) override;
+ void Resume() override;
// Replaces the next handler with |new_handler|, sending
// |payload_for_old_handler| to the old handler. Must be called after
@@ -54,38 +71,70 @@ class CONTENT_EXPORT InterceptingResourceHandler
private:
enum class State {
- // In this state, the InterceptingResourceHandler is waiting for the mime
- // type of the response to be identified, to check if the next handler
- // should be replaced with an appropriate one.
+ // The InterceptingResourceHandler is waiting for the mime type of the
+ // response to be identified, to check if the next handler should be
+ // replaced with an appropriate one.
STARTING,
- // In this state, the InterceptingResourceHandler is waiting to copy the
- // read buffer to the next handler if it was replaced. This is needed
- // because MimeTypeResourceHandler may call OnWillRead before calling
- // OnResponseStarted, that is before the InterceptingResourceHandler
- // replaces the original ResourceHandler of the request. Therefore, the
- // data read at that time should be copied to the new ResourceHandler.
- WAITING_FOR_BUFFER_COPY,
-
- // In this state, the InterceptingResourceHandler has replaced its next
- // ResourceHandler if needed, and has ensured the buffered read data was
- // properly transmitted to the new ResourceHandler. The
- // InterceptingResourceHandler now acts as a pass-through ResourceHandler.
- DONE,
+ // The InterceptingResourceHandler is sending the payload given via
+ // UseNewHandler to the old handler and waiting for its completion via
+ // Resume().
+ SENDING_PAYLOAD_TO_OLD_HANDLER,
+
+ // The InterceptingResourcHandler is calling the new handler's
+ // OnResponseStarted method and waiting for its completion via Resume().
+ // After completion, the InterceptingResourceHandler will transition to
+ // SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER on success.
+ SENDING_ON_WILL_START_TO_NEW_HANDLER,
+
+ // The InterceptingResourcHandler is calling the new handler's
+ // OnResponseStarted method and waiting for its completion via Resume().
+ // After completion, the InterceptingResourceHandler will transition to
+ // WAITING_FOR_ON_READ_COMPLETED on success.
+ SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER,
+
+ // The InterceptingResourcHandler is waiting for OnReadCompleted to be
+ // called.
+ WAITING_FOR_ON_READ_COMPLETED,
+
+ // The InterceptingResourceHandler is sending the old handler's contents to
+ // the new handler and waiting for its completion via Resume().
+ SENDING_BUFFER_TO_NEW_HANDLER,
+
+ // The InterceptingResourceHandler has replaced its next ResourceHandler if
+ // needed, and has ensured the buffered read data was properly transmitted
+ // to the new ResourceHandler. The InterceptingResourceHandler now acts as
+ // a pass-through ResourceHandler.
+ PASS_THROUGH,
};
- void SendPayloadToOldHandler();
+ // Runs necessary operations depending on |state_|. Returns false when an
+ // error happens, and set |*defer| to true if the operation continues upon
+ // return.
+ bool DoLoop(bool* defer);
+
+ // The return value and |defer| has the same meaning as DoLoop.
+ bool SendPayloadToOldHandler(bool* defer);
+ bool SendFirstReadBufferToNewHandler(bool* defer);
+ bool SendOnResponseStartedToNewHandler(bool* defer);
- State state_;
+ State state_ = State::STARTING;
std::unique_ptr<ResourceHandler> new_handler_;
std::string payload_for_old_handler_;
+ size_t payload_bytes_written_ = 0;
// Result of the first read, that may have to be passed to an alternate
// ResourceHandler instead of the original ResourceHandler.
scoped_refptr<net::IOBuffer> first_read_buffer_;
- size_t first_read_buffer_size_;
- scoped_refptr<net::IOBuffer> first_read_buffer_copy_;
+ // Instead of |first_read_buffer_|, this handler creates a new IOBuffer with
+ // the same size and return it to the client.
+ scoped_refptr<net::IOBuffer> first_read_buffer_double_;
+ size_t first_read_buffer_size_ = 0;
+ size_t first_read_buffer_bytes_read_ = 0;
+ size_t first_read_buffer_bytes_written_ = 0;
+
+ scoped_refptr<ResourceResponse> response_;
DISALLOW_COPY_AND_ASSIGN(InterceptingResourceHandler);
};
diff --git a/chromium/content/browser/loader/intercepting_resource_handler_unittest.cc b/chromium/content/browser/loader/intercepting_resource_handler_unittest.cc
index 3ae9dead69e..9f2096ce76c 100644
--- a/chromium/content/browser/loader/intercepting_resource_handler_unittest.cc
+++ b/chromium/content/browser/loader/intercepting_resource_handler_unittest.cc
@@ -7,13 +7,16 @@
#include <stdint.h>
#include <memory>
+#include <string>
#include "base/files/file_path.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "content/browser/loader/test_resource_handler.h"
#include "content/public/browser/resource_controller.h"
#include "content/public/browser/resource_request_info.h"
#include "content/public/common/resource_response.h"
@@ -30,102 +33,20 @@ namespace content {
namespace {
-class TestResourceHandler : public ResourceHandler {
+class TestResourceController : public ResourceController {
public:
- // A test version of a ResourceHandler. |request_status| and
- // |final_bytes_read| will be updated when the response is complete with the
- // final status of the request received by the handler, and the total bytes
- // the handler saw.
- explicit TestResourceHandler(net::URLRequestStatus* request_status,
- size_t* final_bytes_read)
- : TestResourceHandler(request_status,
- final_bytes_read,
- true /* on_response_started_result */,
- true /* on_will_read_result */,
- true /* on_read_completed_result */) {}
-
- // This constructor allows to specify return values for OnResponseStarted,
- // OnWillRead and OnReadCompleted.
- TestResourceHandler(net::URLRequestStatus* request_status,
- size_t* final_bytes_read,
- bool on_response_started_result,
- bool on_will_read_result,
- bool on_read_completed_result)
- : ResourceHandler(nullptr),
- buffer_(new net::IOBuffer(2048)),
- request_status_(request_status),
- final_bytes_read_(final_bytes_read),
- on_response_started_result_(on_response_started_result),
- on_will_read_result_(on_will_read_result),
- on_read_completed_result_(on_read_completed_result),
- bytes_read_(0),
- is_completed_(false) {
- memset(buffer_->data(), '\0', 2048);
- }
-
- ~TestResourceHandler() override {}
-
- void SetController(ResourceController* controller) override {}
-
- bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
- ResourceResponse* response,
- bool* defer) override {
- NOTREACHED();
- return false;
- }
-
- bool OnResponseStarted(ResourceResponse* response, bool* defer) override {
- EXPECT_FALSE(is_completed_);
- return on_response_started_result_;
- }
-
- bool OnWillStart(const GURL& url, bool* defer) override {
- EXPECT_FALSE(is_completed_);
- return true;
- }
-
- bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
- int* buf_size,
- int min_size) override {
- EXPECT_FALSE(is_completed_);
- *buf = buffer_;
- *buf_size = 2048;
- memset(buffer_->data(), '\0', 2048);
- return on_will_read_result_;
- }
-
- bool OnReadCompleted(int bytes_read, bool* defer) override {
- EXPECT_FALSE(is_completed_);
- EXPECT_LT(bytes_read, 2048);
- bytes_read_ += bytes_read;
- return on_read_completed_result_;
- }
-
- void OnResponseCompleted(const net::URLRequestStatus& status,
- bool* defer) override {
- EXPECT_FALSE(is_completed_);
- is_completed_ = true;
- *request_status_ = status;
- *final_bytes_read_ = bytes_read_;
- }
-
- void OnDataDownloaded(int bytes_downloaded) override { NOTREACHED(); }
-
- scoped_refptr<net::IOBuffer> buffer() const { return buffer_; }
-
- size_t bytes_read() const { return bytes_read_; }
+ TestResourceController() = default;
+ void Cancel() override {}
+ void CancelAndIgnore() override {}
+ void CancelWithError(int error_code) override {}
+ void Resume() override { ++resume_calls_; }
+
+ int resume_calls() const { return resume_calls_; }
private:
- scoped_refptr<net::IOBuffer> buffer_;
- net::URLRequestStatus* request_status_;
- size_t* final_bytes_read_;
- bool on_response_started_result_;
- bool on_will_read_result_;
- bool on_read_completed_result_;
- size_t bytes_read_;
- bool is_completed_;
-
- DISALLOW_COPY_AND_ASSIGN(TestResourceHandler);
+ int resume_calls_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(TestResourceController);
};
class InterceptingResourceHandlerTest : public testing::Test {
@@ -155,11 +76,10 @@ TEST_F(InterceptingResourceHandlerTest, NoSwitching) {
false); // is_using_lofi
net::URLRequestStatus old_handler_status;
- size_t old_handler_final_bytes_read = 0;
- std::unique_ptr<TestResourceHandler> old_handler(new TestResourceHandler(
- &old_handler_status, &old_handler_final_bytes_read));
+ std::string old_handler_body;
+ std::unique_ptr<TestResourceHandler> old_handler(
+ new TestResourceHandler(&old_handler_status, &old_handler_body));
TestResourceHandler* old_test_handler = old_handler.get();
- scoped_refptr<net::IOBuffer> old_buffer = old_handler.get()->buffer();
std::unique_ptr<InterceptingResourceHandler> intercepting_handler(
new InterceptingResourceHandler(std::move(old_handler), request.get()));
@@ -176,7 +96,7 @@ TEST_F(InterceptingResourceHandlerTest, NoSwitching) {
const std::string kData = "The data";
EXPECT_NE(kData, std::string(old_test_handler->buffer()->data()));
- ASSERT_EQ(read_buffer.get(), old_test_handler->buffer());
+ ASSERT_NE(read_buffer.get(), old_test_handler->buffer());
ASSERT_GT(static_cast<size_t>(buf_size), kData.length());
memcpy(read_buffer->data(), kData.c_str(), kData.length());
@@ -203,7 +123,7 @@ TEST_F(InterceptingResourceHandlerTest, NoSwitching) {
EXPECT_TRUE(intercepting_handler->OnReadCompleted(kData2.length(), &defer));
EXPECT_FALSE(defer);
EXPECT_EQ(kData2, std::string(old_test_handler->buffer()->data()));
- EXPECT_EQ(kData.length() + kData2.length(), old_test_handler->bytes_read());
+ EXPECT_EQ(kData + kData2, old_handler_body);
}
// Tests that the data received is transmitted to the newly created
@@ -225,9 +145,9 @@ TEST_F(InterceptingResourceHandlerTest, HandlerSwitchNoPayload) {
false); // is_using_lofi
net::URLRequestStatus old_handler_status;
- size_t old_handler_final_bytes_read = 0;
- std::unique_ptr<TestResourceHandler> old_handler(new TestResourceHandler(
- &old_handler_status, &old_handler_final_bytes_read));
+ std::string old_handler_body;
+ std::unique_ptr<TestResourceHandler> old_handler(
+ new TestResourceHandler(&old_handler_status, &old_handler_body));
scoped_refptr<net::IOBuffer> old_buffer = old_handler.get()->buffer();
std::unique_ptr<InterceptingResourceHandler> intercepting_handler(
new InterceptingResourceHandler(std::move(old_handler), request.get()));
@@ -243,17 +163,16 @@ TEST_F(InterceptingResourceHandlerTest, HandlerSwitchNoPayload) {
EXPECT_TRUE(intercepting_handler->OnWillRead(&read_buffer, &buf_size, -1));
const std::string kData = "The data";
- ASSERT_EQ(read_buffer.get(), old_buffer.get());
+ ASSERT_NE(read_buffer.get(), old_buffer.get());
ASSERT_GT(static_cast<size_t>(buf_size), kData.length());
memcpy(read_buffer->data(), kData.c_str(), kData.length());
// Simulate the MimeSniffingResourceHandler asking the
// InterceptingResourceHandler to switch to a new handler.
net::URLRequestStatus new_handler_status;
- size_t new_handler_final_bytes_read = 0;
+ std::string new_handler_body;
std::unique_ptr<TestResourceHandler> new_handler_scoped(
- new TestResourceHandler(&new_handler_status,
- &new_handler_final_bytes_read));
+ new TestResourceHandler(&new_handler_status, &new_handler_body));
TestResourceHandler* new_test_handler = new_handler_scoped.get();
intercepting_handler->UseNewHandler(std::move(new_handler_scoped),
std::string());
@@ -265,7 +184,7 @@ TEST_F(InterceptingResourceHandlerTest, HandlerSwitchNoPayload) {
EXPECT_FALSE(old_handler_status.is_success());
EXPECT_EQ(net::ERR_ABORTED, old_handler_status.error());
- EXPECT_EQ(0ul, old_handler_final_bytes_read);
+ EXPECT_EQ(std::string(), old_handler_body);
// It should not have received the download data yet.
EXPECT_NE(kData, std::string(new_test_handler->buffer()->data()));
@@ -289,7 +208,7 @@ TEST_F(InterceptingResourceHandlerTest, HandlerSwitchNoPayload) {
EXPECT_TRUE(intercepting_handler->OnReadCompleted(kData2.length(), &defer));
EXPECT_FALSE(defer);
EXPECT_EQ(kData2, std::string(new_test_handler->buffer()->data()));
- EXPECT_EQ(kData.length() + kData2.length(), new_test_handler->bytes_read());
+ EXPECT_EQ(kData + kData2, new_handler_body);
}
// Tests that the data received is transmitted to the newly created
@@ -311,10 +230,9 @@ TEST_F(InterceptingResourceHandlerTest, HandlerSwitchWithPayload) {
false); // is_using_lofi
net::URLRequestStatus old_handler_status;
- size_t old_handler_final_bytes_read = 0;
+ std::string old_handler_body;
std::unique_ptr<TestResourceHandler> old_handler_scoped(
- new TestResourceHandler(&old_handler_status,
- &old_handler_final_bytes_read));
+ new TestResourceHandler(&old_handler_status, &old_handler_body));
TestResourceHandler* old_handler = old_handler_scoped.get();
scoped_refptr<net::IOBuffer> old_buffer = old_handler->buffer();
std::unique_ptr<InterceptingResourceHandler> intercepting_handler(
@@ -332,7 +250,7 @@ TEST_F(InterceptingResourceHandlerTest, HandlerSwitchWithPayload) {
EXPECT_TRUE(intercepting_handler->OnWillRead(&read_buffer, &buf_size, -1));
const std::string kData = "The data";
- ASSERT_EQ(read_buffer.get(), old_buffer.get());
+ ASSERT_NE(read_buffer.get(), old_buffer.get());
ASSERT_GT(static_cast<size_t>(buf_size), kData.length());
memcpy(read_buffer->data(), kData.c_str(), kData.length());
@@ -340,16 +258,14 @@ TEST_F(InterceptingResourceHandlerTest, HandlerSwitchWithPayload) {
// InterceptingResourceHandler to switch to a new handler.
const std::string kPayload = "The payload";
net::URLRequestStatus new_handler_status;
- size_t new_handler_final_bytes_read = 0;
+ std::string new_handler_body;
std::unique_ptr<TestResourceHandler> new_handler_scoped(
- new TestResourceHandler(&new_handler_status,
- &new_handler_final_bytes_read));
+ new TestResourceHandler(&new_handler_status, &new_handler_body));
TestResourceHandler* new_test_handler = new_handler_scoped.get();
intercepting_handler->UseNewHandler(std::move(new_handler_scoped), kPayload);
// The old handler should not have received the payload yet.
- ASSERT_FALSE(old_handler->bytes_read());
- EXPECT_NE(kPayload, std::string(old_buffer->data()));
+ ASSERT_EQ(std::string(), old_handler_body);
// The response is received. The new ResourceHandler should be used to handle
// the download.
@@ -357,8 +273,7 @@ TEST_F(InterceptingResourceHandlerTest, HandlerSwitchWithPayload) {
EXPECT_FALSE(defer);
// The old handler should have received the payload.
- ASSERT_TRUE(old_handler_final_bytes_read == kPayload.size());
- EXPECT_EQ(kPayload, std::string(old_buffer->data()));
+ EXPECT_EQ(kPayload, old_handler_body);
EXPECT_TRUE(old_handler_status.is_success());
EXPECT_EQ(net::OK, old_handler_status.error());
@@ -385,7 +300,7 @@ TEST_F(InterceptingResourceHandlerTest, HandlerSwitchWithPayload) {
EXPECT_TRUE(intercepting_handler->OnReadCompleted(kData2.length(), &defer));
EXPECT_FALSE(defer);
EXPECT_EQ(kData2, std::string(new_test_handler->buffer()->data()));
- EXPECT_EQ(kData.length() + kData2.length(), new_test_handler->bytes_read());
+ EXPECT_EQ(kData + kData2, new_handler_body);
}
// Tests that the handler behaves properly if the old handler fails will read.
@@ -406,13 +321,10 @@ TEST_F(InterceptingResourceHandlerTest, OldHandlerFailsWillRead) {
false); // is_using_lofi
net::URLRequestStatus old_handler_status;
- size_t old_handler_final_bytes_read = 0;
- std::unique_ptr<TestResourceHandler> old_handler(new TestResourceHandler(
- &old_handler_status, &old_handler_final_bytes_read,
- true, // on_response_started
- false, // on_will_read
- true)); // on_read_completed
- scoped_refptr<net::IOBuffer> old_buffer = old_handler.get()->buffer();
+ std::string old_handler_body;
+ std::unique_ptr<TestResourceHandler> old_handler(
+ new TestResourceHandler(&old_handler_status, &old_handler_body));
+ old_handler->set_on_will_read_result(false);
std::unique_ptr<InterceptingResourceHandler> intercepting_handler(
new InterceptingResourceHandler(std::move(old_handler), request.get()));
@@ -428,6 +340,61 @@ TEST_F(InterceptingResourceHandlerTest, OldHandlerFailsWillRead) {
EXPECT_FALSE(intercepting_handler->OnWillRead(&read_buffer, &buf_size, -1));
}
+// Tests that the handler behaves properly if the new handler fails in
+// OnWillStart.
+TEST_F(InterceptingResourceHandlerTest, NewHandlerFailsOnWillStart) {
+ net::URLRequestContext context;
+ std::unique_ptr<net::URLRequest> request(context.CreateRequest(
+ GURL("http://www.google.com"), net::DEFAULT_PRIORITY, nullptr));
+ ResourceRequestInfo::AllocateForTesting(request.get(),
+ RESOURCE_TYPE_MAIN_FRAME,
+ nullptr, // context
+ 0, // render_process_id
+ 0, // render_view_id
+ 0, // render_frame_id
+ true, // is_main_frame
+ false, // parent_is_main_frame
+ true, // allow_download
+ true, // is_async
+ false); // is_using_lofi
+
+ net::URLRequestStatus old_handler_status;
+ std::string old_handler_body;
+ std::unique_ptr<TestResourceHandler> old_handler(
+ new TestResourceHandler(&old_handler_status, &old_handler_body));
+ scoped_refptr<net::IOBuffer> old_buffer = old_handler.get()->buffer();
+ std::unique_ptr<InterceptingResourceHandler> intercepting_handler(
+ new InterceptingResourceHandler(std::move(old_handler), request.get()));
+
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+
+ // Simulate the MimeSniffingResourceHandler buffering the data.
+ scoped_refptr<net::IOBuffer> read_buffer;
+ int buf_size = 0;
+ bool defer = false;
+ EXPECT_TRUE(intercepting_handler->OnWillStart(GURL(), &defer));
+ EXPECT_FALSE(defer);
+ EXPECT_TRUE(intercepting_handler->OnWillRead(&read_buffer, &buf_size, -1));
+
+ const char kData[] = "The data";
+ ASSERT_NE(read_buffer.get(), old_buffer.get());
+ ASSERT_GT(static_cast<size_t>(buf_size), sizeof(kData));
+ memcpy(read_buffer->data(), kData, sizeof(kData));
+
+ // Simulate the MimeSniffingResourceHandler asking the
+ // InterceptingResourceHandler to switch to a new handler.
+ net::URLRequestStatus new_handler_status;
+ std::string new_handler_body;
+ std::unique_ptr<TestResourceHandler> new_handler(
+ new TestResourceHandler(&new_handler_status, &new_handler_body));
+ new_handler->set_on_will_start_result(false);
+ intercepting_handler->UseNewHandler(std::move(new_handler), std::string());
+
+ // The response is received. The new ResourceHandler should tell us to fail.
+ EXPECT_FALSE(intercepting_handler->OnResponseStarted(response.get(), &defer));
+ EXPECT_FALSE(defer);
+}
+
// Tests that the handler behaves properly if the new handler fails response
// started.
TEST_F(InterceptingResourceHandlerTest, NewHandlerFailsResponseStarted) {
@@ -447,9 +414,9 @@ TEST_F(InterceptingResourceHandlerTest, NewHandlerFailsResponseStarted) {
false); // is_using_lofi
net::URLRequestStatus old_handler_status;
- size_t old_handler_final_bytes_read = 0;
- std::unique_ptr<TestResourceHandler> old_handler(new TestResourceHandler(
- &old_handler_status, &old_handler_final_bytes_read));
+ std::string old_handler_body;
+ std::unique_ptr<TestResourceHandler> old_handler(
+ new TestResourceHandler(&old_handler_status, &old_handler_body));
scoped_refptr<net::IOBuffer> old_buffer = old_handler.get()->buffer();
std::unique_ptr<InterceptingResourceHandler> intercepting_handler(
new InterceptingResourceHandler(std::move(old_handler), request.get()));
@@ -465,19 +432,17 @@ TEST_F(InterceptingResourceHandlerTest, NewHandlerFailsResponseStarted) {
EXPECT_TRUE(intercepting_handler->OnWillRead(&read_buffer, &buf_size, -1));
const char kData[] = "The data";
- ASSERT_EQ(read_buffer.get(), old_buffer.get());
+ ASSERT_NE(read_buffer.get(), old_buffer.get());
ASSERT_GT(static_cast<size_t>(buf_size), sizeof(kData));
memcpy(read_buffer->data(), kData, sizeof(kData));
// Simulate the MimeSniffingResourceHandler asking the
// InterceptingResourceHandler to switch to a new handler.
net::URLRequestStatus new_handler_status;
- size_t new_handler_final_bytes_read = 0;
- std::unique_ptr<TestResourceHandler> new_handler(new TestResourceHandler(
- &new_handler_status, &new_handler_final_bytes_read,
- false, // on_response_started
- true, // on_will_read
- true)); // on_read_completed
+ std::string new_handler_body;
+ std::unique_ptr<TestResourceHandler> new_handler(
+ new TestResourceHandler(&new_handler_status, &new_handler_body));
+ new_handler->set_on_response_started_result(false);
intercepting_handler->UseNewHandler(std::move(new_handler), std::string());
// The response is received. The new ResourceHandler should tell us to fail.
@@ -503,9 +468,9 @@ TEST_F(InterceptingResourceHandlerTest, NewHandlerFailsWillRead) {
false); // is_using_lofi
net::URLRequestStatus old_handler_status;
- size_t old_handler_final_bytes_read = 0;
- std::unique_ptr<TestResourceHandler> old_handler(new TestResourceHandler(
- &old_handler_status, &old_handler_final_bytes_read));
+ std::string old_handler_body;
+ std::unique_ptr<TestResourceHandler> old_handler(
+ new TestResourceHandler(&old_handler_status, &old_handler_body));
scoped_refptr<net::IOBuffer> old_buffer = old_handler.get()->buffer();
std::unique_ptr<InterceptingResourceHandler> intercepting_handler(
new InterceptingResourceHandler(std::move(old_handler), request.get()));
@@ -521,19 +486,17 @@ TEST_F(InterceptingResourceHandlerTest, NewHandlerFailsWillRead) {
EXPECT_TRUE(intercepting_handler->OnWillRead(&read_buffer, &buf_size, -1));
const char kData[] = "The data";
- ASSERT_EQ(read_buffer.get(), old_buffer.get());
+ ASSERT_NE(read_buffer.get(), old_buffer.get());
ASSERT_GT(static_cast<size_t>(buf_size), sizeof(kData));
memcpy(read_buffer->data(), kData, sizeof(kData));
// Simulate the MimeSniffingResourceHandler asking the
// InterceptingResourceHandler to switch to a new handler.
net::URLRequestStatus new_handler_status;
- size_t new_handler_final_bytes_read = 0;
- std::unique_ptr<TestResourceHandler> new_handler(new TestResourceHandler(
- &new_handler_status, &new_handler_final_bytes_read,
- true, // on_response_started
- false, // on_will_read
- true)); // on_read_completed
+ std::string new_handler_body;
+ std::unique_ptr<TestResourceHandler> new_handler(
+ new TestResourceHandler(&new_handler_status, &new_handler_body));
+ new_handler->set_on_will_read_result(false);
intercepting_handler->UseNewHandler(std::move(new_handler), std::string());
// The response is received. The new handler should not have been asked to
@@ -568,9 +531,9 @@ TEST_F(InterceptingResourceHandlerTest, NewHandlerFailsReadCompleted) {
false); // is_using_lofi
net::URLRequestStatus old_handler_status;
- size_t old_handler_final_bytes_read = 0;
- std::unique_ptr<TestResourceHandler> old_handler(new TestResourceHandler(
- &old_handler_status, &old_handler_final_bytes_read));
+ std::string old_handler_body;
+ std::unique_ptr<TestResourceHandler> old_handler(
+ new TestResourceHandler(&old_handler_status, &old_handler_body));
scoped_refptr<net::IOBuffer> old_buffer = old_handler.get()->buffer();
std::unique_ptr<InterceptingResourceHandler> intercepting_handler(
new InterceptingResourceHandler(std::move(old_handler), request.get()));
@@ -586,19 +549,17 @@ TEST_F(InterceptingResourceHandlerTest, NewHandlerFailsReadCompleted) {
EXPECT_TRUE(intercepting_handler->OnWillRead(&read_buffer, &buf_size, -1));
const char kData[] = "The data";
- ASSERT_EQ(read_buffer.get(), old_buffer.get());
+ ASSERT_NE(read_buffer.get(), old_buffer.get());
ASSERT_GT(static_cast<size_t>(buf_size), sizeof(kData));
memcpy(read_buffer->data(), kData, sizeof(kData));
// Simulate the MimeSniffingResourceHandler asking the
// InterceptingResourceHandler to switch to a new handler.
net::URLRequestStatus new_handler_status;
- size_t new_handler_final_bytes_read = 0;
- std::unique_ptr<TestResourceHandler> new_handler(new TestResourceHandler(
- &new_handler_status, &new_handler_final_bytes_read,
- true, // on_response_started
- true, // on_will_read
- false)); // on_read_completed
+ std::string new_handler_body;
+ std::unique_ptr<TestResourceHandler> new_handler(
+ new TestResourceHandler(&new_handler_status, &new_handler_body));
+ new_handler->set_on_read_completed_result(false);
intercepting_handler->UseNewHandler(std::move(new_handler), std::string());
// The response is received.
@@ -613,6 +574,315 @@ TEST_F(InterceptingResourceHandlerTest, NewHandlerFailsReadCompleted) {
EXPECT_FALSE(defer);
}
+// The old handler sets |defer| to true in OnReadCompleted and
+// OnResponseCompleted. The new handler sets |defer| to true in
+// OnResponseStarted and OnReadCompleted.
+TEST_F(InterceptingResourceHandlerTest, DeferredOperations) {
+ net::URLRequestContext context;
+ std::unique_ptr<net::URLRequest> request(context.CreateRequest(
+ GURL("http://www.google.com"), net::DEFAULT_PRIORITY, nullptr));
+ ResourceRequestInfo::AllocateForTesting(request.get(),
+ RESOURCE_TYPE_MAIN_FRAME,
+ nullptr, // context
+ 0, // render_process_id
+ 0, // render_view_id
+ 0, // render_frame_id
+ true, // is_main_frame
+ false, // parent_is_main_frame
+ true, // allow_download
+ true, // is_async
+ false); // is_using_lofi
+
+ std::unique_ptr<TestResourceController> resource_controller =
+ base::MakeUnique<TestResourceController>();
+ net::URLRequestStatus old_handler_status = {net::URLRequestStatus::IO_PENDING,
+ 0};
+ std::string old_handler_body;
+ std::unique_ptr<TestResourceHandler> old_handler(
+ new TestResourceHandler(&old_handler_status, &old_handler_body));
+ old_handler->SetBufferSize(10);
+ old_handler->set_defer_on_read_completed(true);
+
+ scoped_refptr<net::IOBuffer> old_buffer = old_handler.get()->buffer();
+ std::unique_ptr<InterceptingResourceHandler> intercepting_handler(
+ new InterceptingResourceHandler(std::move(old_handler), request.get()));
+ intercepting_handler->SetController(resource_controller.get());
+
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+
+ // Simulate the MimeSniffingResourceHandler buffering the data.
+ scoped_refptr<net::IOBuffer> read_buffer;
+ int buf_size = 0;
+ bool defer = false;
+ EXPECT_TRUE(intercepting_handler->OnWillStart(GURL(), &defer));
+ EXPECT_FALSE(defer);
+ EXPECT_TRUE(intercepting_handler->OnWillRead(&read_buffer, &buf_size, -1));
+
+ const char kData[] = "The data";
+ ASSERT_NE(read_buffer.get(), old_buffer.get());
+ ASSERT_GT(static_cast<size_t>(buf_size), strlen(kData));
+ memcpy(read_buffer->data(), kData, strlen(kData));
+
+ // Simulate the MimeSniffingResourceHandler asking the
+ // InterceptingResourceHandler to switch to a new handler.
+ net::URLRequestStatus new_handler_status = {net::URLRequestStatus::IO_PENDING,
+ 0};
+
+ std::string new_handler_body;
+ const std::string kPayload = "The long long long long long payload";
+ ASSERT_GT(kPayload.size(), static_cast<size_t>(buf_size));
+ std::unique_ptr<TestResourceHandler> new_handler(
+ new TestResourceHandler(&new_handler_status, &new_handler_body));
+ new_handler->SetBufferSize(1);
+ new_handler->set_defer_on_will_start(true);
+ new_handler->set_defer_on_response_started(true);
+ new_handler->set_defer_on_read_completed(true);
+ new_handler->set_defer_on_response_completed(true);
+ intercepting_handler->UseNewHandler(std::move(new_handler), kPayload);
+
+ // The response is received, and then deferred by the old handler's
+ // OnReadCompleted method.
+ ASSERT_TRUE(intercepting_handler->OnResponseStarted(response.get(), &defer));
+ ASSERT_TRUE(defer);
+
+ // The old handler has received the first N bytes of the payload synchronously
+ // where N is the size of the buffer exposed via OnWillRead.
+ EXPECT_EQ("The long l", old_handler_body);
+ EXPECT_EQ(std::string(), new_handler_body);
+ EXPECT_EQ(old_handler_status.status(), net::URLRequestStatus::IO_PENDING);
+ EXPECT_EQ(new_handler_status.status(), net::URLRequestStatus::IO_PENDING);
+
+ // Run until the new handler's OnWillStart method defers the request.
+ intercepting_handler->Resume();
+ EXPECT_EQ(0, resource_controller->resume_calls());
+ EXPECT_EQ(kPayload, old_handler_body);
+ EXPECT_EQ(std::string(), new_handler_body);
+ EXPECT_EQ(old_handler_status.status(), net::URLRequestStatus::SUCCESS);
+ EXPECT_EQ(new_handler_status.status(), net::URLRequestStatus::IO_PENDING);
+
+ // Run until the new handler's OnResponseStarted method defers the request.
+ intercepting_handler->Resume();
+ EXPECT_EQ(0, resource_controller->resume_calls());
+ EXPECT_EQ(std::string(), new_handler_body);
+ EXPECT_EQ(old_handler_status.status(), net::URLRequestStatus::SUCCESS);
+ EXPECT_EQ(new_handler_status.status(), net::URLRequestStatus::IO_PENDING);
+
+ // Resuming should finally call back into the ResourceController.
+ intercepting_handler->Resume();
+ EXPECT_EQ(1, resource_controller->resume_calls());
+
+ // Data is read, the new handler defers completion of the read.
+ defer = false;
+ ASSERT_TRUE(intercepting_handler->OnReadCompleted(strlen(kData), &defer));
+ ASSERT_TRUE(defer);
+
+ EXPECT_EQ(kPayload, old_handler_body);
+ EXPECT_EQ("T", new_handler_body);
+
+ intercepting_handler->Resume();
+ EXPECT_EQ(2, resource_controller->resume_calls());
+ EXPECT_EQ(kPayload, old_handler_body);
+ EXPECT_EQ(kData, new_handler_body);
+
+ EXPECT_EQ(old_handler_status.status(), net::URLRequestStatus::SUCCESS);
+ EXPECT_EQ(new_handler_status.status(), net::URLRequestStatus::IO_PENDING);
+
+ defer = false;
+ intercepting_handler->OnResponseCompleted({net::URLRequestStatus::SUCCESS, 0},
+ &defer);
+ ASSERT_TRUE(defer);
+ EXPECT_EQ(old_handler_status.status(), net::URLRequestStatus::SUCCESS);
+ EXPECT_EQ(new_handler_status.status(), net::URLRequestStatus::SUCCESS);
+}
+
+// Test cancellation where there is only the old handler in an
+// InterceptingResourceHandler.
+TEST_F(InterceptingResourceHandlerTest, CancelOldHandler) {
+ net::URLRequestContext context;
+ std::unique_ptr<net::URLRequest> request(context.CreateRequest(
+ GURL("http://www.google.com"), net::DEFAULT_PRIORITY, nullptr));
+ ResourceRequestInfo::AllocateForTesting(request.get(),
+ RESOURCE_TYPE_MAIN_FRAME,
+ nullptr, // context
+ 0, // render_process_id
+ 0, // render_view_id
+ 0, // render_frame_id
+ true, // is_main_frame
+ false, // parent_is_main_frame
+ true, // allow_download
+ true, // is_async
+ false); // is_using_lofi
+
+ std::unique_ptr<TestResourceController> resource_controller =
+ base::MakeUnique<TestResourceController>();
+ net::URLRequestStatus old_handler_status = {net::URLRequestStatus::IO_PENDING,
+ 0};
+ std::string old_handler_body;
+ std::unique_ptr<TestResourceHandler> old_handler(
+ new TestResourceHandler(&old_handler_status, &old_handler_body));
+
+ std::unique_ptr<InterceptingResourceHandler> intercepting_handler(
+ new InterceptingResourceHandler(std::move(old_handler), request.get()));
+ intercepting_handler->SetController(resource_controller.get());
+
+ EXPECT_EQ(net::URLRequestStatus::IO_PENDING, old_handler_status.status());
+
+ bool defer = false;
+ intercepting_handler->OnResponseCompleted(
+ {net::URLRequestStatus::CANCELED, net::ERR_FAILED}, &defer);
+ ASSERT_FALSE(defer);
+ EXPECT_EQ(0, resource_controller->resume_calls());
+ EXPECT_EQ(net::URLRequestStatus::CANCELED, old_handler_status.status());
+}
+
+// Test cancellation where there is only the new handler in an
+// InterceptingResourceHandler.
+TEST_F(InterceptingResourceHandlerTest, CancelNewHandler) {
+ net::URLRequestContext context;
+ std::unique_ptr<net::URLRequest> request(context.CreateRequest(
+ GURL("http://www.google.com"), net::DEFAULT_PRIORITY, nullptr));
+ ResourceRequestInfo::AllocateForTesting(request.get(),
+ RESOURCE_TYPE_MAIN_FRAME,
+ nullptr, // context
+ 0, // render_process_id
+ 0, // render_view_id
+ 0, // render_frame_id
+ true, // is_main_frame
+ false, // parent_is_main_frame
+ true, // allow_download
+ true, // is_async
+ false); // is_using_lofi
+
+ std::unique_ptr<TestResourceController> resource_controller =
+ base::MakeUnique<TestResourceController>();
+ net::URLRequestStatus old_handler_status = {net::URLRequestStatus::IO_PENDING,
+ 0};
+ std::string old_handler_body;
+ std::unique_ptr<TestResourceHandler> old_handler(
+ new TestResourceHandler(&old_handler_status, &old_handler_body));
+
+ std::unique_ptr<InterceptingResourceHandler> intercepting_handler(
+ new InterceptingResourceHandler(std::move(old_handler), request.get()));
+ intercepting_handler->SetController(resource_controller.get());
+
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+
+ // Simulate the MimeSniffingResourceHandler buffering the data.
+ scoped_refptr<net::IOBuffer> read_buffer;
+ int buf_size = 0;
+ bool defer = false;
+ EXPECT_TRUE(intercepting_handler->OnWillStart(GURL(), &defer));
+ EXPECT_FALSE(defer);
+ EXPECT_TRUE(intercepting_handler->OnWillRead(&read_buffer, &buf_size, -1));
+
+ const char kData[] = "The data";
+ ASSERT_GT(static_cast<size_t>(buf_size), strlen(kData));
+ memcpy(read_buffer->data(), kData, strlen(kData));
+
+ // Simulate the MimeSniffingResourceHandler asking the
+ // InterceptingResourceHandler to switch to a new handler.
+ net::URLRequestStatus new_handler_status = {net::URLRequestStatus::IO_PENDING,
+ 0};
+
+ std::string new_handler_body;
+ const std::string kPayload = "The payload";
+ std::unique_ptr<TestResourceHandler> new_handler(
+ new TestResourceHandler(&new_handler_status, &new_handler_body));
+ new_handler->SetBufferSize(1);
+ new_handler->set_defer_on_response_started(true);
+ new_handler->set_defer_on_response_completed(true);
+ intercepting_handler->UseNewHandler(std::move(new_handler), kPayload);
+
+ // The response is received.
+ ASSERT_TRUE(intercepting_handler->OnResponseStarted(response.get(), &defer));
+ ASSERT_TRUE(defer);
+
+ EXPECT_EQ(net::URLRequestStatus::SUCCESS, old_handler_status.status());
+ EXPECT_EQ(net::URLRequestStatus::IO_PENDING, new_handler_status.status());
+
+ defer = false;
+ intercepting_handler->OnResponseCompleted(
+ {net::URLRequestStatus::CANCELED, net::ERR_FAILED}, &defer);
+ ASSERT_TRUE(defer);
+ EXPECT_EQ(0, resource_controller->resume_calls());
+ EXPECT_EQ(net::URLRequestStatus::SUCCESS, old_handler_status.status());
+ EXPECT_EQ(net::URLRequestStatus::CANCELED, new_handler_status.status());
+}
+
+// Test cancellation where there are both the old and the new handlers in an
+// InterceptingResourceHandler.
+TEST_F(InterceptingResourceHandlerTest, CancelBothHandlers) {
+ net::URLRequestContext context;
+ std::unique_ptr<net::URLRequest> request(context.CreateRequest(
+ GURL("http://www.google.com"), net::DEFAULT_PRIORITY, nullptr));
+ ResourceRequestInfo::AllocateForTesting(request.get(),
+ RESOURCE_TYPE_MAIN_FRAME,
+ nullptr, // context
+ 0, // render_process_id
+ 0, // render_view_id
+ 0, // render_frame_id
+ true, // is_main_frame
+ false, // parent_is_main_frame
+ true, // allow_download
+ true, // is_async
+ false); // is_using_lofi
+
+ std::unique_ptr<TestResourceController> resource_controller =
+ base::MakeUnique<TestResourceController>();
+ net::URLRequestStatus old_handler_status = {net::URLRequestStatus::IO_PENDING,
+ 0};
+ std::string old_handler_body;
+ std::unique_ptr<TestResourceHandler> old_handler(
+ new TestResourceHandler(&old_handler_status, &old_handler_body));
+ old_handler->set_defer_on_read_completed(true);
+
+ std::unique_ptr<InterceptingResourceHandler> intercepting_handler(
+ new InterceptingResourceHandler(std::move(old_handler), request.get()));
+ intercepting_handler->SetController(resource_controller.get());
+
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+
+ // Simulate the MimeSniffingResourceHandler buffering the data.
+ scoped_refptr<net::IOBuffer> read_buffer;
+ int buf_size = 0;
+ bool defer = false;
+ EXPECT_TRUE(intercepting_handler->OnWillStart(GURL(), &defer));
+ EXPECT_FALSE(defer);
+ EXPECT_TRUE(intercepting_handler->OnWillRead(&read_buffer, &buf_size, -1));
+
+ const char kData[] = "The data";
+ ASSERT_GT(static_cast<size_t>(buf_size), strlen(kData));
+ memcpy(read_buffer->data(), kData, strlen(kData));
+
+ // Simulate the MimeSniffingResourceHandler asking the
+ // InterceptingResourceHandler to switch to a new handler.
+ net::URLRequestStatus new_handler_status = {net::URLRequestStatus::IO_PENDING,
+ 0};
+
+ std::string new_handler_body;
+ const std::string kPayload = "The payload";
+ std::unique_ptr<TestResourceHandler> new_handler(
+ new TestResourceHandler(&new_handler_status, &new_handler_body));
+ new_handler->SetBufferSize(1);
+ new_handler->set_defer_on_response_completed(true);
+ intercepting_handler->UseNewHandler(std::move(new_handler), kPayload);
+
+ // The response is received.
+ ASSERT_TRUE(intercepting_handler->OnResponseStarted(response.get(), &defer));
+ ASSERT_TRUE(defer);
+
+ EXPECT_EQ(net::URLRequestStatus::IO_PENDING, old_handler_status.status());
+ EXPECT_EQ(net::URLRequestStatus::IO_PENDING, new_handler_status.status());
+
+ defer = false;
+ intercepting_handler->OnResponseCompleted(
+ {net::URLRequestStatus::CANCELED, net::ERR_FAILED}, &defer);
+ ASSERT_TRUE(defer);
+ EXPECT_EQ(0, resource_controller->resume_calls());
+ EXPECT_EQ(net::URLRequestStatus::CANCELED, old_handler_status.status());
+ EXPECT_EQ(net::URLRequestStatus::CANCELED, new_handler_status.status());
+}
+
} // namespace
} // namespace content
diff --git a/chromium/content/browser/loader/mime_sniffing_resource_handler.cc b/chromium/content/browser/loader/mime_sniffing_resource_handler.cc
index bba9d01aa6a..3e5e414ff1c 100644
--- a/chromium/content/browser/loader/mime_sniffing_resource_handler.cc
+++ b/chromium/content/browser/loader/mime_sniffing_resource_handler.cc
@@ -406,7 +406,7 @@ bool MimeSniffingResourceHandler::MaybeStartInterception(bool* defer) {
return true;
}
- // This is request is a download,
+ // This request is a download.
if (!CheckResponseIsNotProvisional())
return false;
diff --git a/chromium/content/browser/loader/mime_sniffing_resource_handler_unittest.cc b/chromium/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
index 4e8e912e4b1..92a8a1fca76 100644
--- a/chromium/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
+++ b/chromium/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
@@ -12,10 +12,12 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/browser/loader/intercepting_resource_handler.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/loader/test_resource_handler.h"
#include "content/public/browser/resource_controller.h"
#include "content/public/browser/resource_dispatcher_host_delegate.h"
#include "content/public/browser/resource_request_info.h"
@@ -33,97 +35,6 @@ namespace content {
namespace {
-class TestResourceHandler : public ResourceHandler {
- public:
- TestResourceHandler(bool response_started_succeeds,
- bool defer_on_response_started,
- bool will_read_succeeds,
- bool read_completed_succeeds,
- bool defer_on_read_completed)
- : ResourceHandler(nullptr),
- buffer_(new net::IOBuffer(2048)),
- response_started_succeeds_(response_started_succeeds),
- defer_on_response_started_(defer_on_response_started),
- will_read_succeeds_(will_read_succeeds),
- read_completed_succeeds_(read_completed_succeeds),
- defer_on_read_completed_(defer_on_read_completed),
- on_will_start_called_(0),
- on_request_redirected_called_(0),
- on_response_started_called_(0),
- on_will_read_called_(0),
- on_read_completed_called_(0) {}
-
- void SetController(ResourceController* controller) override {}
-
- bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
- ResourceResponse* response,
- bool* defer) override {
- on_request_redirected_called_++;
- NOTREACHED();
- return false;
- }
-
- bool OnResponseStarted(ResourceResponse* response, bool* defer) override {
- on_response_started_called_++;
- if (defer_on_response_started_)
- *defer = true;
- return response_started_succeeds_;
- }
-
- bool OnWillStart(const GURL& url, bool* defer) override {
- on_will_start_called_++;
- return false;
- }
-
- bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
- int* buf_size,
- int min_size) override {
- on_will_read_called_++;
- *buf = buffer_;
- *buf_size = 2048;
- return will_read_succeeds_;
- }
-
- bool OnReadCompleted(int bytes_read, bool* defer) override {
- DCHECK_LT(bytes_read, 2048);
- on_read_completed_called_++;
- if (defer_on_read_completed_)
- *defer = true;
- return read_completed_succeeds_;
- }
-
- void OnResponseCompleted(const net::URLRequestStatus& status,
- bool* defer) override {}
-
- void OnDataDownloaded(int bytes_downloaded) override { NOTREACHED(); }
-
- scoped_refptr<net::IOBuffer> buffer() { return buffer_; }
-
- int on_will_start_called() const { return on_will_start_called_; }
- int on_request_redirected_called() const {
- return on_request_redirected_called_;
- }
- int on_response_started_called() const { return on_response_started_called_; }
- int on_will_read_called() const { return on_will_read_called_; }
- int on_read_completed_called() const { return on_read_completed_called_; }
-
- private:
- scoped_refptr<net::IOBuffer> buffer_;
- bool response_started_succeeds_;
- bool defer_on_response_started_;
- bool will_read_succeeds_;
- bool read_completed_succeeds_;
- bool defer_on_read_completed_;
-
- int on_will_start_called_;
- int on_request_redirected_called_;
- int on_response_started_called_;
- int on_will_read_called_;
- int on_read_completed_called_;
-
- DISALLOW_COPY_AND_ASSIGN(TestResourceHandler);
-};
-
class TestResourceDispatcherHostDelegate
: public ResourceDispatcherHostDelegate {
public:
@@ -179,7 +90,8 @@ class TestResourceDispatcherHost : public ResourceDispatcherHostImpl {
private:
std::unique_ptr<ResourceHandler> CreateNewResourceHandler() {
std::unique_ptr<TestResourceHandler> new_resource_handler(
- new TestResourceHandler(false, false, true, true, false));
+ new TestResourceHandler());
+ new_resource_handler->set_on_response_started_result(false);
new_resource_handler_ = new_resource_handler.get();
return std::move(new_resource_handler);
}
@@ -340,12 +252,14 @@ MimeSniffingResourceHandlerTest::TestAcceptHeaderSettingWithURLRequest(
true, // is_async
false); // is_using_lofi
+ std::unique_ptr<TestResourceHandler> scoped_test_handler(
+ new TestResourceHandler());
+ scoped_test_handler->set_on_response_started_result(false);
+
std::unique_ptr<ResourceHandler> mime_sniffing_handler(
- new MimeSniffingResourceHandler(
- std::unique_ptr<ResourceHandler>(
- new TestResourceHandler(false, false, false, false, false)),
- nullptr, nullptr, nullptr, request,
- REQUEST_CONTEXT_TYPE_UNSPECIFIED));
+ new MimeSniffingResourceHandler(std::move(scoped_test_handler), nullptr,
+ nullptr, nullptr, request,
+ REQUEST_CONTEXT_TYPE_UNSPECIFIED));
bool defer = false;
mime_sniffing_handler->OnWillStart(request->url(), &defer);
@@ -380,13 +294,16 @@ bool MimeSniffingResourceHandlerTest::TestStreamIsIntercepted(
host.SetDelegate(&host_delegate);
TestFakePluginService plugin_service(plugin_available_, plugin_stale_);
+
std::unique_ptr<InterceptingResourceHandler> intercepting_handler(
- new InterceptingResourceHandler(std::unique_ptr<ResourceHandler>(),
+ new InterceptingResourceHandler(base::MakeUnique<TestResourceHandler>(),
nullptr));
+ std::unique_ptr<TestResourceHandler> scoped_test_handler(
+ new TestResourceHandler());
+ scoped_test_handler->set_on_response_started_result(false);
std::unique_ptr<ResourceHandler> mime_handler(new MimeSniffingResourceHandler(
- std::unique_ptr<ResourceHandler>(
- new TestResourceHandler(false, false, false, false, false)),
- &host, &plugin_service, intercepting_handler.get(), request.get(),
+ std::unique_ptr<ResourceHandler>(std::move(scoped_test_handler)), &host,
+ &plugin_service, intercepting_handler.get(), request.get(),
REQUEST_CONTEXT_TYPE_UNSPECIFIED));
TestResourceController resource_controller;
@@ -397,6 +314,9 @@ bool MimeSniffingResourceHandlerTest::TestStreamIsIntercepted(
response->head.mime_type = "application/pdf";
bool defer = false;
+ mime_handler->OnWillStart(request->url(), &defer);
+ EXPECT_FALSE(defer);
+
mime_handler->OnResponseStarted(response.get(), &defer);
content::RunAllPendingInMessageLoop();
@@ -433,12 +353,16 @@ void MimeSniffingResourceHandlerTest::TestHandlerSniffing(
TestFakePluginService plugin_service(plugin_available_, plugin_stale_);
std::unique_ptr<InterceptingResourceHandler> intercepting_handler(
- new InterceptingResourceHandler(std::unique_ptr<ResourceHandler>(),
+ new InterceptingResourceHandler(base::MakeUnique<TestResourceHandler>(),
nullptr));
- std::unique_ptr<TestResourceHandler> scoped_test_handler =
- std::unique_ptr<TestResourceHandler>(new TestResourceHandler(
- response_started, defer_response_started, will_read, read_completed,
- defer_read_completed));
+
+ std::unique_ptr<TestResourceHandler> scoped_test_handler(
+ new TestResourceHandler());
+ scoped_test_handler->set_on_response_started_result(response_started);
+ scoped_test_handler->set_defer_on_response_started(defer_response_started);
+ scoped_test_handler->set_on_will_read_result(will_read);
+ scoped_test_handler->set_on_read_completed_result(read_completed);
+ scoped_test_handler->set_defer_on_read_completed(defer_read_completed);
TestResourceHandler* test_handler = scoped_test_handler.get();
std::unique_ptr<MimeSniffingResourceHandler> mime_sniffing_handler(
new MimeSniffingResourceHandler(std::move(scoped_test_handler), &host,
@@ -594,13 +518,16 @@ void MimeSniffingResourceHandlerTest::TestHandlerNoSniffing(
TestFakePluginService plugin_service(plugin_available_, plugin_stale_);
std::unique_ptr<InterceptingResourceHandler> intercepting_handler(
- new InterceptingResourceHandler(std::unique_ptr<ResourceHandler>(),
+ new InterceptingResourceHandler(base::MakeUnique<TestResourceHandler>(),
nullptr));
- std::unique_ptr<TestResourceHandler> scoped_test_handler =
- std::unique_ptr<TestResourceHandler>(new TestResourceHandler(
- response_started, defer_response_started, will_read, read_completed,
- defer_read_completed));
+ std::unique_ptr<TestResourceHandler> scoped_test_handler(
+ new TestResourceHandler());
+ scoped_test_handler->set_on_response_started_result(response_started);
+ scoped_test_handler->set_defer_on_response_started(defer_response_started);
+ scoped_test_handler->set_on_will_read_result(will_read);
+ scoped_test_handler->set_on_read_completed_result(read_completed);
+ scoped_test_handler->set_defer_on_read_completed(defer_read_completed);
TestResourceHandler* test_handler = scoped_test_handler.get();
std::unique_ptr<MimeSniffingResourceHandler> mime_sniffing_handler(
new MimeSniffingResourceHandler(std::move(scoped_test_handler), &host,
@@ -988,18 +915,22 @@ TEST_F(MimeSniffingResourceHandlerTest, 304Handling) {
TestFakePluginService plugin_service(false, false);
std::unique_ptr<ResourceHandler> intercepting_handler(
- new InterceptingResourceHandler(std::unique_ptr<ResourceHandler>(),
+ new InterceptingResourceHandler(base::MakeUnique<TestResourceHandler>(),
nullptr));
std::unique_ptr<ResourceHandler> mime_handler(new MimeSniffingResourceHandler(
- std::unique_ptr<ResourceHandler>(
- new TestResourceHandler(true, false, true, true, false)),
- &host, &plugin_service,
+ std::unique_ptr<ResourceHandler>(new TestResourceHandler()), &host,
+ &plugin_service,
static_cast<InterceptingResourceHandler*>(intercepting_handler.get()),
request.get(), REQUEST_CONTEXT_TYPE_UNSPECIFIED));
TestResourceController resource_controller;
mime_handler->SetController(&resource_controller);
+ // Request starts.
+ bool defer = false;
+ mime_handler->OnWillStart(request->url(), &defer);
+ EXPECT_FALSE(defer);
+
// Simulate a 304 response.
scoped_refptr<ResourceResponse> response(new ResourceResponse);
// The MIME type isn't important but it shouldn't be empty.
@@ -1008,7 +939,6 @@ TEST_F(MimeSniffingResourceHandlerTest, 304Handling) {
// The response is received. No new ResourceHandler should be created to
// handle the download.
- bool defer = false;
mime_handler->OnResponseStarted(response.get(), &defer);
EXPECT_FALSE(defer);
EXPECT_FALSE(host.new_resource_handler());
@@ -1036,14 +966,12 @@ TEST_F(MimeSniffingResourceHandlerTest, FetchShouldDisableMimeSniffing) {
TestFakePluginService plugin_service(false, false);
std::unique_ptr<InterceptingResourceHandler> intercepting_handler(
- new InterceptingResourceHandler(nullptr, nullptr));
+ new InterceptingResourceHandler(base::MakeUnique<TestResourceHandler>(),
+ nullptr));
std::unique_ptr<TestResourceHandler> scoped_test_handler(
- new TestResourceHandler(false, // response_started
- false, // defer_response_started
- true, // will_read,
- true, // read_completed,
- false)); // defer_read_completed
+ new TestResourceHandler());
+ scoped_test_handler->set_on_response_started_result(false);
std::unique_ptr<ResourceHandler> mime_sniffing_handler(
new MimeSniffingResourceHandler(std::move(scoped_test_handler), &host,
&plugin_service,
diff --git a/chromium/content/browser/loader/mojo_async_resource_handler.cc b/chromium/content/browser/loader/mojo_async_resource_handler.cc
index b66c389d3ff..1288fe45136 100644
--- a/chromium/content/browser/loader/mojo_async_resource_handler.cc
+++ b/chromium/content/browser/loader/mojo_async_resource_handler.cc
@@ -16,9 +16,12 @@
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/loader/resource_request_info_impl.h"
#include "content/common/resource_request_completion_status.h"
+#include "content/public/browser/global_request_id.h"
+#include "content/public/browser/resource_controller.h"
#include "content/public/browser/resource_dispatcher_host_delegate.h"
#include "content/public/common/resource_response.h"
#include "mojo/public/c/system/data_pipe.h"
+#include "mojo/public/cpp/bindings/message.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
@@ -103,14 +106,18 @@ class MojoAsyncResourceHandler::WriterIOBuffer final
MojoAsyncResourceHandler::MojoAsyncResourceHandler(
net::URLRequest* request,
ResourceDispatcherHostImpl* rdh,
- mojo::InterfaceRequest<mojom::URLLoader> mojo_request,
- mojom::URLLoaderClientPtr url_loader_client)
+ mojom::URLLoaderAssociatedRequest mojo_request,
+ mojom::URLLoaderClientAssociatedPtr url_loader_client)
: ResourceHandler(request),
rdh_(rdh),
binding_(this, std::move(mojo_request)),
url_loader_client_(std::move(url_loader_client)) {
DCHECK(url_loader_client_);
InitializeResourceBufferConstants();
+ // This unretained pointer is safe, because |binding_| is owned by |this| and
+ // the callback will never be called after |this| is destroyed.
+ binding_.set_connection_error_handler(
+ base::Bind(&MojoAsyncResourceHandler::Cancel, base::Unretained(this)));
}
MojoAsyncResourceHandler::~MojoAsyncResourceHandler() {
@@ -122,8 +129,24 @@ bool MojoAsyncResourceHandler::OnRequestRedirected(
const net::RedirectInfo& redirect_info,
ResourceResponse* response,
bool* defer) {
- // Not implemented.
- return false;
+ // Unlike OnResponseStarted, OnRequestRedirected will NOT be preceded by
+ // OnWillRead.
+ DCHECK(!shared_writer_);
+
+ *defer = true;
+ request()->LogBlockedBy("MojoAsyncResourceHandler");
+ did_defer_on_redirect_ = true;
+
+ NetLogObserver::PopulateResponseInfo(request(), response);
+ response->head.encoded_data_length = request()->GetTotalReceivedBytes();
+ response->head.request_start = request()->creation_time();
+ response->head.response_start = base::TimeTicks::Now();
+ // TODO(davidben): Is it necessary to pass the new first party URL for
+ // cookies? The only case where it can change is top-level navigation requests
+ // and hopefully those will eventually all be owned by the browser. It's
+ // possible this is still needed while renderer-owned ones exist.
+ url_loader_client_->OnReceiveRedirect(redirect_info, response->head);
+ return true;
}
bool MojoAsyncResourceHandler::OnResponseStarted(ResourceResponse* response,
@@ -213,8 +236,10 @@ bool MojoAsyncResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
buffer_bytes_read_ = bytes_read;
if (!CopyReadDataToDataPipe(defer))
return false;
- if (*defer)
- OnDefer();
+ if (*defer) {
+ request()->LogBlockedBy("MojoAsyncResourceHandler");
+ did_defer_on_writing_ = true;
+ }
return true;
}
@@ -224,25 +249,42 @@ bool MojoAsyncResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
// doesn't have |defer| parameter.
if (!AllocateWriterIOBuffer(&buffer_, defer))
return false;
- if (*defer)
- OnDefer();
+ if (*defer) {
+ request()->LogBlockedBy("MojoAsyncResourceHandler");
+ did_defer_on_writing_ = true;
+ }
return true;
}
void MojoAsyncResourceHandler::OnDataDownloaded(int bytes_downloaded) {
- // Not implemented.
+ int64_t total_received_bytes = request()->GetTotalReceivedBytes();
+ int64_t bytes_to_report =
+ total_received_bytes - reported_total_received_bytes_;
+ reported_total_received_bytes_ = total_received_bytes;
+ DCHECK_LE(0, bytes_to_report);
+
+ url_loader_client_->OnDataDownloaded(bytes_downloaded, bytes_to_report);
}
void MojoAsyncResourceHandler::FollowRedirect() {
- NOTIMPLEMENTED();
-}
+ if (!request()->status().is_success()) {
+ DVLOG(1) << "FollowRedirect for invalid request";
+ return;
+ }
+ if (!did_defer_on_redirect_) {
+ DVLOG(1) << "Malformed FollowRedirect request";
+ ReportBadMessage("Malformed FollowRedirect request");
+ return;
+ }
-void MojoAsyncResourceHandler::Cancel() {
- NOTIMPLEMENTED();
+ DCHECK(!did_defer_on_writing_);
+ did_defer_on_redirect_ = false;
+ request()->LogUnblocked();
+ controller()->Resume();
}
-void MojoAsyncResourceHandler::ResumeForTesting() {
- Resume();
+void MojoAsyncResourceHandler::OnWritableForTesting() {
+ OnWritable(MOJO_RESULT_OK);
}
void MojoAsyncResourceHandler::SetAllocationSizeForTesting(size_t size) {
@@ -344,54 +386,56 @@ bool MojoAsyncResourceHandler::AllocateWriterIOBuffer(
return true;
}
-void MojoAsyncResourceHandler::Resume() {
- if (!did_defer_)
+bool MojoAsyncResourceHandler::CheckForSufficientResource() {
+ if (has_checked_for_sufficient_resources_)
+ return true;
+ has_checked_for_sufficient_resources_ = true;
+
+ if (rdh_->HasSufficientResourcesForRequest(request()))
+ return true;
+
+ controller()->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
+ return false;
+}
+
+void MojoAsyncResourceHandler::OnWritable(MojoResult result) {
+ if (!did_defer_on_writing_)
return;
- bool defer = false;
+ DCHECK(!did_defer_on_redirect_);
+ did_defer_on_writing_ = false;
+
if (is_using_io_buffer_not_from_writer_) {
// |buffer_| is set to a net::IOBufferWithSize. Write the buffer contents
// to the data pipe.
DCHECK_GT(buffer_bytes_read_, 0u);
- if (!CopyReadDataToDataPipe(&defer)) {
+ if (!CopyReadDataToDataPipe(&did_defer_on_writing_)) {
controller()->CancelWithError(net::ERR_FAILED);
return;
}
} else {
// Allocate a buffer for the next OnWillRead call here.
- if (!AllocateWriterIOBuffer(&buffer_, &defer)) {
+ if (!AllocateWriterIOBuffer(&buffer_, &did_defer_on_writing_)) {
controller()->CancelWithError(net::ERR_FAILED);
return;
}
}
- if (defer) {
+ if (did_defer_on_writing_) {
// Continue waiting.
return;
}
- did_defer_ = false;
request()->LogUnblocked();
controller()->Resume();
}
-void MojoAsyncResourceHandler::OnDefer() {
- request()->LogBlockedBy("MojoAsyncResourceHandler");
- did_defer_ = true;
-}
-
-bool MojoAsyncResourceHandler::CheckForSufficientResource() {
- if (has_checked_for_sufficient_resources_)
- return true;
- has_checked_for_sufficient_resources_ = true;
-
- if (rdh_->HasSufficientResourcesForRequest(request()))
- return true;
-
- controller()->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
- return false;
+void MojoAsyncResourceHandler::Cancel() {
+ const ResourceRequestInfoImpl* info = GetRequestInfo();
+ ResourceDispatcherHostImpl::Get()->CancelRequestFromRenderer(
+ GlobalRequestID(info->GetChildID(), info->GetRequestID()));
}
-void MojoAsyncResourceHandler::OnWritable(MojoResult unused) {
- Resume();
+void MojoAsyncResourceHandler::ReportBadMessage(const std::string& error) {
+ mojo::ReportBadMessage(error);
}
} // namespace content
diff --git a/chromium/content/browser/loader/mojo_async_resource_handler.h b/chromium/content/browser/loader/mojo_async_resource_handler.h
index 5df87fd090e..ae47419a956 100644
--- a/chromium/content/browser/loader/mojo_async_resource_handler.h
+++ b/chromium/content/browser/loader/mojo_async_resource_handler.h
@@ -16,7 +16,7 @@
#include "content/browser/loader/resource_handler.h"
#include "content/common/content_export.h"
#include "content/common/url_loader.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
#include "mojo/public/cpp/system/watcher.h"
#include "net/base/io_buffer.h"
#include "url/gurl.h"
@@ -27,17 +27,13 @@ class URLRequest;
namespace content {
class ResourceDispatcherHostImpl;
-class ResourceRequestInfoImpl;
struct ResourceResponse;
// Used to complete an asynchronous resource request in response to resource
// load events from the resource dispatcher host. This class is used only
// when LoadingWithMojo runtime flag is enabled.
//
-// TODO(yhirano): Implement redirects.
-// TODO(yhirano): Implement downloading to file.
// TODO(yhirano): Add histograms.
-// TODO(yhirano): Set zoom level.
// TODO(yhirano): Send cached metadata.
//
// This class can be inherited only for tests.
@@ -48,8 +44,8 @@ class CONTENT_EXPORT MojoAsyncResourceHandler
MojoAsyncResourceHandler(
net::URLRequest* request,
ResourceDispatcherHostImpl* rdh,
- mojo::InterfaceRequest<mojom::URLLoader> mojo_request,
- mojom::URLLoaderClientPtr url_loader_client);
+ mojom::URLLoaderAssociatedRequest mojo_request,
+ mojom::URLLoaderClientAssociatedPtr url_loader_client);
~MojoAsyncResourceHandler() override;
// ResourceHandler implementation:
@@ -68,9 +64,8 @@ class CONTENT_EXPORT MojoAsyncResourceHandler
// mojom::URLLoader implementation
void FollowRedirect() override;
- void Cancel() override;
- void ResumeForTesting();
+ void OnWritableForTesting();
static void SetAllocationSizeForTesting(size_t size);
static constexpr size_t kDefaultAllocationSize = 512 * 1024;
@@ -92,23 +87,26 @@ class CONTENT_EXPORT MojoAsyncResourceHandler
bool AllocateWriterIOBuffer(scoped_refptr<net::IOBufferWithSize>* buf,
bool* defer);
- void Resume();
- void OnDefer();
bool CheckForSufficientResource();
void OnWritable(MojoResult result);
+ void Cancel();
+ // This function can be overriden only for tests.
+ virtual void ReportBadMessage(const std::string& error);
ResourceDispatcherHostImpl* rdh_;
- mojo::Binding<mojom::URLLoader> binding_;
+ mojo::AssociatedBinding<mojom::URLLoader> binding_;
bool has_checked_for_sufficient_resources_ = false;
bool sent_received_response_message_ = false;
bool is_using_io_buffer_not_from_writer_ = false;
- bool did_defer_ = false;
+ bool did_defer_on_writing_ = false;
+ bool did_defer_on_redirect_ = false;
base::TimeTicks response_started_ticks_;
+ int64_t reported_total_received_bytes_ = 0;
mojo::Watcher handle_watcher_;
std::unique_ptr<mojom::URLLoader> url_loader_;
- mojom::URLLoaderClientPtr url_loader_client_;
+ mojom::URLLoaderClientAssociatedPtr url_loader_client_;
scoped_refptr<net::IOBufferWithSize> buffer_;
size_t buffer_offset_ = 0;
size_t buffer_bytes_read_ = 0;
diff --git a/chromium/content/browser/loader/mojo_async_resource_handler_unittest.cc b/chromium/content/browser/loader/mojo_async_resource_handler_unittest.cc
index 5386d6e906f..4ad1ba638fe 100644
--- a/chromium/content/browser/loader/mojo_async_resource_handler_unittest.cc
+++ b/chromium/content/browser/loader/mojo_async_resource_handler_unittest.cc
@@ -33,6 +33,7 @@
#include "content/public/test/test_browser_thread_bundle.h"
#include "mojo/public/c/system/data_pipe.h"
#include "mojo/public/c/system/types.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "net/base/auth.h"
#include "net/base/net_errors.h"
@@ -98,12 +99,7 @@ class TestResourceDispatcherHostDelegate final
bool HandleExternalProtocol(
const GURL& url,
- int child_id,
- const ResourceRequestInfo::WebContentsGetter& web_contents_getter,
- bool is_main_frame,
- ui::PageTransition page_transition,
- bool has_user_gesture,
- ResourceContext* resource_context) override {
+ ResourceRequestInfo* resource_request_info) override {
ADD_FAILURE() << "HandleExternalProtocol should not be called.";
return false;
}
@@ -189,6 +185,10 @@ class TestResourceController : public ResourceController {
}
void CancelWithError(int error_code) override {
+ // While cancelling more than once is legal, none of these tests should do
+ // it.
+ EXPECT_FALSE(is_cancel_with_error_called_);
+
is_cancel_with_error_called_ = true;
error_ = error_code;
if (quit_closure_)
@@ -228,8 +228,8 @@ class MojoAsyncResourceHandlerWithCustomDataPipeOperations
MojoAsyncResourceHandlerWithCustomDataPipeOperations(
net::URLRequest* request,
ResourceDispatcherHostImpl* rdh,
- mojo::InterfaceRequest<mojom::URLLoader> mojo_request,
- mojom::URLLoaderClientPtr url_loader_client)
+ mojom::URLLoaderAssociatedRequest mojo_request,
+ mojom::URLLoaderClientAssociatedPtr url_loader_client)
: MojoAsyncResourceHandler(request,
rdh,
std::move(mojo_request),
@@ -246,6 +246,7 @@ class MojoAsyncResourceHandlerWithCustomDataPipeOperations
is_end_write_expectation_set_ = true;
end_write_expectation_ = end_write_expectation;
}
+ bool has_received_bad_message() const { return has_received_bad_message_; }
private:
MojoResult BeginWrite(void** data, uint32_t* available) override {
@@ -258,9 +259,13 @@ class MojoAsyncResourceHandlerWithCustomDataPipeOperations
return end_write_expectation_;
return MojoAsyncResourceHandler::EndWrite(written);
}
+ void ReportBadMessage(const std::string& error) override {
+ has_received_bad_message_ = true;
+ }
bool is_begin_write_expectation_set_ = false;
bool is_end_write_expectation_set_ = false;
+ bool has_received_bad_message_ = false;
MojoResult begin_write_expectation_ = MOJO_RESULT_UNKNOWN;
MojoResult end_write_expectation_ = MOJO_RESULT_UNKNOWN;
@@ -268,6 +273,43 @@ class MojoAsyncResourceHandlerWithCustomDataPipeOperations
MojoAsyncResourceHandlerWithCustomDataPipeOperations);
};
+class TestURLLoaderFactory final : public mojom::URLLoaderFactory {
+ public:
+ TestURLLoaderFactory() {}
+ ~TestURLLoaderFactory() override {}
+
+ void CreateLoaderAndStart(
+ mojom::URLLoaderAssociatedRequest request,
+ int32_t routing_id,
+ int32_t request_id,
+ const ResourceRequest& url_request,
+ mojom::URLLoaderClientAssociatedPtrInfo client_ptr_info) override {
+ loader_request_ = std::move(request);
+ client_ptr_info_ = std::move(client_ptr_info);
+ }
+
+ mojom::URLLoaderAssociatedRequest PassLoaderRequest() {
+ return std::move(loader_request_);
+ }
+
+ mojom::URLLoaderClientAssociatedPtrInfo PassClientPtrInfo() {
+ return std::move(client_ptr_info_);
+ }
+
+ void SyncLoad(int32_t routing_id,
+ int32_t request_id,
+ const ResourceRequest& url_request,
+ const SyncLoadCallback& callback) override {
+ NOTREACHED();
+ }
+
+ private:
+ mojom::URLLoaderAssociatedRequest loader_request_;
+ mojom::URLLoaderClientAssociatedPtrInfo client_ptr_info_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestURLLoaderFactory);
+};
+
class MojoAsyncResourceHandlerTestBase {
public:
MojoAsyncResourceHandlerTestBase()
@@ -295,9 +337,28 @@ class MojoAsyncResourceHandlerTestBase {
true, // is_async
false // is_using_lofi
);
+
+ ResourceRequest request;
+ base::WeakPtr<mojo::StrongBinding<mojom::URLLoaderFactory>> weak_binding =
+ mojo::MakeStrongBinding(base::MakeUnique<TestURLLoaderFactory>(),
+ mojo::GetProxy(&url_loader_factory_));
+
+ url_loader_factory_->CreateLoaderAndStart(
+ mojo::GetProxy(&url_loader_proxy_,
+ url_loader_factory_.associated_group()),
+ 0, 0, request, url_loader_client_.CreateRemoteAssociatedPtrInfo(
+ url_loader_factory_.associated_group()));
+
+ url_loader_factory_.FlushForTesting();
+ DCHECK(weak_binding);
+ TestURLLoaderFactory* factory_impl =
+ static_cast<TestURLLoaderFactory*>(weak_binding->impl());
+
+ mojom::URLLoaderClientAssociatedPtr client_ptr;
+ client_ptr.Bind(factory_impl->PassClientPtrInfo());
handler_.reset(new MojoAsyncResourceHandlerWithCustomDataPipeOperations(
- request_.get(), &rdh_, nullptr,
- url_loader_client_.CreateInterfacePtrAndBind()));
+ request_.get(), &rdh_, factory_impl->PassLoaderRequest(),
+ std::move(client_ptr)));
handler_->SetController(&resource_controller_);
}
@@ -349,6 +410,8 @@ class MojoAsyncResourceHandlerTestBase {
TestBrowserThreadBundle thread_bundle_;
TestResourceDispatcherHostDelegate rdh_delegate_;
ResourceDispatcherHostImpl rdh_;
+ mojom::URLLoaderFactoryPtr url_loader_factory_;
+ mojom::URLLoaderAssociatedPtr url_loader_proxy_;
TestURLLoaderClient url_loader_client_;
TestResourceController resource_controller_;
std::unique_ptr<TestBrowserContext> browser_context_;
@@ -781,7 +844,7 @@ TEST_F(MojoAsyncResourceHandlerTest,
url_loader_client_.RunUntilResponseBodyArrived();
ASSERT_TRUE(url_loader_client_.response_body().is_valid());
handler_->ResetBeginWriteExpectation();
- handler_->ResumeForTesting();
+ handler_->OnWritableForTesting();
std::string actual;
while (actual.size() < written) {
@@ -1020,6 +1083,76 @@ TEST_P(MojoAsyncResourceHandlerWithAllocationSizeTest, CancelWhileWaiting) {
EXPECT_EQ(0, resource_controller_.num_resume_calls());
}
+TEST_P(MojoAsyncResourceHandlerWithAllocationSizeTest, RedirectHandling) {
+ rdh_delegate_.set_num_on_response_started_calls_expectation(1);
+ bool defer = false;
+
+ ASSERT_TRUE(handler_->OnWillStart(request_->url(), &defer));
+ ASSERT_FALSE(defer);
+ scoped_refptr<ResourceResponse> response = new ResourceResponse();
+ net::RedirectInfo redirect_info;
+ redirect_info.status_code = 301;
+ ASSERT_TRUE(
+ handler_->OnRequestRedirected(redirect_info, response.get(), &defer));
+ ASSERT_TRUE(defer);
+
+ ASSERT_FALSE(url_loader_client_.has_received_response());
+ ASSERT_FALSE(url_loader_client_.has_received_redirect());
+ url_loader_client_.RunUntilRedirectReceived();
+
+ ASSERT_FALSE(url_loader_client_.has_received_response());
+ ASSERT_TRUE(url_loader_client_.has_received_redirect());
+ EXPECT_EQ(301, url_loader_client_.redirect_info().status_code);
+
+ EXPECT_EQ(0, resource_controller_.num_resume_calls());
+ handler_->FollowRedirect();
+ EXPECT_EQ(1, resource_controller_.num_resume_calls());
+
+ url_loader_client_.ClearHasReceivedRedirect();
+ // Redirect once more.
+ defer = false;
+ redirect_info.status_code = 302;
+ ASSERT_TRUE(
+ handler_->OnRequestRedirected(redirect_info, response.get(), &defer));
+ ASSERT_TRUE(defer);
+
+ ASSERT_FALSE(url_loader_client_.has_received_response());
+ ASSERT_FALSE(url_loader_client_.has_received_redirect());
+ url_loader_client_.RunUntilRedirectReceived();
+
+ ASSERT_FALSE(url_loader_client_.has_received_response());
+ ASSERT_TRUE(url_loader_client_.has_received_redirect());
+ EXPECT_EQ(302, url_loader_client_.redirect_info().status_code);
+
+ EXPECT_EQ(1, resource_controller_.num_resume_calls());
+ handler_->FollowRedirect();
+ EXPECT_EQ(2, resource_controller_.num_resume_calls());
+
+ // Give the final response.
+ defer = false;
+ ASSERT_TRUE(handler_->OnResponseStarted(response.get(), &defer));
+ ASSERT_FALSE(defer);
+
+ net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, net::OK);
+ handler_->OnResponseCompleted(status, &defer);
+ ASSERT_FALSE(defer);
+
+ ASSERT_FALSE(url_loader_client_.has_received_completion());
+ url_loader_client_.RunUntilComplete();
+
+ ASSERT_TRUE(url_loader_client_.has_received_response());
+ ASSERT_TRUE(url_loader_client_.has_received_completion());
+ EXPECT_EQ(net::OK, url_loader_client_.completion_status().error_code);
+}
+
+TEST_P(MojoAsyncResourceHandlerWithAllocationSizeTest,
+ MalformedFollowRedirectRequest) {
+ handler_->FollowRedirect();
+
+ EXPECT_TRUE(handler_->has_received_bad_message());
+ EXPECT_EQ(0, resource_controller_.num_resume_calls());
+}
+
// Typically ResourceHandler methods are called in this order.
TEST_P(
MojoAsyncResourceHandlerWithAllocationSizeTest,
diff --git a/chromium/content/browser/loader/navigation_resource_handler.cc b/chromium/content/browser/loader/navigation_resource_handler.cc
index 76a5d8898db..dc73b854bea 100644
--- a/chromium/content/browser/loader/navigation_resource_handler.cc
+++ b/chromium/content/browser/loader/navigation_resource_handler.cc
@@ -14,7 +14,6 @@
#include "content/browser/resource_context_impl.h"
#include "content/browser/streams/stream.h"
#include "content/browser/streams/stream_context.h"
-#include "content/common/security_style_util.h"
#include "content/public/browser/navigation_data.h"
#include "content/public/browser/resource_controller.h"
#include "content/public/browser/resource_dispatcher_host_delegate.h"
@@ -32,9 +31,7 @@ void NavigationResourceHandler::GetSSLStatusForRequest(
int child_id,
SSLStatus* ssl_status) {
DCHECK(ssl_info.cert);
- *ssl_status = SSLStatus(GetSecurityStyleForResource(
- url, !!ssl_info.cert, ssl_info.cert_status),
- ssl_info.cert, ssl_info);
+ *ssl_status = SSLStatus(ssl_info);
}
NavigationResourceHandler::NavigationResourceHandler(
diff --git a/chromium/content/browser/loader/navigation_resource_throttle.cc b/chromium/content/browser/loader/navigation_resource_throttle.cc
index 46e901fd694..e8f9e6ed25b 100644
--- a/chromium/content/browser/loader/navigation_resource_throttle.cc
+++ b/chromium/content/browser/loader/navigation_resource_throttle.cc
@@ -15,6 +15,8 @@
#include "content/browser/frame_host/navigator.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/loader/navigation_resource_handler.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/loader/resource_loader.h"
#include "content/browser/loader/resource_request_info_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_data.h"
@@ -38,6 +40,9 @@ namespace {
// NavigationHandle.
bool g_ui_checks_always_succeed = false;
+// Used in unit tests to transfer all navigations.
+bool g_force_transfer = false;
+
typedef base::Callback<void(NavigationThrottle::ThrottleCheckResult)>
UIChecksPerformedCallback;
@@ -76,11 +81,9 @@ NavigationHandleImpl* FindNavigationHandle(
}
NavigationHandleImpl* navigation_handle =
- render_frame_host->frame_tree_node()
- ->navigator()
- ->GetNavigationHandleForFrameHost(render_frame_host);
+ render_frame_host->navigation_handle();
if (!navigation_handle) {
- SendCheckResultToIOThread(callback, NavigationThrottle::PROCEED);
+ SendCheckResultToIOThread(callback, NavigationThrottle::CANCEL);
return nullptr;
}
return navigation_handle;
@@ -118,7 +121,8 @@ void CheckWillRedirectRequestOnUIThread(
const std::string& new_method,
const GURL& new_referrer_url,
bool new_is_external_protocol,
- scoped_refptr<net::HttpResponseHeaders> headers) {
+ scoped_refptr<net::HttpResponseHeaders> headers,
+ net::HttpResponseInfo::ConnectionInfo connection_info) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
NavigationHandleImpl* navigation_handle =
FindNavigationHandle(render_process_id, render_frame_host_id, callback);
@@ -130,7 +134,8 @@ void CheckWillRedirectRequestOnUIThread(
->FilterURL(false, &new_validated_url);
navigation_handle->WillRedirectRequest(
new_validated_url, new_method, new_referrer_url, new_is_external_protocol,
- headers, base::Bind(&SendCheckResultToIOThread, callback));
+ headers, connection_info,
+ base::Bind(&SendCheckResultToIOThread, callback));
}
void WillProcessResponseOnUIThread(
@@ -138,9 +143,20 @@ void WillProcessResponseOnUIThread(
int render_process_id,
int render_frame_host_id,
scoped_refptr<net::HttpResponseHeaders> headers,
+ net::HttpResponseInfo::ConnectionInfo connection_info,
const SSLStatus& ssl_status,
+ const GlobalRequestID& request_id,
+ bool should_replace_current_entry,
+ bool is_download,
+ bool is_stream,
+ const base::Closure& transfer_callback,
std::unique_ptr<NavigationData> navigation_data) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ if (g_force_transfer) {
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, transfer_callback);
+ }
+
NavigationHandleImpl* navigation_handle =
FindNavigationHandle(render_process_id, render_frame_host_id, callback);
if (!navigation_handle)
@@ -153,7 +169,8 @@ void WillProcessResponseOnUIThread(
RenderFrameHostImpl::FromID(render_process_id, render_frame_host_id);
DCHECK(render_frame_host);
navigation_handle->WillProcessResponse(
- render_frame_host, headers, ssl_status,
+ render_frame_host, headers, connection_info, ssl_status, request_id,
+ should_replace_current_entry, is_download, is_stream, transfer_callback,
base::Bind(&SendCheckResultToIOThread, callback));
}
@@ -166,6 +183,8 @@ NavigationResourceThrottle::NavigationResourceThrottle(
: request_(request),
resource_dispatcher_host_delegate_(resource_dispatcher_host_delegate),
request_context_type_(request_context_type),
+ in_cross_site_transition_(false),
+ on_transfer_done_result_(NavigationThrottle::DEFER),
weak_ptr_factory_(this) {}
NavigationResourceThrottle::~NavigationResourceThrottle() {}
@@ -238,13 +257,15 @@ void NavigationResourceThrottle::WillRedirectRequest(
base::Bind(&CheckWillRedirectRequestOnUIThread, callback,
render_process_id, render_frame_id, redirect_info.new_url,
redirect_info.new_method, GURL(redirect_info.new_referrer),
- new_is_external_protocol, response_headers));
+ new_is_external_protocol, response_headers,
+ request_->response_info().connection_info));
*defer = true;
}
void NavigationResourceThrottle::WillProcessResponse(bool* defer) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_);
+ const ResourceRequestInfoImpl* info =
+ ResourceRequestInfoImpl::ForRequest(request_);
if (!info)
return;
@@ -274,6 +295,9 @@ void NavigationResourceThrottle::WillProcessResponse(bool* defer) {
UIChecksPerformedCallback callback =
base::Bind(&NavigationResourceThrottle::OnUIChecksPerformed,
weak_ptr_factory_.GetWeakPtr());
+ base::Closure transfer_callback =
+ base::Bind(&NavigationResourceThrottle::InitiateTransfer,
+ weak_ptr_factory_.GetWeakPtr());
SSLStatus ssl_status;
if (request_->ssl_info().cert.get()) {
@@ -284,7 +308,11 @@ void NavigationResourceThrottle::WillProcessResponse(bool* defer) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&WillProcessResponseOnUIThread, callback, render_process_id,
- render_frame_id, response_headers, ssl_status,
+ render_frame_id, response_headers,
+ request_->response_info().connection_info, ssl_status,
+ info->GetGlobalRequestID(),
+ info->should_replace_current_entry(), info->IsDownload(),
+ info->is_stream(), transfer_callback,
base::Passed(&cloned_data)));
*defer = true;
}
@@ -298,9 +326,20 @@ void NavigationResourceThrottle::set_ui_checks_always_succeed_for_testing(
g_ui_checks_always_succeed = ui_checks_always_succeed;
}
+void NavigationResourceThrottle::set_force_transfer_for_testing(
+ bool force_transfer) {
+ g_force_transfer = force_transfer;
+}
+
void NavigationResourceThrottle::OnUIChecksPerformed(
NavigationThrottle::ThrottleCheckResult result) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK_NE(NavigationThrottle::DEFER, result);
+ if (in_cross_site_transition_) {
+ on_transfer_done_result_ = result;
+ return;
+ }
+
if (result == NavigationThrottle::CANCEL_AND_IGNORE) {
controller()->CancelAndIgnore();
} else if (result == NavigationThrottle::CANCEL) {
@@ -312,4 +351,28 @@ void NavigationResourceThrottle::OnUIChecksPerformed(
}
}
+void NavigationResourceThrottle::InitiateTransfer() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ in_cross_site_transition_ = true;
+ ResourceRequestInfoImpl* info =
+ ResourceRequestInfoImpl::ForRequest(request_);
+ ResourceDispatcherHostImpl::Get()->MarkAsTransferredNavigation(
+ info->GetGlobalRequestID(),
+ base::Bind(&NavigationResourceThrottle::OnTransferComplete,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void NavigationResourceThrottle::OnTransferComplete() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(in_cross_site_transition_);
+ in_cross_site_transition_ = false;
+
+ // If the results of the checks on the UI thread are known, unblock the
+ // navigation. Otherwise, wait until the callback has executed.
+ if (on_transfer_done_result_ != NavigationThrottle::DEFER) {
+ OnUIChecksPerformed(on_transfer_done_result_);
+ on_transfer_done_result_ = NavigationThrottle::DEFER;
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/loader/navigation_resource_throttle.h b/chromium/content/browser/loader/navigation_resource_throttle.h
index e85a1fb9a09..a9685e347c7 100644
--- a/chromium/content/browser/loader/navigation_resource_throttle.h
+++ b/chromium/content/browser/loader/navigation_resource_throttle.h
@@ -42,12 +42,23 @@ class NavigationResourceThrottle : public ResourceThrottle {
CONTENT_EXPORT static void set_ui_checks_always_succeed_for_testing(
bool ui_checks_always_succeed);
+ // Used in unit tests to make all navigations transfer.
+ CONTENT_EXPORT static void set_force_transfer_for_testing(
+ bool force_transfer);
+
private:
void OnUIChecksPerformed(NavigationThrottle::ThrottleCheckResult result);
+ // Used in transfer navigations.
+ void InitiateTransfer();
+ void OnTransferComplete();
+
net::URLRequest* request_;
ResourceDispatcherHostDelegate* resource_dispatcher_host_delegate_;
RequestContextType request_context_type_;
+ bool in_cross_site_transition_;
+ NavigationThrottle::ThrottleCheckResult on_transfer_done_result_;
+
base::WeakPtrFactory<NavigationResourceThrottle> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(NavigationResourceThrottle);
diff --git a/chromium/content/browser/loader/navigation_url_loader.h b/chromium/content/browser/loader/navigation_url_loader.h
index d4494aadca7..a97e0d728b6 100644
--- a/chromium/content/browser/loader/navigation_url_loader.h
+++ b/chromium/content/browser/loader/navigation_url_loader.h
@@ -17,7 +17,6 @@ class NavigationUIData;
class NavigationURLLoaderDelegate;
class NavigationURLLoaderFactory;
class ServiceWorkerNavigationHandle;
-struct CommonNavigationParams;
struct NavigationRequestInfo;
// PlzNavigate: The navigation logic's UI thread entry point into the resource
diff --git a/chromium/content/browser/loader/navigation_url_loader_impl_core.h b/chromium/content/browser/loader/navigation_url_loader_impl_core.h
index 786634c349e..dd55af60123 100644
--- a/chromium/content/browser/loader/navigation_url_loader_impl_core.h
+++ b/chromium/content/browser/loader/navigation_url_loader_impl_core.h
@@ -12,18 +12,15 @@
#include "content/browser/loader/navigation_url_loader_impl.h"
namespace net {
-class URLRequest;
struct RedirectInfo;
}
namespace content {
-class FrameTreeNode;
class NavigationResourceHandler;
class NavigationData;
class ResourceContext;
class ResourceHandler;
-class ResourceRequestBody;
class ServiceWorkerNavigationHandleCore;
class StreamHandle;
struct ResourceResponse;
diff --git a/chromium/content/browser/loader/navigation_url_loader_unittest.cc b/chromium/content/browser/loader/navigation_url_loader_unittest.cc
index 89604bb33ba..a0b61b98c6b 100644
--- a/chromium/content/browser/loader/navigation_url_loader_unittest.cc
+++ b/chromium/content/browser/loader/navigation_url_loader_unittest.cc
@@ -112,7 +112,8 @@ class NavigationURLLoaderTest : public testing::Test {
common_params.url = url;
std::unique_ptr<NavigationRequestInfo> request_info(
new NavigationRequestInfo(common_params, begin_params, url,
- url::Origin(url), true, false, false, -1));
+ url::Origin(url), true, false, false, -1,
+ false, false));
return NavigationURLLoader::Create(browser_context_.get(),
std::move(request_info), nullptr,
diff --git a/chromium/content/browser/loader/reload_cache_control_browsertest.cc b/chromium/content/browser/loader/reload_cache_control_browsertest.cc
index 362bff46039..8999d37b199 100644
--- a/chromium/content/browser/loader/reload_cache_control_browsertest.cc
+++ b/chromium/content/browser/loader/reload_cache_control_browsertest.cc
@@ -6,8 +6,8 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
-#include "base/feature_list.h"
#include "base/files/file_path.h"
+#include "base/test/scoped_feature_list.h"
#include "content/public/common/content_features.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
@@ -45,11 +45,8 @@ class ReloadCacheControlBrowserTest : public ContentBrowserTest {
void SetUpOnMainThread() override {
// TODO(toyoshim): Tests in this file depend on current reload behavior,
// and should be modified when we enable the new reload behavior.
- base::FeatureList::ClearInstanceForTesting();
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- feature_list->InitializeFromCommandLine(
- std::string(), features::kNonValidatingReloadOnNormalReload.name);
- base::FeatureList::SetInstance(std::move(feature_list));
+ scoped_feature_list_.InitAndDisableFeature(
+ features::kNonValidatingReloadOnNormalReload);
SetUpTestServerOnMainThread();
}
@@ -80,6 +77,8 @@ class ReloadCacheControlBrowserTest : public ContentBrowserTest {
request_log_.push_back(log);
}
+ base::test::ScopedFeatureList scoped_feature_list_;
+
DISALLOW_COPY_AND_ASSIGN(ReloadCacheControlBrowserTest);
};
@@ -90,15 +89,14 @@ class ReloadCacheControlWithAnExperimentBrowserTest
~ReloadCacheControlWithAnExperimentBrowserTest() override = default;
void SetUpOnMainThread() override {
- base::FeatureList::ClearInstanceForTesting();
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- feature_list->InitializeFromCommandLine(
- features::kNonValidatingReloadOnNormalReload.name, std::string());
- base::FeatureList::SetInstance(std::move(feature_list));
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kNonValidatingReloadOnNormalReload);
SetUpTestServerOnMainThread();
}
+ base::test::ScopedFeatureList scoped_feature_list_;
+
DISALLOW_COPY_AND_ASSIGN(ReloadCacheControlWithAnExperimentBrowserTest);
};
diff --git a/chromium/content/browser/loader/resource_dispatcher_host_browsertest.cc b/chromium/content/browser/loader/resource_dispatcher_host_browsertest.cc
index e69f948ee47..b47f3572a81 100644
--- a/chromium/content/browser/loader/resource_dispatcher_host_browsertest.cc
+++ b/chromium/content/browser/loader/resource_dispatcher_host_browsertest.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
@@ -16,6 +17,7 @@
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "content/browser/download/download_manager_impl.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
@@ -238,6 +240,52 @@ IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest,
ASSERT_FALSE(got_downloads());
}
+namespace {
+
+// Responses with a HungResponse for the specified URL to hang on the request,
+// and cancells all requests from specifield |child_id|.
+std::unique_ptr<net::test_server::HttpResponse> CancelOnRequest(
+ const std::string& relative_url,
+ int child_id,
+ const net::test_server::HttpRequest& request) {
+ if (request.relative_url != relative_url)
+ return nullptr;
+
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&ResourceDispatcherHostImpl::CancelRequestsForProcess,
+ base::Unretained(ResourceDispatcherHostImpl::Get()),
+ child_id));
+
+ return base::MakeUnique<net::test_server::HungResponse>();
+}
+
+} // namespace
+
+// Tests the case where the request is cancelled by a layer above the
+// URLRequest, which passes the error on ResourceLoader teardown, rather than in
+// response to call to AsyncResourceHandler::OnResponseComplete.
+IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest,
+ SyncXMLHttpRequest_Cancelled) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ WaitForLoadStop(shell()->web_contents());
+
+ embedded_test_server()->RegisterRequestHandler(
+ base::Bind(&CancelOnRequest, "/hung",
+ shell()->web_contents()->GetRenderProcessHost()->GetID()));
+ NavigateToURL(shell(), embedded_test_server()->GetURL(
+ "/sync_xmlhttprequest_cancelled.html"));
+
+ int status_code = -1;
+ EXPECT_TRUE(ExecuteScriptAndExtractInt(
+ shell(), "window.domAutomationController.send(getErrorCode());",
+ &status_code));
+
+ // 19 is the value of NETWORK_ERROR on DOMException.
+ EXPECT_EQ(19, status_code);
+}
+
// Flaky everywhere. http://crbug.com/130404
// Tests that onunload is run for cross-site requests. (Bug 1114994)
IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest,
@@ -297,6 +345,10 @@ std::unique_ptr<net::test_server::HttpResponse> NoContentResponseHandler(
// If this flakes use http://crbug.com/80596.
IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest,
CrossSiteNoUnloadOn204) {
+ const char kNoContentPath[] = "/nocontent";
+ embedded_test_server()->RegisterRequestHandler(
+ base::Bind(&NoContentResponseHandler, kNoContentPath));
+
ASSERT_TRUE(embedded_test_server()->Start());
// Start with a URL that sets a cookie in its unload handler.
@@ -304,9 +356,6 @@ IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest,
CheckTitleTest(url, "set cookie on unload");
// Navigate to a cross-site URL that returns a 204 No Content response.
- const char kNoContentPath[] = "/nocontent";
- embedded_test_server()->RegisterRequestHandler(
- base::Bind(&NoContentResponseHandler, kNoContentPath));
NavigateToURL(shell(), embedded_test_server()->GetURL(kNoContentPath));
// Check that the unload cookie was not set.
@@ -480,9 +529,9 @@ std::unique_ptr<net::test_server::HttpResponse> HandleRedirectRequest(
// Test that we update the cookie policy URLs correctly when transferring
// navigations.
IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest, CookiePolicy) {
- ASSERT_TRUE(embedded_test_server()->Start());
embedded_test_server()->RegisterRequestHandler(
base::Bind(&HandleRedirectRequest, "/redirect?"));
+ ASSERT_TRUE(embedded_test_server()->Start());
std::string set_cookie_url(base::StringPrintf(
"http://localhost:%u/set_cookie.html", embedded_test_server()->port()));
@@ -755,11 +804,11 @@ namespace {
struct RequestDataForDelegate {
const GURL url;
const GURL first_party;
- const url::Origin initiator;
+ const base::Optional<url::Origin> initiator;
RequestDataForDelegate(const GURL& url,
const GURL& first_party,
- const url::Origin initiator)
+ const base::Optional<url::Origin>& initiator)
: url(url), first_party(first_party), initiator(initiator) {}
};
diff --git a/chromium/content/browser/loader/resource_dispatcher_host_impl.cc b/chromium/content/browser/loader/resource_dispatcher_host_impl.cc
index 8cc50c6f058..4117eae4cdc 100644
--- a/chromium/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/chromium/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -32,7 +32,7 @@
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
-#include "base/time/time.h"
+#include "base/timer/timer.h"
#include "content/browser/appcache/appcache_interceptor.h"
#include "content/browser/appcache/chrome_appcache_service.h"
#include "content/browser/bad_message.h"
@@ -44,7 +44,6 @@
#include "content/browser/frame_host/navigator.h"
#include "content/browser/loader/async_resource_handler.h"
#include "content/browser/loader/async_revalidation_manager.h"
-#include "content/browser/loader/cross_site_resource_handler.h"
#include "content/browser/loader/detachable_resource_handler.h"
#include "content/browser/loader/intercepting_resource_handler.h"
#include "content/browser/loader/loader_delegate.h"
@@ -55,8 +54,10 @@
#include "content/browser/loader/navigation_url_loader_impl_core.h"
#include "content/browser/loader/power_save_block_resource_throttle.h"
#include "content/browser/loader/redirect_to_file_resource_handler.h"
+#include "content/browser/loader/resource_loader.h"
#include "content/browser/loader/resource_message_filter.h"
#include "content/browser/loader/resource_request_info_impl.h"
+#include "content/browser/loader/resource_scheduler.h"
#include "content/browser/loader/stream_resource_handler.h"
#include "content/browser/loader/sync_resource_handler.h"
#include "content/browser/loader/throttling_resource_handler.h"
@@ -64,6 +65,7 @@
#include "content/browser/resource_context_impl.h"
#include "content/browser/service_worker/foreign_fetch_request_handler.h"
#include "content/browser/service_worker/link_header_support.h"
+#include "content/browser/service_worker/service_worker_navigation_handle_core.h"
#include "content/browser/service_worker/service_worker_request_handler.h"
#include "content/browser/streams/stream.h"
#include "content/browser/streams/stream_context.h"
@@ -96,10 +98,10 @@
#include "net/base/mime_util.h"
#include "net/base/net_errors.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
-#include "net/base/request_priority.h"
#include "net/base/upload_data_stream.h"
#include "net/cert/cert_status_flags.h"
#include "net/cookies/cookie_monster.h"
+#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
#include "net/ssl/client_cert_store.h"
@@ -113,12 +115,15 @@
#include "storage/browser/blob/shareable_file_reference.h"
#include "storage/browser/fileapi/file_permission_policy.h"
#include "storage/browser/fileapi/file_system_context.h"
+#include "url/third_party/mozilla/url_parse.h"
#include "url/url_constants.h"
using base::Time;
using base::TimeDelta;
using base::TimeTicks;
using storage::ShareableFileReference;
+using SyncLoadResultCallback =
+ content::ResourceDispatcherHostImpl::SyncLoadResultCallback;
// ----------------------------------------------------------------------------
@@ -221,15 +226,15 @@ bool IsDetachableResourceType(ResourceType type) {
}
// Aborts a request before an URLRequest has actually been created.
-void AbortRequestBeforeItStarts(ResourceMessageFilter* filter,
- IPC::Message* sync_result,
- int request_id,
- mojom::URLLoaderClientPtr url_loader_client) {
- if (sync_result) {
+void AbortRequestBeforeItStarts(
+ ResourceMessageFilter* filter,
+ const SyncLoadResultCallback& sync_result_handler,
+ int request_id,
+ mojom::URLLoaderClientAssociatedPtr url_loader_client) {
+ if (sync_result_handler) {
SyncLoadResult result;
result.error_code = net::ERR_ABORTED;
- ResourceHostMsg_SyncLoad::WriteReplyParams(sync_result, result);
- filter->Send(sync_result);
+ sync_result_handler.Run(&result);
} else {
// Tell the renderer that this request was disallowed.
ResourceRequestCompletionStatus request_complete_data;
@@ -261,9 +266,13 @@ void SetReferrerForRequest(net::URLRequest* request, const Referrer& referrer) {
net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
switch (referrer.policy) {
case blink::WebReferrerPolicyAlways:
+ net_referrer_policy = net::URLRequest::NEVER_CLEAR_REFERRER;
+ break;
case blink::WebReferrerPolicyNever:
+ net_referrer_policy = net::URLRequest::NO_REFERRER;
+ break;
case blink::WebReferrerPolicyOrigin:
- net_referrer_policy = net::URLRequest::NEVER_CLEAR_REFERRER;
+ net_referrer_policy = net::URLRequest::ORIGIN;
break;
case blink::WebReferrerPolicyNoReferrerWhenDowngrade:
net_referrer_policy =
@@ -414,6 +423,22 @@ void NotifyForEachFrameFromUI(
base::Passed(std::move(routing_ids))));
}
+// Sends back the result of a synchronous loading result to the renderer through
+// Chrome IPC.
+void HandleSyncLoadResult(base::WeakPtr<ResourceMessageFilter> filter,
+ std::unique_ptr<IPC::Message> sync_result,
+ const SyncLoadResult* result) {
+ if (!filter)
+ return;
+
+ if (result) {
+ ResourceHostMsg_SyncLoad::WriteReplyParams(sync_result.get(), *result);
+ } else {
+ sync_result->set_reply_error();
+ }
+ filter->Send(sync_result.release());
+}
+
} // namespace
ResourceDispatcherHostImpl::LoadInfo::LoadInfo() {}
@@ -728,10 +753,7 @@ bool ResourceDispatcherHostImpl::HandleExternalProtocol(ResourceLoader* loader,
if (job_factory->IsHandledURL(url))
return false;
- return delegate_->HandleExternalProtocol(
- url, info->GetChildID(), info->GetWebContentsGetterForRequest(),
- info->IsMainFrame(), info->GetPageTransition(), info->HasUserGesture(),
- info->GetContext());
+ return delegate_->HandleExternalProtocol(url, info);
}
void ResourceDispatcherHostImpl::DidStartRequest(ResourceLoader* loader) {
@@ -909,7 +931,7 @@ void ResourceDispatcherHostImpl::DidFinishLoading(ResourceLoader* loader) {
}
if (loader->request()->url().SchemeIsCryptographic()) {
- if (loader->request()->url().host() == "www.google.com") {
+ if (loader->request()->url().host_piece() == "www.google.com") {
UMA_HISTOGRAM_SPARSE_SLOWLY("Net.ErrorCodesForHTTPSGoogleMainFrame2",
-loader->request()->status().error());
}
@@ -995,7 +1017,6 @@ bool ResourceDispatcherHostImpl::OnMessageReceived(
IPC_MESSAGE_HANDLER_DELAY_REPLY(ResourceHostMsg_SyncLoad, OnSyncLoad)
IPC_MESSAGE_HANDLER(ResourceHostMsg_ReleaseDownloadedFile,
OnReleaseDownloadedFile)
- IPC_MESSAGE_HANDLER(ResourceHostMsg_DataDownloaded_ACK, OnDataDownloadedACK)
IPC_MESSAGE_HANDLER(ResourceHostMsg_CancelRequest, OnCancelRequest)
IPC_MESSAGE_HANDLER(ResourceHostMsg_DidChangePriority, OnDidChangePriority)
IPC_MESSAGE_UNHANDLED(handled = false)
@@ -1009,10 +1030,11 @@ bool ResourceDispatcherHostImpl::OnMessageReceived(
GlobalRequestID id(filter_->child_id(), request_id);
DelegateMap::iterator it = delegate_map_.find(id);
if (it != delegate_map_.end()) {
- base::ObserverList<ResourceMessageDelegate>::Iterator del_it(it->second);
- ResourceMessageDelegate* delegate;
- while (!handled && (delegate = del_it.GetNext()) != NULL) {
- handled = delegate->OnMessageReceived(message);
+ for (auto& delegate : *it->second) {
+ if (delegate.OnMessageReceived(message)) {
+ handled = true;
+ break;
+ }
}
}
@@ -1037,8 +1059,8 @@ void ResourceDispatcherHostImpl::OnRequestResourceInternal(
int routing_id,
int request_id,
const ResourceRequest& request_data,
- mojo::InterfaceRequest<mojom::URLLoader> mojo_request,
- mojom::URLLoaderClientPtr url_loader_client) {
+ mojom::URLLoaderAssociatedRequest mojo_request,
+ mojom::URLLoaderClientAssociatedPtr url_loader_client) {
// TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
tracked_objects::ScopedTracker tracking_profile(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
@@ -1059,7 +1081,7 @@ void ResourceDispatcherHostImpl::OnRequestResourceInternal(
request_data.render_frame_id,
request_data.url));
}
- BeginRequest(request_id, request_data, NULL, routing_id,
+ BeginRequest(request_id, request_data, SyncLoadResultCallback(), routing_id,
std::move(mojo_request), std::move(url_loader_client));
}
@@ -1074,7 +1096,10 @@ void ResourceDispatcherHostImpl::OnRequestResourceInternal(
void ResourceDispatcherHostImpl::OnSyncLoad(int request_id,
const ResourceRequest& request_data,
IPC::Message* sync_result) {
- BeginRequest(request_id, request_data, sync_result, sync_result->routing_id(),
+ SyncLoadResultCallback callback = base::Bind(
+ &HandleSyncLoadResult, filter_->GetWeakPtr(),
+ base::Passed(WrapUnique(sync_result)));
+ BeginRequest(request_id, request_data, callback, sync_result->routing_id(),
nullptr, nullptr);
}
@@ -1145,11 +1170,8 @@ void ResourceDispatcherHostImpl::UpdateRequestForTransfer(
DelegateMap::iterator it = delegate_map_.find(old_request_id);
if (it != delegate_map_.end()) {
// Tell each delegate that the request ID has changed.
- base::ObserverList<ResourceMessageDelegate>::Iterator del_it(it->second);
- ResourceMessageDelegate* delegate;
- while ((delegate = del_it.GetNext()) != NULL) {
- delegate->set_request_id(new_request_id);
- }
+ for (auto& delegate : *it->second)
+ delegate.set_request_id(new_request_id);
// Now store the observer list under the new request ID.
delegate_map_[new_request_id] = delegate_map_[old_request_id];
delegate_map_.erase(old_request_id);
@@ -1173,18 +1195,66 @@ void ResourceDispatcherHostImpl::UpdateRequestForTransfer(
child_id, request_data.service_worker_provider_id);
}
}
+}
+
+void ResourceDispatcherHostImpl::CompleteTransfer(
+ int request_id,
+ const ResourceRequest& request_data,
+ int route_id) {
+ // Caller should ensure that |request_data| is associated with a transfer.
+ DCHECK(request_data.transferred_request_child_id != -1 ||
+ request_data.transferred_request_request_id != -1);
+
+ bool is_navigational_request =
+ request_data.resource_type == RESOURCE_TYPE_MAIN_FRAME ||
+ request_data.resource_type == RESOURCE_TYPE_SUB_FRAME;
+ if (!is_navigational_request) {
+ // Transfers apply only to navigational requests - the renderer seems to
+ // have sent bogus IPC data.
+ bad_message::ReceivedBadMessage(
+ filter_, bad_message::RDH_TRANSFERRING_NONNAVIGATIONAL_REQUEST);
+ return;
+ }
- // We should have a CrossSiteResourceHandler to finish the transfer.
- DCHECK(info->cross_site_handler());
+ // Attempt to find a loader associated with the deferred transfer request.
+ LoaderMap::iterator it = pending_loaders_.find(
+ GlobalRequestID(request_data.transferred_request_child_id,
+ request_data.transferred_request_request_id));
+ if (it == pending_loaders_.end()) {
+ // Renderer sent transferred_request_request_id and/or
+ // transferred_request_child_id that doesn't have a corresponding entry on
+ // the browser side.
+ // TODO(lukasza): https://crbug.com/659613: Need to understand the scenario
+ // that can lead here (and then attempt to reintroduce a renderer kill
+ // below).
+ return;
+ }
+ ResourceLoader* pending_loader = it->second.get();
+
+ if (!pending_loader->is_transferring()) {
+ // Renderer sent transferred_request_request_id and/or
+ // transferred_request_child_id that doesn't correspond to an actually
+ // transferring loader on the browser side.
+ base::debug::Alias(pending_loader);
+ bad_message::ReceivedBadMessage(filter_,
+ bad_message::RDH_REQUEST_NOT_TRANSFERRING);
+ return;
+ }
+
+ // If the request is transferring to a new process, we can update our
+ // state and let it resume with its existing ResourceHandlers.
+ UpdateRequestForTransfer(filter_->child_id(), route_id, request_id,
+ request_data, it);
+ pending_loader->CompleteTransfer();
}
void ResourceDispatcherHostImpl::BeginRequest(
int request_id,
const ResourceRequest& request_data,
- IPC::Message* sync_result, // only valid for sync
+ const SyncLoadResultCallback& sync_result_handler, // only valid for sync
int route_id,
- mojo::InterfaceRequest<mojom::URLLoader> mojo_request,
- mojom::URLLoaderClientPtr url_loader_client) {
+ mojom::URLLoaderAssociatedRequest mojo_request,
+ mojom::URLLoaderClientAssociatedPtr url_loader_client) {
int process_type = filter_->process_type();
int child_id = filter_->child_id();
@@ -1222,24 +1292,12 @@ void ResourceDispatcherHostImpl::BeginRequest(
// If the request that's coming in is being transferred from another process,
// we want to reuse and resume the old loader rather than start a new one.
- LoaderMap::iterator it = pending_loaders_.find(
- GlobalRequestID(request_data.transferred_request_child_id,
- request_data.transferred_request_request_id));
- if (it != pending_loaders_.end()) {
+ if (request_data.transferred_request_child_id != -1 ||
+ request_data.transferred_request_request_id != -1) {
// TODO(yhirano): Make mojo work for this case.
DCHECK(!url_loader_client);
- // If the request is transferring to a new process, we can update our
- // state and let it resume with its existing ResourceHandlers.
- if (it->second->is_transferring()) {
- ResourceLoader* deferred_loader = it->second.get();
- UpdateRequestForTransfer(child_id, route_id, request_id,
- request_data, it);
- deferred_loader->CompleteTransfer();
- } else {
- bad_message::ReceivedBadMessage(
- filter_, bad_message::RDH_REQUEST_NOT_TRANSFERRING);
- }
+ CompleteTransfer(request_id, request_data, route_id);
return;
}
@@ -1256,7 +1314,7 @@ void ResourceDispatcherHostImpl::BeginRequest(
if (is_shutdown_ ||
!ShouldServiceRequest(process_type, child_id, request_data, headers,
filter_, resource_context)) {
- AbortRequestBeforeItStarts(filter_, sync_result, request_id,
+ AbortRequestBeforeItStarts(filter_, sync_result_handler, request_id,
std::move(url_loader_client));
return;
}
@@ -1281,33 +1339,33 @@ void ResourceDispatcherHostImpl::BeginRequest(
it.name(), it.value(), child_id, resource_context,
base::Bind(&ResourceDispatcherHostImpl::ContinuePendingBeginRequest,
base::Unretained(this), request_id, request_data,
- sync_result, route_id, headers,
+ sync_result_handler, route_id, headers,
base::Passed(std::move(mojo_request)),
base::Passed(std::move(url_loader_client))));
return;
}
}
}
- ContinuePendingBeginRequest(request_id, request_data, sync_result, route_id,
- headers, std::move(mojo_request),
+ ContinuePendingBeginRequest(request_id, request_data, sync_result_handler,
+ route_id, headers, std::move(mojo_request),
std::move(url_loader_client), true, 0);
}
void ResourceDispatcherHostImpl::ContinuePendingBeginRequest(
int request_id,
const ResourceRequest& request_data,
- IPC::Message* sync_result, // only valid for sync
+ const SyncLoadResultCallback& sync_result_handler, // only valid for sync
int route_id,
const net::HttpRequestHeaders& headers,
- mojo::InterfaceRequest<mojom::URLLoader> mojo_request,
- mojom::URLLoaderClientPtr url_loader_client,
+ mojom::URLLoaderAssociatedRequest mojo_request,
+ mojom::URLLoaderClientAssociatedPtr url_loader_client,
bool continue_request,
int error_code) {
if (!continue_request) {
// TODO(ananta): Find a way to specify the right error code here. Passing
// in a non-content error code is not safe.
bad_message::ReceivedBadMessage(filter_, bad_message::RDH_ILLEGAL_ORIGIN);
- AbortRequestBeforeItStarts(filter_, sync_result, request_id,
+ AbortRequestBeforeItStarts(filter_, sync_result_handler, request_id,
std::move(url_loader_client));
return;
}
@@ -1330,7 +1388,7 @@ void ResourceDispatcherHostImpl::ContinuePendingBeginRequest(
request_data.url,
request_data.resource_type,
resource_context)) {
- AbortRequestBeforeItStarts(filter_, sync_result, request_id,
+ AbortRequestBeforeItStarts(filter_, sync_result_handler, request_id,
std::move(url_loader_client));
return;
}
@@ -1352,6 +1410,12 @@ void ResourceDispatcherHostImpl::ContinuePendingBeginRequest(
new_request->set_first_party_for_cookies(
request_data.first_party_for_cookies);
+
+ // The initiator should normally be present, unless this is a navigation in a
+ // top-level frame. It may be null for some top-level navigations (eg:
+ // browser-initiated ones).
+ DCHECK(request_data.request_initiator.has_value() ||
+ request_data.resource_type == RESOURCE_TYPE_MAIN_FRAME);
new_request->set_initiator(request_data.request_initiator);
if (request_data.originated_from_service_worker) {
@@ -1403,7 +1467,7 @@ void ResourceDispatcherHostImpl::ContinuePendingBeginRequest(
bool allow_download = request_data.allow_download &&
IsResourceTypeFrame(request_data.resource_type);
bool do_not_prompt_for_login = request_data.do_not_prompt_for_login;
- bool is_sync_load = sync_result != NULL;
+ bool is_sync_load = !!sync_result_handler;
// Raw headers are sensitive, as they include Cookie/Set-Cookie, so only
// allow requesting them if requester has ReadRawCookies permission.
@@ -1515,8 +1579,8 @@ void ResourceDispatcherHostImpl::ContinuePendingBeginRequest(
request_data.should_reset_appcache);
std::unique_ptr<ResourceHandler> handler(CreateResourceHandler(
- new_request.get(), request_data, sync_result, route_id, process_type,
- child_id, resource_context, std::move(mojo_request),
+ new_request.get(), request_data, sync_result_handler, route_id,
+ process_type, child_id, resource_context, std::move(mojo_request),
std::move(url_loader_client)));
if (handler)
@@ -1527,20 +1591,20 @@ std::unique_ptr<ResourceHandler>
ResourceDispatcherHostImpl::CreateResourceHandler(
net::URLRequest* request,
const ResourceRequest& request_data,
- IPC::Message* sync_result,
+ const SyncLoadResultCallback& sync_result_handler,
int route_id,
int process_type,
int child_id,
ResourceContext* resource_context,
- mojo::InterfaceRequest<mojom::URLLoader> mojo_request,
- mojom::URLLoaderClientPtr url_loader_client) {
+ mojom::URLLoaderAssociatedRequest mojo_request,
+ mojom::URLLoaderClientAssociatedPtr url_loader_client) {
// TODO(pkasting): Remove ScopedTracker below once crbug.com/456331 is fixed.
tracked_objects::ScopedTracker tracking_profile(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"456331 ResourceDispatcherHostImpl::CreateResourceHandler"));
// Construct the IPC resource handler.
std::unique_ptr<ResourceHandler> handler;
- if (sync_result) {
+ if (sync_result_handler) {
// download_to_file is not supported for synchronous requests.
if (request_data.download_to_file) {
bad_message::ReceivedBadMessage(filter_, bad_message::RDH_BAD_DOWNLOAD);
@@ -1549,7 +1613,7 @@ ResourceDispatcherHostImpl::CreateResourceHandler(
DCHECK(!mojo_request.is_pending());
DCHECK(!url_loader_client);
- handler.reset(new SyncResourceHandler(request, sync_result, this));
+ handler.reset(new SyncResourceHandler(request, sync_result_handler, this));
} else {
if (mojo_request.is_pending()) {
handler.reset(new MojoAsyncResourceHandler(request, this,
@@ -1569,8 +1633,9 @@ ResourceDispatcherHostImpl::CreateResourceHandler(
bool start_detached = request_data.download_to_network_cache_only;
// Prefetches and <a ping> requests outlive their child process.
- if (!sync_result && (start_detached ||
- IsDetachableResourceType(request_data.resource_type))) {
+ if (!sync_result_handler &&
+ (start_detached ||
+ IsDetachableResourceType(request_data.resource_type))) {
std::unique_ptr<DetachableResourceHandler> detachable_handler =
base::MakeUnique<DetachableResourceHandler>(
request,
@@ -1581,28 +1646,6 @@ ResourceDispatcherHostImpl::CreateResourceHandler(
handler = std::move(detachable_handler);
}
- // PlzNavigate: If using --enable-browser-side-navigation, the
- // CrossSiteResourceHandler is not needed. This codepath is not used for the
- // actual navigation request, but only the subsequent blob URL load. This does
- // not require request transfers.
- if (!IsBrowserSideNavigationEnabled()) {
- // Install a CrossSiteResourceHandler for all main frame requests. This will
- // check whether a transfer is required and, if so, pause for the UI thread
- // to drive the transfer.
- bool is_swappable_navigation =
- request_data.resource_type == RESOURCE_TYPE_MAIN_FRAME;
- // If out-of-process iframes are possible, then all subframe requests need
- // to go through the CrossSiteResourceHandler to enforce the site isolation
- // policy.
- if (!is_swappable_navigation &&
- SiteIsolationPolicy::AreCrossProcessFramesPossible()) {
- is_swappable_navigation =
- request_data.resource_type == RESOURCE_TYPE_SUB_FRAME;
- }
- if (is_swappable_navigation && process_type == PROCESS_TYPE_RENDERER)
- handler.reset(new CrossSiteResourceHandler(std::move(handler), request));
- }
-
return AddStandardHandlers(
request, request_data.resource_type, resource_context,
request_data.fetch_request_context_type, filter_->appcache_service(),
@@ -1725,10 +1768,6 @@ void ResourceDispatcherHostImpl::OnDidChangePriority(
intra_priority_value);
}
-void ResourceDispatcherHostImpl::OnDataDownloadedACK(int request_id) {
- // TODO(michaeln): maybe throttle DataDownloaded messages
-}
-
void ResourceDispatcherHostImpl::RegisterDownloadedTempFile(
int child_id, int request_id, const base::FilePath& file_path) {
scoped_refptr<ShareableFileReference> reference =
@@ -1770,26 +1809,8 @@ bool ResourceDispatcherHostImpl::Send(IPC::Message* message) {
return false;
}
-// Note that this cancel is subtly different from the other
-// CancelRequest methods in this file, which also tear down the loader.
void ResourceDispatcherHostImpl::OnCancelRequest(int request_id) {
- int child_id = filter_->child_id();
-
- // When the old renderer dies, it sends a message to us to cancel its
- // requests.
- if (IsTransferredNavigation(GlobalRequestID(child_id, request_id)))
- return;
-
- ResourceLoader* loader = GetLoader(child_id, request_id);
-
- // It is possible that the request has been completed and removed from the
- // loader queue but the client has not processed the request completed message
- // before issuing a cancel. This happens frequently for beacons which are
- // canceled in the response received handler.
- if (!loader)
- return;
-
- loader->CancelRequest(true);
+ CancelRequestFromRenderer(GlobalRequestID(filter_->child_id(), request_id));
}
ResourceRequestInfoImpl* ResourceDispatcherHostImpl::CreateRequestInfo(
@@ -1799,17 +1820,12 @@ ResourceRequestInfoImpl* ResourceDispatcherHostImpl::CreateRequestInfo(
bool download,
ResourceContext* context) {
return new ResourceRequestInfoImpl(
- PROCESS_TYPE_RENDERER,
- child_id,
- render_view_route_id,
+ PROCESS_TYPE_RENDERER, child_id, render_view_route_id,
-1, // frame_tree_node_id
- 0,
- request_id_,
- render_frame_route_id,
- false, // is_main_frame
- false, // parent_is_main_frame
- RESOURCE_TYPE_SUB_RESOURCE,
- ui::PAGE_TRANSITION_LINK,
+ 0, MakeRequestID(), render_frame_route_id,
+ false, // is_main_frame
+ false, // parent_is_main_frame
+ RESOURCE_TYPE_SUB_RESOURCE, ui::PAGE_TRANSITION_LINK,
false, // should_replace_current_entry
download, // is_download
false, // is_stream
@@ -1818,8 +1834,7 @@ ResourceRequestInfoImpl* ResourceDispatcherHostImpl::CreateRequestInfo(
false, // enable_load_timing
false, // enable_upload_progress
false, // do_not_prompt_for_login
- blink::WebReferrerPolicyDefault,
- blink::WebPageVisibilityStateVisible,
+ blink::WebReferrerPolicyDefault, blink::WebPageVisibilityStateVisible,
context,
base::WeakPtr<ResourceMessageFilter>(), // filter
false, // report_raw_headers
@@ -1848,8 +1863,8 @@ void ResourceDispatcherHostImpl::OnRenderViewHostSetIsLoading(int child_id,
void ResourceDispatcherHostImpl::MarkAsTransferredNavigation(
const GlobalRequestID& id,
- const scoped_refptr<ResourceResponse>& response) {
- GetLoader(id)->MarkAsTransferring(response);
+ const base::Closure& on_transfer_complete_callback) {
+ GetLoader(id)->MarkAsTransferring(on_transfer_complete_callback);
}
void ResourceDispatcherHostImpl::CancelTransferringNavigation(
@@ -2083,7 +2098,21 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest(
ResourceType resource_type = info.is_main_frame ?
RESOURCE_TYPE_MAIN_FRAME : RESOURCE_TYPE_SUB_FRAME;
- if (is_shutdown_ ||
+ // Do not allow browser plugin guests to navigate to non-web URLs, since they
+ // cannot swap processes or grant bindings. Do not check external protocols
+ // here because they're checked in
+ // ChromeResourceDispatcherHostDelegate::HandleExternalProtocol.
+ ChildProcessSecurityPolicyImpl* policy =
+ ChildProcessSecurityPolicyImpl::GetInstance();
+ bool is_external_protocol =
+ !resource_context->GetRequestContext()->job_factory()->IsHandledURL(
+ info.common_params.url);
+ bool non_web_url_in_guest =
+ info.is_for_guests_only &&
+ !policy->IsWebSafeScheme(info.common_params.url.scheme()) &&
+ !is_external_protocol;
+
+ if (is_shutdown_ || non_web_url_in_guest ||
// TODO(davidben): Check ShouldServiceRequest here. This is important; it
// needs to be checked relative to the child that /requested/ the
// navigation. It's where file upload checks, etc., come in.
@@ -2148,8 +2177,6 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest(
BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE).get()));
}
- request_id_--;
-
// Make extra info and read footer (contains request ID).
//
// TODO(davidben): Associate the request with the FrameTreeNode and/or tab so
@@ -2160,7 +2187,7 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest(
-1, // route_id
info.frame_tree_node_id,
-1, // request_data.origin_pid,
- request_id_,
+ MakeRequestID(),
-1, // request_data.render_frame_id,
info.is_main_frame, info.parent_is_main_frame, resource_type,
info.common_params.transition,
@@ -2179,7 +2206,7 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest(
// same mechanism as the cookie one.
blink::WebPageVisibilityStateVisible, resource_context,
base::WeakPtr<ResourceMessageFilter>(), // filter
- false, // request_data.report_raw_headers
+ info.report_raw_headers,
true, // is_async
IsUsingLoFi(info.common_params.lofi_state, delegate_, *new_request,
resource_context, info.is_main_frame),
@@ -2197,6 +2224,11 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest(
false); // initiated_in_secure_context
extra_info->set_navigation_ui_data(std::move(navigation_ui_data));
+ if (service_worker_handle_core) {
+ extra_info->set_service_worker_context(
+ service_worker_handle_core->context_wrapper());
+ }
+
// Request takes ownership.
extra_info->AssociateWithRequest(new_request.get());
@@ -2255,8 +2287,8 @@ void ResourceDispatcherHostImpl::OnRequestResourceWithMojo(
int routing_id,
int request_id,
const ResourceRequest& request,
- mojo::InterfaceRequest<mojom::URLLoader> mojo_request,
- mojom::URLLoaderClientPtr url_loader_client,
+ mojom::URLLoaderAssociatedRequest mojo_request,
+ mojom::URLLoaderClientAssociatedPtr url_loader_client,
ResourceMessageFilter* filter) {
filter_ = filter;
OnRequestResourceInternal(routing_id, request_id, request,
@@ -2265,16 +2297,32 @@ void ResourceDispatcherHostImpl::OnRequestResourceWithMojo(
filter_ = nullptr;
}
+void ResourceDispatcherHostImpl::OnSyncLoadWithMojo(
+ int routing_id,
+ int request_id,
+ const ResourceRequest& request_data,
+ ResourceMessageFilter* filter,
+ const SyncLoadResultCallback& result_handler) {
+ filter_ = filter;
+ BeginRequest(request_id, request_data, result_handler, routing_id,
+ nullptr, nullptr);
+ filter_ = nullptr;
+}
+
// static
int ResourceDispatcherHostImpl::CalculateApproximateMemoryCost(
net::URLRequest* request) {
// The following fields should be a minor size contribution (experimentally
// on the order of 100). However since they are variable length, it could
// in theory be a sizeable contribution.
- int strings_cost = request->extra_request_headers().ToString().size() +
- request->original_url().spec().size() +
- request->referrer().size() +
- request->method().size();
+ int strings_cost = 0;
+ for (net::HttpRequestHeaders::Iterator it(request->extra_request_headers());
+ it.GetNext();) {
+ strings_cost += it.name().length() + it.value().length();
+ }
+ strings_cost +=
+ request->original_url().parsed_for_possibly_invalid_spec().Length() +
+ request->referrer().size() + request->method().size();
// Note that this expression will typically be dominated by:
// |kAvgBytesPerOutstandingRequest|.
@@ -2345,8 +2393,6 @@ void ResourceDispatcherHostImpl::InitializeURLRequest(
SetReferrerForRequest(request, referrer);
- request_id_--;
-
ResourceRequestInfoImpl* info =
CreateRequestInfo(render_process_host_id, render_view_routing_id,
render_frame_routing_id, is_download, context);
@@ -2392,6 +2438,30 @@ void ResourceDispatcherHostImpl::BeginURLRequest(
BeginRequestInternal(std::move(request), std::move(handler));
}
+int ResourceDispatcherHostImpl::MakeRequestID() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ return --request_id_;
+}
+
+void ResourceDispatcherHostImpl::CancelRequestFromRenderer(
+ GlobalRequestID request_id) {
+ // When the old renderer dies, it sends a message to us to cancel its
+ // requests.
+ if (IsTransferredNavigation(request_id))
+ return;
+
+ ResourceLoader* loader = GetLoader(request_id);
+
+ // It is possible that the request has been completed and removed from the
+ // loader queue but the client has not processed the request completed message
+ // before issuing a cancel. This happens frequently for beacons which are
+ // canceled in the response received handler.
+ if (!loader)
+ return;
+
+ loader->CancelRequest(true);
+}
+
void ResourceDispatcherHostImpl::StartLoading(
ResourceRequestInfoImpl* info,
std::unique_ptr<ResourceLoader> loader) {
diff --git a/chromium/content/browser/loader/resource_dispatcher_host_impl.h b/chromium/content/browser/loader/resource_dispatcher_host_impl.h
index 0ee50dfa24c..655d83fe80a 100644
--- a/chromium/content/browser/loader/resource_dispatcher_host_impl.h
+++ b/chromium/content/browser/loader/resource_dispatcher_host_impl.h
@@ -19,16 +19,14 @@
#include <string>
#include <vector>
+#include "base/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "content/browser/download/save_types.h"
#include "content/browser/loader/global_routing_id.h"
-#include "content/browser/loader/resource_loader.h"
#include "content/browser/loader/resource_loader_delegate.h"
-#include "content/browser/loader/resource_scheduler.h"
#include "content/common/content_export.h"
#include "content/common/url_loader.mojom.h"
#include "content/public/browser/global_request_id.h"
@@ -37,17 +35,18 @@
#include "content/public/common/request_context_type.h"
#include "content/public/common/resource_type.h"
#include "ipc/ipc_message.h"
-#include "mojo/public/cpp/system/data_pipe.h"
+#include "net/base/load_states.h"
#include "net/base/request_priority.h"
-#include "net/cookies/canonical_cookie.h"
-#include "net/url_request/url_request.h"
+#include "url/gurl.h"
namespace base {
class FilePath;
+class RepeatingTimer;
}
namespace net {
-class URLRequestJobFactory;
+class URLRequest;
+class HttpRequestHeaders;
}
namespace storage {
@@ -63,20 +62,17 @@ class NavigationUIData;
class RenderFrameHostImpl;
class ResourceContext;
class ResourceDispatcherHostDelegate;
+class ResourceLoader;
class ResourceHandler;
class ResourceMessageDelegate;
class ResourceMessageFilter;
class ResourceRequestInfoImpl;
+class ResourceScheduler;
class ServiceWorkerNavigationHandleCore;
-struct CommonNavigationParams;
struct NavigationRequestInfo;
struct Referrer;
struct ResourceRequest;
-namespace mojom {
-class URLLoader;
-} // namespace mojom
-
using CreateDownloadHandlerIntercept =
base::Callback<std::unique_ptr<ResourceHandler>(net::URLRequest*)>;
@@ -84,6 +80,11 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
: public ResourceDispatcherHost,
public ResourceLoaderDelegate {
public:
+ // Used to handle the result of SyncLoad IPC. |result| is null if it's
+ // unavailable due to an error.
+ using SyncLoadResultCallback =
+ base::Callback<void(const SyncLoadResult* result)>;
+
// This constructor should be used if we want downloads to work correctly.
// TODO(ananta)
// Work on moving creation of download handlers out of
@@ -144,7 +145,7 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// resumed by a new process.
void MarkAsTransferredNavigation(
const GlobalRequestID& id,
- const scoped_refptr<ResourceResponse>& response);
+ const base::Closure& on_transfer_complete_callback);
// Cancels a request previously marked as being transferred, for use when a
// navigation was cancelled.
@@ -297,10 +298,16 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
int routing_id,
int request_id,
const ResourceRequest& request,
- mojo::InterfaceRequest<mojom::URLLoader> mojo_request,
- mojom::URLLoaderClientPtr url_loader_client,
+ mojom::URLLoaderAssociatedRequest mojo_request,
+ mojom::URLLoaderClientAssociatedPtr url_loader_client,
ResourceMessageFilter* filter);
+ void OnSyncLoadWithMojo(int routing_id,
+ int request_id,
+ const ResourceRequest& request_data,
+ ResourceMessageFilter* filter,
+ const SyncLoadResultCallback& result_handler);
+
// Helper function for initializing the |request| passed in. By initializing
// we mean setting the |referrer| on the |request|, associating the
// ResourceRequestInfoImpl structure with the |request|, etc.
@@ -330,6 +337,16 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
bool is_shutdown() const { return is_shutdown_; }
+ // Creates a new request ID for browser initiated requests. See the comments
+ // of |request_id_| for the details. Must be called on the IO thread.
+ int MakeRequestID();
+
+ // Cancels a request as requested by a renderer. This function is called when
+ // a mojo connection is lost.
+ // Note that this cancel is subtly different from the other CancelRequest
+ // methods in this file, which also tear down the loader.
+ void CancelRequestFromRenderer(GlobalRequestID request_id);
+
private:
friend class ResourceDispatcherHostTest;
@@ -361,6 +378,7 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
LoadInfo();
LoadInfo(const LoadInfo& other);
~LoadInfo();
+
ResourceRequestInfo::WebContentsGetter web_contents_getter;
GURL url;
net::LoadStateWithParam load_state;
@@ -515,8 +533,8 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
int routing_id,
int request_id,
const ResourceRequest& request_data,
- mojo::InterfaceRequest<mojom::URLLoader> mojo_request,
- mojom::URLLoaderClientPtr url_loader_client);
+ mojom::URLLoaderAssociatedRequest mojo_request,
+ mojom::URLLoaderClientAssociatedPtr url_loader_client);
void OnSyncLoad(int request_id,
const ResourceRequest& request_data,
@@ -532,12 +550,19 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
const ResourceRequest& request_data,
LoaderMap::iterator iter);
- void BeginRequest(int request_id,
- const ResourceRequest& request_data,
- IPC::Message* sync_result, // only valid for sync
- int route_id, // only valid for async
- mojo::InterfaceRequest<mojom::URLLoader> mojo_request,
- mojom::URLLoaderClientPtr url_loader_client);
+ // If |request_data| is for a request being transferred from another process,
+ // then CompleteTransfer method can be used to complete the transfer.
+ void CompleteTransfer(int request_id,
+ const ResourceRequest& request_data,
+ int route_id);
+
+ void BeginRequest(
+ int request_id,
+ const ResourceRequest& request_data,
+ const SyncLoadResultCallback& sync_result_handler, // only valid for sync
+ int route_id,
+ mojom::URLLoaderAssociatedRequest mojo_request,
+ mojom::URLLoaderClientAssociatedPtr url_loader_client);
// There are requests which need decisions to be made like the following:
// Whether the presence of certain HTTP headers like the Origin header are
@@ -551,11 +576,11 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
void ContinuePendingBeginRequest(
int request_id,
const ResourceRequest& request_data,
- IPC::Message* sync_result, // only valid for sync
+ const SyncLoadResultCallback& sync_result_handler, // only valid for sync
int route_id,
const net::HttpRequestHeaders& headers,
- mojo::InterfaceRequest<mojom::URLLoader> mojo_request,
- mojom::URLLoaderClientPtr url_loader_client,
+ mojom::URLLoaderAssociatedRequest mojo_request,
+ mojom::URLLoaderClientAssociatedPtr url_loader_client,
bool continue_request,
int error_code);
@@ -564,13 +589,13 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
std::unique_ptr<ResourceHandler> CreateResourceHandler(
net::URLRequest* request,
const ResourceRequest& request_data,
- IPC::Message* sync_result,
+ const SyncLoadResultCallback& sync_result_handler,
int route_id,
int process_type,
int child_id,
ResourceContext* resource_context,
- mojo::InterfaceRequest<mojom::URLLoader> mojo_request,
- mojom::URLLoaderClientPtr url_loader_client);
+ mojom::URLLoaderAssociatedRequest mojo_request,
+ mojom::URLLoaderClientAssociatedPtr url_loader_client);
// Wraps |handler| in the standard resource handlers for normal resource
// loading and navigation requests. This adds MimeTypeResourceHandler and
@@ -585,7 +610,6 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
int route_id,
std::unique_ptr<ResourceHandler> handler);
- void OnDataDownloadedACK(int request_id);
void OnCancelRequest(int request_id);
void OnReleaseDownloadedFile(int request_id);
void OnDidChangePriority(int request_id,
diff --git a/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc b/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc
index a4bcf9b425a..8dfae97d5e5 100644
--- a/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc
+++ b/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc
@@ -9,7 +9,6 @@
#include <vector>
#include "base/bind.h"
-#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/location.h"
@@ -21,13 +20,13 @@
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
+#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/browser/browser_thread_impl.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/download/download_manager_impl.h"
#include "content/browser/download/download_resource_handler.h"
#include "content/browser/frame_host/navigation_request_info.h"
-#include "content/browser/loader/cross_site_resource_handler.h"
#include "content/browser/loader/detachable_resource_handler.h"
#include "content/browser/loader/navigation_resource_throttle.h"
#include "content/browser/loader/navigation_url_loader.h"
@@ -160,6 +159,7 @@ static ResourceRequest CreateResourceRequest(const char* method,
request.method = std::string(method);
request.url = url;
request.first_party_for_cookies = url; // bypass third-party cookie blocking
+ request.request_initiator = url::Origin(url); // ensure initiator is set
request.referrer_policy = blink::WebReferrerPolicyDefault;
request.load_flags = 0;
request.origin_pid = 0;
@@ -203,6 +203,9 @@ class ResourceIPCAccumulator {
typedef std::vector< std::vector<IPC::Message> > ClassifiedMessages;
void GetClassifiedMessages(ClassifiedMessages* msgs);
+ // Returns the reply of |msg|, which is a synchronous IPC message.
+ const IPC::Message* GetReply(const IPC::Message& msg);
+
private:
std::vector<IPC::Message> messages_;
};
@@ -232,6 +235,17 @@ void ResourceIPCAccumulator::GetClassifiedMessages(ClassifiedMessages* msgs) {
}
}
+const IPC::Message* ResourceIPCAccumulator::GetReply(const IPC::Message& msg) {
+ for (auto& reply : messages_) {
+ if (!reply.is_reply())
+ continue;
+ if (IPC::SyncMessage::GetMessageId(reply) ==
+ IPC::SyncMessage::GetMessageId(msg))
+ return &reply;
+ }
+ return nullptr;
+}
+
// This is used to create a filter matching a specified child id.
class TestFilterSpecifyingChild : public ResourceMessageFilter {
public:
@@ -244,7 +258,6 @@ class TestFilterSpecifyingChild : public ResourceMessageFilter {
NULL,
NULL,
NULL,
- NULL,
base::Bind(&TestFilterSpecifyingChild::GetContexts,
base::Unretained(this))),
resource_context_(resource_context),
@@ -619,16 +632,6 @@ class TestUserData : public base::SupportsUserData::Data {
bool* was_deleted_;
};
-class TransfersAllNavigationsContentBrowserClient
- : public TestContentBrowserClient {
- public:
- bool ShouldSwapProcessesForRedirect(ResourceContext* resource_context,
- const GURL& current_url,
- const GURL& new_url) override {
- return true;
- }
-};
-
enum GenericResourceThrottleFlags {
NONE = 0,
DEFER_STARTING_REQUEST = 1 << 0,
@@ -872,6 +875,10 @@ class ResourceDispatcherHostTest : public testing::TestWithParam<TestConfig>,
request_context->set_network_delegate(&network_delegate_);
}
+ ~ResourceDispatcherHostTest() override {
+ filter_->OnChannelClosing();
+ }
+
// IPC::Sender implementation
bool Send(IPC::Message* msg) override {
accum_.AddMessage(*msg);
@@ -909,16 +916,12 @@ class ResourceDispatcherHostTest : public testing::TestWithParam<TestConfig>,
web_contents_->GetRenderProcessHost()->GetID());
child_ids_.insert(web_contents_->GetRenderProcessHost()->GetID());
- base::FeatureList::ClearInstanceForTesting();
switch (GetParam()) {
case TestConfig::kDefault:
- base::FeatureList::InitializeInstance(std::string(), std::string());
break;
case TestConfig::kOptimizeIPCForSmallResourceEnabled: {
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- feature_list->InitializeFromCommandLine(
- features::kOptimizeLoadingIPCForSmallResources.name, std::string());
- base::FeatureList::SetInstance(std::move(feature_list));
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kOptimizeLoadingIPCForSmallResources);
ASSERT_TRUE(base::FeatureList::IsEnabled(
features::kOptimizeLoadingIPCForSmallResources));
break;
@@ -927,6 +930,7 @@ class ResourceDispatcherHostTest : public testing::TestWithParam<TestConfig>,
}
void TearDown() override {
+ web_contents_filter_->OnChannelClosing();
web_contents_observer_.reset();
web_contents_.reset();
@@ -1090,7 +1094,8 @@ class ResourceDispatcherHostTest : public testing::TestWithParam<TestConfig>,
common_params.url = url;
std::unique_ptr<NavigationRequestInfo> request_info(
new NavigationRequestInfo(common_params, begin_params, url,
- url::Origin(url), true, false, false, -1));
+ url::Origin(url), true, false, false, -1,
+ false, false));
std::unique_ptr<NavigationURLLoader> test_loader =
NavigationURLLoader::Create(browser_context_.get(),
std::move(request_info), nullptr, nullptr,
@@ -1143,6 +1148,7 @@ class ResourceDispatcherHostTest : public testing::TestWithParam<TestConfig>,
std::unique_ptr<base::RunLoop> wait_for_request_complete_loop_;
RenderViewHostTestEnabler render_view_host_test_enabler_;
bool auto_advance_;
+ base::test::ScopedFeatureList scoped_feature_list_;
};
void ResourceDispatcherHostTest::MakeTestRequest(int render_view_id,
@@ -1564,6 +1570,60 @@ TEST_P(ResourceDispatcherHostTest, DetachedResourceTimesOut) {
EXPECT_EQ(0, network_delegate()->error_count());
}
+TEST_P(ResourceDispatcherHostTest, SyncLoadSuccess) {
+ ResourceRequest request = CreateResourceRequest(
+ "GET", RESOURCE_TYPE_XHR, net::URLRequestTestJob::test_url_1());
+ request.priority = net::MAXIMUM_PRIORITY;
+
+ // Successful sync load.
+ std::tuple<SyncLoadResult> result;
+ ResourceHostMsg_SyncLoad sync_load_msg(0, 1, request, &std::get<0>(result));
+ host_.OnMessageReceived(sync_load_msg, filter_.get());
+ base::RunLoop().RunUntilIdle();
+
+ const IPC::Message* reply = accum_.GetReply(sync_load_msg);
+ ASSERT_TRUE(reply);
+
+ ASSERT_TRUE(ResourceHostMsg_SyncLoad::ReadReplyParam(reply, &result));
+ EXPECT_EQ(net::OK, std::get<0>(result).error_code);
+}
+
+TEST_P(ResourceDispatcherHostTest, SyncLoadError) {
+ ResourceRequest request = CreateResourceRequest(
+ "GET", RESOURCE_TYPE_XHR, net::URLRequestTestJob::test_url_error());
+ request.priority = net::MAXIMUM_PRIORITY;
+
+ // Failued sync load.
+ std::tuple<SyncLoadResult> result;
+ ResourceHostMsg_SyncLoad sync_load_msg(0, 1, request, &std::get<0>(result));
+ host_.OnMessageReceived(sync_load_msg, filter_.get());
+ base::RunLoop().RunUntilIdle();
+
+ const IPC::Message* reply = accum_.GetReply(sync_load_msg);
+ ASSERT_TRUE(reply);
+
+ ASSERT_TRUE(ResourceHostMsg_SyncLoad::ReadReplyParam(reply, &result));
+ EXPECT_EQ(net::ERR_INVALID_URL, std::get<0>(result).error_code);
+}
+
+TEST_P(ResourceDispatcherHostTest, SyncLoadCancel) {
+ ResourceRequest request = CreateResourceRequest(
+ "GET", RESOURCE_TYPE_XHR, net::URLRequestTestJob::test_url_1());
+ request.priority = net::MAXIMUM_PRIORITY;
+
+ // Cancelled sync load.
+ SyncLoadResult result;
+ ResourceHostMsg_SyncLoad sync_load_msg(0, 1, request, &result);
+
+ host_.OnMessageReceived(sync_load_msg, filter_.get());
+ host_.CancelRequestsForProcess(filter_->child_id());
+ base::RunLoop().RunUntilIdle();
+
+ const IPC::Message* reply = accum_.GetReply(sync_load_msg);
+ ASSERT_TRUE(reply);
+ ASSERT_TRUE(reply->is_reply_error());
+}
+
// If the filter has disappeared then detachable resources should continue to
// load.
TEST_P(ResourceDispatcherHostTest, DeletedFilterDetached) {
@@ -1905,6 +1965,8 @@ TEST_P(ResourceDispatcherHostTest, TestProcessCancel) {
EXPECT_EQ(4, network_delegate()->completed_requests());
EXPECT_EQ(0, network_delegate()->canceled_requests());
EXPECT_EQ(0, network_delegate()->error_count());
+
+ test_filter->OnChannelClosing();
}
// Tests whether the correct requests get canceled when a RenderViewHost is
@@ -2155,6 +2217,7 @@ TEST_P(ResourceDispatcherHostTest, TestBlockedRequestsProcessDies) {
CheckSuccessfulRequest(msgs[1], net::URLRequestTestJob::test_data_3());
EXPECT_TRUE(host_.blocked_loaders_map_.empty());
+ second_filter->OnChannelClosing();
}
// Tests that blocked requests don't leak when the ResourceDispatcherHost goes
@@ -2200,6 +2263,8 @@ TEST_P(ResourceDispatcherHostTest, TestBlockedRequestsDontLeak) {
// Flush all the pending requests.
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
+
+ second_filter->OnChannelClosing();
}
// Test the private helper method "CalculateApproximateMemoryCost()".
@@ -2207,15 +2272,13 @@ TEST_P(ResourceDispatcherHostTest, CalculateApproximateMemoryCost) {
net::URLRequestContext context;
std::unique_ptr<net::URLRequest> req(context.CreateRequest(
GURL("http://www.google.com"), net::DEFAULT_PRIORITY, NULL));
- EXPECT_EQ(
- 4427,
- ResourceDispatcherHostImpl::CalculateApproximateMemoryCost(req.get()));
+ EXPECT_EQ(4425, ResourceDispatcherHostImpl::CalculateApproximateMemoryCost(
+ req.get()));
// Add 9 bytes of referrer.
req->SetReferrer("123456789");
- EXPECT_EQ(
- 4436,
- ResourceDispatcherHostImpl::CalculateApproximateMemoryCost(req.get()));
+ EXPECT_EQ(4434, ResourceDispatcherHostImpl::CalculateApproximateMemoryCost(
+ req.get()));
// Add 33 bytes of upload content.
std::string upload_content;
@@ -2228,9 +2291,8 @@ TEST_P(ResourceDispatcherHostTest, CalculateApproximateMemoryCost) {
net::ElementsUploadDataStream::CreateWithReader(std::move(reader), 0));
// Since the upload throttling is disabled, this has no effect on the cost.
- EXPECT_EQ(
- 4436,
- ResourceDispatcherHostImpl::CalculateApproximateMemoryCost(req.get()));
+ EXPECT_EQ(4434, ResourceDispatcherHostImpl::CalculateApproximateMemoryCost(
+ req.get()));
}
// Test that too much memory for outstanding requests for a particular
@@ -2306,6 +2368,8 @@ TEST_P(ResourceDispatcherHostTest, TooMuchOutstandingRequestsMemory) {
net::URLRequestTestJob::test_data_2());
CheckSuccessfulRequest(msgs[kMaxRequests + 3],
net::URLRequestTestJob::test_data_2());
+
+ second_filter->OnChannelClosing();
}
// Test that when too many requests are outstanding for a particular
@@ -2371,6 +2435,9 @@ TEST_P(ResourceDispatcherHostTest, TooManyOutstandingRequests) {
CheckFailedRequest(msgs[kMaxRequestsPerProcess + 2],
net::URLRequestTestJob::test_data_2(),
net::ERR_INSUFFICIENT_RESOURCES);
+
+ second_filter->OnChannelClosing();
+ third_filter->OnChannelClosing();
}
// Tests that we sniff the mime type for a simple request.
@@ -2578,7 +2645,7 @@ TEST_P(ResourceDispatcherHostTest, CancelRequestsForContext) {
std::unique_ptr<NavigationRequestInfo> request_info(
new NavigationRequestInfo(common_params, begin_params, download_url,
url::Origin(download_url), true, false, false,
- -1));
+ -1, false, false));
std::unique_ptr<NavigationURLLoader> loader = NavigationURLLoader::Create(
browser_context_.get(), std::move(request_info), nullptr, nullptr,
&delegate);
@@ -2687,7 +2754,7 @@ TEST_P(ResourceDispatcherHostTest, CancelRequestsForContextTransferred) {
GlobalRequestID global_request_id(web_contents_filter_->child_id(),
request_id);
- host_.MarkAsTransferredNavigation(global_request_id, nullptr);
+ host_.MarkAsTransferredNavigation(global_request_id, base::Closure());
// And now simulate a cancellation coming from the renderer.
ResourceHostMsg_CancelRequest msg(request_id);
@@ -2714,13 +2781,11 @@ TEST_P(ResourceDispatcherHostTest, TransferNavigationHtml) {
SUCCEED() << "Test is not applicable with browser side navigation enabled";
return;
}
- // This test expects the cross site request to be leaked, so it can transfer
- // the request directly.
- CrossSiteResourceHandler::SetLeakRequestsForTesting(true);
EXPECT_EQ(0, host_.pending_requests());
NavigationResourceThrottle::set_ui_checks_always_succeed_for_testing(true);
+ NavigationResourceThrottle::set_force_transfer_for_testing(true);
int render_view_id = 0;
int request_id = 1;
@@ -2731,11 +2796,6 @@ TEST_P(ResourceDispatcherHostTest, TransferNavigationHtml) {
HandleScheme("http");
- // Temporarily replace ContentBrowserClient with one that will trigger the
- // transfer navigation code paths.
- TransfersAllNavigationsContentBrowserClient new_client;
- ContentBrowserClient* old_client = SetBrowserClientForTesting(&new_client);
-
MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
GURL("http://example.com/blah"),
RESOURCE_TYPE_MAIN_FRAME);
@@ -2754,9 +2814,6 @@ TEST_P(ResourceDispatcherHostTest, TransferNavigationHtml) {
// MimeTypeResourceHandler.
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
- // Restore, now that we've set up a transfer.
- SetBrowserClientForTesting(old_client);
-
// This second filter is used to emulate a second process.
scoped_refptr<ForwardingFilter> second_filter = MakeForwardingFilter();
@@ -2780,6 +2837,8 @@ TEST_P(ResourceDispatcherHostTest, TransferNavigationHtml) {
ASSERT_EQ(2U, msgs.size());
EXPECT_EQ(ResourceMsg_ReceivedRedirect::ID, msgs[0][0].type());
CheckSuccessfulRequest(msgs[1], kResponseBody);
+
+ second_filter->OnChannelClosing();
}
// Test transferring two navigations with text/html, to ensure the resource
@@ -2789,10 +2848,8 @@ TEST_P(ResourceDispatcherHostTest, TransferTwoNavigationsHtml) {
SUCCEED() << "Test is not applicable with browser side navigation enabled";
return;
}
- // This test expects the cross site request to be leaked, so it can transfer
- // the request directly.
- CrossSiteResourceHandler::SetLeakRequestsForTesting(true);
+ NavigationResourceThrottle::set_force_transfer_for_testing(true);
NavigationResourceThrottle::set_ui_checks_always_succeed_for_testing(true);
EXPECT_EQ(0, host_.pending_requests());
@@ -2808,11 +2865,6 @@ TEST_P(ResourceDispatcherHostTest, TransferTwoNavigationsHtml) {
HandleScheme("http");
- // Temporarily replace ContentBrowserClient with one that will trigger the
- // transfer navigation code paths.
- TransfersAllNavigationsContentBrowserClient new_client;
- ContentBrowserClient* old_client = SetBrowserClientForTesting(&new_client);
-
// Make the first request.
MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
GURL("http://example.com/blah"),
@@ -2829,8 +2881,7 @@ TEST_P(ResourceDispatcherHostTest, TransferTwoNavigationsHtml) {
// MimeTypeResourceHandler.
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
- // Restore, now that we've set up a transfer.
- SetBrowserClientForTesting(old_client);
+ NavigationResourceThrottle::set_force_transfer_for_testing(false);
// This second filter is used to emulate a second process.
scoped_refptr<ForwardingFilter> second_filter = MakeForwardingFilter();
@@ -2866,6 +2917,8 @@ TEST_P(ResourceDispatcherHostTest, TransferTwoNavigationsHtml) {
ASSERT_EQ(2U, msgs.size());
CheckSuccessfulRequest(msgs[0], kResponseBody);
+
+ second_filter->OnChannelClosing();
}
// Test transferred navigations with text/plain, which causes
@@ -2876,10 +2929,8 @@ TEST_P(ResourceDispatcherHostTest, TransferNavigationText) {
SUCCEED() << "Test is not applicable with browser side navigation enabled";
return;
}
- // This test expects the cross site request to be leaked, so it can transfer
- // the request directly.
- CrossSiteResourceHandler::SetLeakRequestsForTesting(true);
+ NavigationResourceThrottle::set_force_transfer_for_testing(true);
NavigationResourceThrottle::set_ui_checks_always_succeed_for_testing(true);
EXPECT_EQ(0, host_.pending_requests());
@@ -2893,11 +2944,6 @@ TEST_P(ResourceDispatcherHostTest, TransferNavigationText) {
HandleScheme("http");
- // Temporarily replace ContentBrowserClient with one that will trigger the
- // transfer navigation code paths.
- TransfersAllNavigationsContentBrowserClient new_client;
- ContentBrowserClient* old_client = SetBrowserClientForTesting(&new_client);
-
MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
GURL("http://example.com/blah"),
RESOURCE_TYPE_MAIN_FRAME);
@@ -2919,9 +2965,6 @@ TEST_P(ResourceDispatcherHostTest, TransferNavigationText) {
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
base::RunLoop().RunUntilIdle();
- // Restore, now that we've set up a transfer.
- SetBrowserClientForTesting(old_client);
-
// This second filter is used to emulate a second process.
scoped_refptr<ForwardingFilter> second_filter = MakeForwardingFilter();
@@ -2945,6 +2988,8 @@ TEST_P(ResourceDispatcherHostTest, TransferNavigationText) {
ASSERT_EQ(2U, msgs.size());
EXPECT_EQ(ResourceMsg_ReceivedRedirect::ID, msgs[0][0].type());
CheckSuccessfulRequest(msgs[1], kResponseBody);
+
+ second_filter->OnChannelClosing();
}
TEST_P(ResourceDispatcherHostTest, TransferNavigationWithProcessCrash) {
@@ -2952,10 +2997,8 @@ TEST_P(ResourceDispatcherHostTest, TransferNavigationWithProcessCrash) {
SUCCEED() << "Test is not applicable with browser side navigation enabled";
return;
}
- // This test expects the cross site request to be leaked, so it can transfer
- // the request directly.
- CrossSiteResourceHandler::SetLeakRequestsForTesting(true);
+ NavigationResourceThrottle::set_force_transfer_for_testing(true);
NavigationResourceThrottle::set_ui_checks_always_succeed_for_testing(true);
EXPECT_EQ(0, host_.pending_requests());
@@ -2971,11 +3014,6 @@ TEST_P(ResourceDispatcherHostTest, TransferNavigationWithProcessCrash) {
HandleScheme("http");
- // Temporarily replace ContentBrowserClient with one that will trigger the
- // transfer navigation code paths.
- TransfersAllNavigationsContentBrowserClient new_client;
- ContentBrowserClient* old_client = SetBrowserClientForTesting(&new_client);
-
// Create a first filter that can be deleted before the second one starts.
{
scoped_refptr<ForwardingFilter> first_filter = MakeForwardingFilter();
@@ -3001,12 +3039,11 @@ TEST_P(ResourceDispatcherHostTest, TransferNavigationWithProcessCrash) {
// Flush all the pending requests to get the response through the
// MimeTypeResourceHandler.
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
+
+ first_filter->OnChannelClosing();
}
// The first filter is now deleted, as if the child process died.
- // Restore.
- SetBrowserClientForTesting(old_client);
-
// Make sure we don't hold onto the ResourceMessageFilter after it is deleted.
GlobalRequestID first_global_request_id(first_child_id, request_id);
@@ -3035,6 +3072,8 @@ TEST_P(ResourceDispatcherHostTest, TransferNavigationWithProcessCrash) {
ASSERT_EQ(2U, msgs.size());
EXPECT_EQ(ResourceMsg_ReceivedRedirect::ID, msgs[0][0].type());
CheckSuccessfulRequest(msgs[1], kResponseBody);
+
+ second_filter->OnChannelClosing();
}
TEST_P(ResourceDispatcherHostTest, TransferNavigationWithTwoRedirects) {
@@ -3042,10 +3081,8 @@ TEST_P(ResourceDispatcherHostTest, TransferNavigationWithTwoRedirects) {
SUCCEED() << "Test is not applicable with browser side navigation enabled";
return;
}
- // This test expects the cross site request to be leaked, so it can transfer
- // the request directly.
- CrossSiteResourceHandler::SetLeakRequestsForTesting(true);
+ NavigationResourceThrottle::set_force_transfer_for_testing(true);
NavigationResourceThrottle::set_ui_checks_always_succeed_for_testing(true);
EXPECT_EQ(0, host_.pending_requests());
@@ -3059,11 +3096,6 @@ TEST_P(ResourceDispatcherHostTest, TransferNavigationWithTwoRedirects) {
HandleScheme("http");
- // Temporarily replace ContentBrowserClient with one that will trigger the
- // transfer navigation code paths.
- TransfersAllNavigationsContentBrowserClient new_client;
- ContentBrowserClient* old_client = SetBrowserClientForTesting(&new_client);
-
MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
GURL("http://example.com/blah"),
RESOURCE_TYPE_MAIN_FRAME);
@@ -3092,9 +3124,6 @@ TEST_P(ResourceDispatcherHostTest, TransferNavigationWithTwoRedirects) {
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
base::RunLoop().RunUntilIdle();
- // Restore.
- SetBrowserClientForTesting(old_client);
-
// This second filter is used to emulate a second process.
scoped_refptr<ForwardingFilter> second_filter = MakeForwardingFilter();
@@ -3131,6 +3160,8 @@ TEST_P(ResourceDispatcherHostTest, TransferNavigationWithTwoRedirects) {
ASSERT_EQ(2U, msgs.size());
EXPECT_EQ(ResourceMsg_ReceivedRedirect::ID, msgs[0][0].type());
CheckSuccessfulRequest(msgs[1], kResponseBody);
+
+ second_filter->OnChannelClosing();
}
TEST_P(ResourceDispatcherHostTest, UnknownURLScheme) {
@@ -3755,6 +3786,72 @@ TEST_P(ResourceDispatcherHostTest, ThrottleMustProcessResponseBeforeRead) {
base::RunLoop().RunUntilIdle();
}
+namespace {
+
+void StoreSyncLoadResult(bool* called,
+ bool* was_null,
+ SyncLoadResult* result_out,
+ const SyncLoadResult* result) {
+ *called = true;
+ *was_null = !result;
+
+ if (result)
+ *result_out = *result;
+}
+
+} // namespace
+
+TEST_P(ResourceDispatcherHostTest, SyncLoadWithMojoSuccess) {
+ ResourceRequest request = CreateResourceRequest(
+ "GET", RESOURCE_TYPE_XHR, net::URLRequestTestJob::test_url_1());
+ request.priority = net::MAXIMUM_PRIORITY;
+
+ bool called = false;
+ bool was_null = false;
+ SyncLoadResult result;
+ host_.OnSyncLoadWithMojo(0, 1, request, filter_.get(),
+ base::Bind(&StoreSyncLoadResult,
+ &called, &was_null, &result));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
+ EXPECT_FALSE(was_null);
+ EXPECT_EQ(net::OK, result.error_code);
+}
+
+TEST_P(ResourceDispatcherHostTest, SyncLoadWithMojoError) {
+ ResourceRequest request = CreateResourceRequest(
+ "GET", RESOURCE_TYPE_XHR, net::URLRequestTestJob::test_url_error());
+ request.priority = net::MAXIMUM_PRIORITY;
+
+ bool called = false;
+ bool was_null = false;
+ SyncLoadResult result;
+ host_.OnSyncLoadWithMojo(0, 1, request, filter_.get(),
+ base::Bind(&StoreSyncLoadResult,
+ &called, &was_null, &result));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
+ EXPECT_FALSE(was_null);
+ EXPECT_EQ(net::ERR_INVALID_URL, result.error_code);
+}
+
+TEST_P(ResourceDispatcherHostTest, SyncLoadWithMojoCancel) {
+ ResourceRequest request = CreateResourceRequest(
+ "GET", RESOURCE_TYPE_XHR, net::URLRequestTestJob::test_url_error());
+ request.priority = net::MAXIMUM_PRIORITY;
+
+ bool called = false;
+ bool was_null = false;
+ SyncLoadResult result;
+ host_.OnSyncLoadWithMojo(0, 1, request, filter_.get(),
+ base::Bind(&StoreSyncLoadResult,
+ &called, &was_null, &result));
+ host_.CancelRequestsForProcess(filter_->child_id());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
+ EXPECT_TRUE(was_null);
+}
+
// A URLRequestTestJob that sets a test certificate on the |ssl_info|
// field of the response.
class TestHTTPSURLRequestJob : public net::URLRequestTestJob {
diff --git a/chromium/content/browser/loader/resource_handler.cc b/chromium/content/browser/loader/resource_handler.cc
index 358dd65a90a..1c9287e3ad2 100644
--- a/chromium/content/browser/loader/resource_handler.cc
+++ b/chromium/content/browser/loader/resource_handler.cc
@@ -8,6 +8,8 @@
namespace content {
+ResourceHandler::~ResourceHandler() {}
+
ResourceHandler::ResourceHandler(net::URLRequest* request)
: controller_(NULL),
request_(request) {
diff --git a/chromium/content/browser/loader/resource_handler.h b/chromium/content/browser/loader/resource_handler.h
index 02ef6b87f12..a6cc6822c69 100644
--- a/chromium/content/browser/loader/resource_handler.h
+++ b/chromium/content/browser/loader/resource_handler.h
@@ -14,8 +14,9 @@
#include <string>
+#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/sequenced_task_runner_helpers.h"
#include "base/threading/non_thread_safe.h"
#include "content/common/content_export.h"
@@ -40,7 +41,7 @@ struct ResourceResponse;
class CONTENT_EXPORT ResourceHandler
: public NON_EXPORTED_BASE(base::NonThreadSafe) {
public:
- virtual ~ResourceHandler() {}
+ virtual ~ResourceHandler();
// Sets the controller for this handler.
virtual void SetController(ResourceController* controller);
@@ -114,6 +115,8 @@ class CONTENT_EXPORT ResourceHandler
private:
ResourceController* controller_;
net::URLRequest* request_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResourceHandler);
};
} // namespace content
diff --git a/chromium/content/browser/loader/resource_loader.cc b/chromium/content/browser/loader/resource_loader.cc
index 6fda9a09bcb..f2f670a566d 100644
--- a/chromium/content/browser/loader/resource_loader.cc
+++ b/chromium/content/browser/loader/resource_loader.cc
@@ -6,18 +6,18 @@
#include <utility>
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/location.h"
#include "base/metrics/histogram_macros.h"
#include "base/profiler/scoped_tracker.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "content/browser/appcache/appcache_interceptor.h"
#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/loader/cross_site_resource_handler.h"
#include "content/browser/loader/detachable_resource_handler.h"
+#include "content/browser/loader/resource_handler.h"
#include "content/browser/loader/resource_loader_delegate.h"
#include "content/browser/loader/resource_request_info_impl.h"
#include "content/browser/service_worker/service_worker_request_handler.h"
@@ -25,6 +25,7 @@
#include "content/browser/ssl/ssl_client_auth_handler.h"
#include "content/browser/ssl/ssl_manager.h"
#include "content/public/browser/resource_dispatcher_host_login_delegate.h"
+#include "content/public/common/browser_side_navigation_policy.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/process_type.h"
@@ -197,10 +198,11 @@ void ResourceLoader::CancelWithError(int error_code) {
}
void ResourceLoader::MarkAsTransferring(
- const scoped_refptr<ResourceResponse>& response) {
+ const base::Closure& on_transfer_complete_callback) {
CHECK(IsResourceTypeFrame(GetRequestInfo()->GetResourceType()))
<< "Can only transfer for navigations";
is_transferring_ = true;
+ on_transfer_complete_callback_ = on_transfer_complete_callback;
int child_id = GetRequestInfo()->GetChildID();
AppCacheInterceptor::PrepareForCrossSiteTransfer(request(), child_id);
@@ -211,13 +213,14 @@ void ResourceLoader::MarkAsTransferring(
}
void ResourceLoader::CompleteTransfer() {
- // Although CrossSiteResourceHandler defers at OnResponseStarted
+ // Although NavigationResourceThrottle defers at WillProcessResponse
// (DEFERRED_READ), it may be seeing a replay of events via
- // MimeTypeResourceHandler, and so the request itself is actually deferred
- // at a later read stage.
+ // MimeTypeResourceHandler, and so the request itself is actually deferred at
+ // a later read stage.
DCHECK(DEFERRED_READ == deferred_stage_ ||
DEFERRED_RESPONSE_COMPLETE == deferred_stage_);
DCHECK(is_transferring_);
+ DCHECK(!on_transfer_complete_callback_.is_null());
// In some cases, a process transfer doesn't really happen and the
// request is resumed in the original process. Real transfers to a new process
@@ -231,7 +234,7 @@ void ResourceLoader::CompleteTransfer() {
handler->MaybeCompleteCrossSiteTransferInOldProcess(child_id);
is_transferring_ = false;
- GetRequestInfo()->cross_site_handler()->ResumeResponse();
+ base::ResetAndReturn(&on_transfer_complete_callback_).Run();
}
ResourceRequestInfoImpl* ResourceLoader::GetRequestInfo() {
@@ -254,14 +257,21 @@ void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
ResourceRequestInfoImpl* info = GetRequestInfo();
- if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
- info->GetChildID(), redirect_info.new_url)) {
- DVLOG(1) << "Denied unauthorized request for "
- << redirect_info.new_url.possibly_invalid_spec();
+ // With PlzNavigate for frame navigations this check is done in the
+ // NavigationRequest::OnReceivedRedirect() function.
+ bool check_handled_elsewhere = IsBrowserSideNavigationEnabled() &&
+ IsResourceTypeFrame(info->GetResourceType());
- // Tell the renderer that this request was disallowed.
- Cancel();
- return;
+ if (!check_handled_elsewhere) {
+ if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
+ info->GetChildID(), redirect_info.new_url)) {
+ DVLOG(1) << "Denied unauthorized request for "
+ << redirect_info.new_url.possibly_invalid_spec();
+
+ // Tell the renderer that this request was disallowed.
+ Cancel();
+ return;
+ }
}
if (delegate_->HandleExternalProtocol(this, redirect_info.new_url)) {
diff --git a/chromium/content/browser/loader/resource_loader.h b/chromium/content/browser/loader/resource_loader.h
index 8dcaf63fc45..6ebcd2de50b 100644
--- a/chromium/content/browser/loader/resource_loader.h
+++ b/chromium/content/browser/loader/resource_loader.h
@@ -7,10 +7,10 @@
#include <memory>
+#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "base/timer/timer.h"
-#include "content/browser/loader/resource_handler.h"
+#include "base/time/time.h"
#include "content/browser/ssl/ssl_client_auth_handler.h"
#include "content/browser/ssl/ssl_error_handler.h"
#include "content/common/content_export.h"
@@ -23,6 +23,7 @@ class X509Certificate;
namespace content {
class ResourceDispatcherHostLoginDelegate;
+class ResourceHandler;
class ResourceLoaderDelegate;
class ResourceRequestInfoImpl;
@@ -43,7 +44,7 @@ class CONTENT_EXPORT ResourceLoader : public net::URLRequest::Delegate,
void CancelRequest(bool from_renderer);
bool is_transferring() const { return is_transferring_; }
- void MarkAsTransferring(const scoped_refptr<ResourceResponse>& response);
+ void MarkAsTransferring(const base::Closure& on_transfer_complete_callback);
void CompleteTransfer();
net::URLRequest* request() { return request_.get(); }
@@ -129,6 +130,9 @@ class CONTENT_EXPORT ResourceLoader : public net::URLRequest::Delegate,
// which point we'll receive a new ResourceHandler.
bool is_transferring_;
+ // Called when a navigation has finished transfer.
+ base::Closure on_transfer_complete_callback_;
+
// Instrumentation add to investigate http://crbug.com/503306.
// TODO(mmenke): Remove once bug is fixed.
int times_cancelled_before_request_start_;
diff --git a/chromium/content/browser/loader/resource_loader_delegate.h b/chromium/content/browser/loader/resource_loader_delegate.h
index 36702faf567..a6b2be979c0 100644
--- a/chromium/content/browser/loader/resource_loader_delegate.h
+++ b/chromium/content/browser/loader/resource_loader_delegate.h
@@ -7,6 +7,8 @@
#include "content/common/content_export.h"
+class GURL;
+
namespace net {
class AuthChallengeInfo;
class ClientCertStore;
diff --git a/chromium/content/browser/loader/resource_message_filter.cc b/chromium/content/browser/loader/resource_message_filter.cc
index b14afa1b422..2ee8ff5c7a7 100644
--- a/chromium/content/browser/loader/resource_message_filter.cc
+++ b/chromium/content/browser/loader/resource_message_filter.cc
@@ -6,8 +6,8 @@
#include "content/browser/appcache/chrome_appcache_service.h"
#include "content/browser/blob_storage/chrome_blob_storage_context.h"
-#include "content/browser/host_zoom_level_context.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/loader/url_loader_factory_impl.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/common/resource_messages.h"
#include "content/public/browser/resource_context.h"
@@ -22,27 +22,34 @@ ResourceMessageFilter::ResourceMessageFilter(
ChromeBlobStorageContext* blob_storage_context,
storage::FileSystemContext* file_system_context,
ServiceWorkerContextWrapper* service_worker_context,
- HostZoomLevelContext* host_zoom_level_context,
const GetContextsCallback& get_contexts_callback)
: BrowserMessageFilter(ResourceMsgStart),
+ BrowserAssociatedInterface<mojom::URLLoaderFactory>(this, this),
child_id_(child_id),
process_type_(process_type),
+ is_channel_closed_(false),
appcache_service_(appcache_service),
blob_storage_context_(blob_storage_context),
file_system_context_(file_system_context),
service_worker_context_(service_worker_context),
- host_zoom_level_context_(host_zoom_level_context),
get_contexts_callback_(get_contexts_callback),
- weak_ptr_factory_(this) {
-}
+ weak_ptr_factory_(this) {}
ResourceMessageFilter::~ResourceMessageFilter() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(is_channel_closed_);
+ DCHECK(!weak_ptr_factory_.HasWeakPtrs());
}
void ResourceMessageFilter::OnChannelClosing() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
// Unhook us from all pending network requests so they don't get sent to a
// deleted object.
ResourceDispatcherHostImpl::Get()->CancelRequestsForProcess(child_id_);
+
+ weak_ptr_factory_.InvalidateWeakPtrs();
+ is_channel_closed_ = true;
}
bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) {
@@ -63,15 +70,28 @@ void ResourceMessageFilter::GetContexts(
request_context);
}
-const HostZoomMap* ResourceMessageFilter::GetHostZoomMap() const {
- if (host_zoom_level_context_.get())
- return host_zoom_level_context_->GetHostZoomMap();
- return NULL;
-}
-
base::WeakPtr<ResourceMessageFilter> ResourceMessageFilter::GetWeakPtr() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- return weak_ptr_factory_.GetWeakPtr();
+ return is_channel_closed_ ? nullptr : weak_ptr_factory_.GetWeakPtr();
+}
+
+void ResourceMessageFilter::CreateLoaderAndStart(
+ mojom::URLLoaderAssociatedRequest request,
+ int32_t routing_id,
+ int32_t request_id,
+ const ResourceRequest& url_request,
+ mojom::URLLoaderClientAssociatedPtrInfo client_ptr_info) {
+ URLLoaderFactoryImpl::CreateLoaderAndStart(std::move(request), routing_id,
+ request_id, url_request,
+ std::move(client_ptr_info), this);
+}
+
+void ResourceMessageFilter::SyncLoad(int32_t routing_id,
+ int32_t request_id,
+ const ResourceRequest& url_request,
+ const SyncLoadCallback& callback) {
+ URLLoaderFactoryImpl::SyncLoad(routing_id, request_id, url_request, callback,
+ this);
}
} // namespace content
diff --git a/chromium/content/browser/loader/resource_message_filter.h b/chromium/content/browser/loader/resource_message_filter.h
index 4037826d7b1..bcc07138851 100644
--- a/chromium/content/browser/loader/resource_message_filter.h
+++ b/chromium/content/browser/loader/resource_message_filter.h
@@ -11,8 +11,9 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner_helpers.h"
-#include "content/browser/host_zoom_level_context.h"
#include "content/common/content_export.h"
+#include "content/common/url_loader_factory.mojom.h"
+#include "content/public/browser/browser_associated_interface.h"
#include "content/public/browser/browser_message_filter.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/resource_type.h"
@@ -37,7 +38,10 @@ class ServiceWorkerContextWrapper;
// delayed by costly UI processing that may be occuring on the main thread of
// the browser. It also means that any hangs in starting a network request
// will not interfere with browser UI.
-class CONTENT_EXPORT ResourceMessageFilter : public BrowserMessageFilter {
+class CONTENT_EXPORT ResourceMessageFilter
+ : public BrowserMessageFilter,
+ public BrowserAssociatedInterface<mojom::URLLoaderFactory>,
+ public mojom::URLLoaderFactory {
public:
typedef base::Callback<void(ResourceType resource_type,
ResourceContext**,
@@ -54,7 +58,6 @@ class CONTENT_EXPORT ResourceMessageFilter : public BrowserMessageFilter {
ChromeBlobStorageContext* blob_storage_context,
storage::FileSystemContext* file_system_context,
ServiceWorkerContextWrapper* service_worker_context,
- HostZoomLevelContext* host_zoom_level_context,
const GetContextsCallback& get_contexts_callback);
// BrowserMessageFilter implementation.
@@ -85,15 +88,22 @@ class CONTENT_EXPORT ResourceMessageFilter : public BrowserMessageFilter {
return service_worker_context_.get();
}
- // Returns a raw pointer to the HostZoomLevelContext's associated HostZoomMap,
- // or NULL if no context is present.
- const HostZoomMap* GetHostZoomMap() const;
-
int child_id() const { return child_id_; }
int process_type() const { return process_type_; }
base::WeakPtr<ResourceMessageFilter> GetWeakPtr();
+ void CreateLoaderAndStart(
+ mojom::URLLoaderAssociatedRequest request,
+ int32_t routing_id,
+ int32_t request_id,
+ const ResourceRequest& url_request,
+ mojom::URLLoaderClientAssociatedPtrInfo client_ptr_info) override;
+ void SyncLoad(int32_t routing_id,
+ int32_t request_id,
+ const ResourceRequest& request,
+ const SyncLoadCallback& callback) override;
+
protected:
// Protected destructor so that we can be overriden in tests.
~ResourceMessageFilter() override;
@@ -106,12 +116,12 @@ class CONTENT_EXPORT ResourceMessageFilter : public BrowserMessageFilter {
int child_id_;
int process_type_;
+ bool is_channel_closed_;
scoped_refptr<ChromeAppCacheService> appcache_service_;
scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
scoped_refptr<storage::FileSystemContext> file_system_context_;
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
- scoped_refptr<HostZoomLevelContext> host_zoom_level_context_;
GetContextsCallback get_contexts_callback_;
diff --git a/chromium/content/browser/loader/resource_request_info_impl.cc b/chromium/content/browser/loader/resource_request_info_impl.cc
index d9f14b9706a..fc7d9730281 100644
--- a/chromium/content/browser/loader/resource_request_info_impl.cc
+++ b/chromium/content/browser/loader/resource_request_info_impl.cc
@@ -160,8 +160,7 @@ ResourceRequestInfoImpl::ResourceRequestInfoImpl(
const std::string& original_headers,
const scoped_refptr<ResourceRequestBodyImpl> body,
bool initiated_in_secure_context)
- : cross_site_handler_(NULL),
- detachable_handler_(NULL),
+ : detachable_handler_(NULL),
process_type_(process_type),
child_id_(child_id),
route_id_(route_id),
@@ -233,6 +232,10 @@ int ResourceRequestInfoImpl::GetRouteID() const {
return route_id_;
}
+GlobalRequestID ResourceRequestInfoImpl::GetGlobalRequestID() const {
+ return GlobalRequestID(child_id_, request_id_);
+}
+
int ResourceRequestInfoImpl::GetOriginPID() const {
return origin_pid_;
}
@@ -325,10 +328,6 @@ int ResourceRequestInfoImpl::GetRequestID() const {
return request_id_;
}
-GlobalRequestID ResourceRequestInfoImpl::GetGlobalRequestID() const {
- return GlobalRequestID(child_id_, request_id_);
-}
-
GlobalRoutingID ResourceRequestInfoImpl::GetGlobalRoutingID() const {
return GlobalRoutingID(child_id_, route_id_);
}
diff --git a/chromium/content/browser/loader/resource_request_info_impl.h b/chromium/content/browser/loader/resource_request_info_impl.h
index 356efa4cf8a..97cc7198960 100644
--- a/chromium/content/browser/loader/resource_request_info_impl.h
+++ b/chromium/content/browser/loader/resource_request_info_impl.h
@@ -7,12 +7,14 @@
#include <memory>
#include <string>
+#include <utility>
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/supports_user_data.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/common/resource_request_body_impl.h"
#include "content/public/browser/navigation_ui_data.h"
#include "content/public/browser/resource_request_info.h"
@@ -21,7 +23,6 @@
#include "net/base/load_states.h"
namespace content {
-class CrossSiteResourceHandler;
class DetachableResourceHandler;
class ResourceContext;
class ResourceMessageFilter;
@@ -78,6 +79,7 @@ class ResourceRequestInfoImpl : public ResourceRequestInfo,
ResourceContext* GetContext() const override;
int GetChildID() const override;
int GetRouteID() const override;
+ GlobalRequestID GetGlobalRequestID() const override;
int GetOriginPID() const override;
int GetRenderFrameID() const override;
int GetFrameTreeNodeId() const override;
@@ -101,7 +103,6 @@ class ResourceRequestInfoImpl : public ResourceRequestInfo,
CONTENT_EXPORT void AssociateWithRequest(net::URLRequest* request);
CONTENT_EXPORT int GetRequestID() const;
- CONTENT_EXPORT GlobalRequestID GetGlobalRequestID() const;
GlobalRoutingID GetGlobalRoutingID() const;
// PlzNavigate
@@ -125,14 +126,6 @@ class ResourceRequestInfoImpl : public ResourceRequestInfo,
int request_id,
base::WeakPtr<ResourceMessageFilter> filter);
- // CrossSiteResourceHandler for this request. May be null.
- CrossSiteResourceHandler* cross_site_handler() {
- return cross_site_handler_;
- }
- void set_cross_site_handler(CrossSiteResourceHandler* h) {
- cross_site_handler_ = h;
- }
-
// Whether this request is part of a navigation that should replace the
// current session history entry. This state is shuffled up and down the stack
// for request transfers.
@@ -205,13 +198,23 @@ class ResourceRequestInfoImpl : public ResourceRequestInfo,
navigation_ui_data_ = std::move(navigation_ui_data);
}
+ // PlzNavigate: used in navigations to store the ServiceWorkerContext, since
+ // the ResourceMessageFilter will be null in this case. All other requests
+ // should access the ServiceWorkerContext through the ResourceMessageFilter.
+ void set_service_worker_context(
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context) {
+ service_worker_context_ = service_worker_context;
+ }
+ ServiceWorkerContextWrapper* service_worker_context() const {
+ return service_worker_context_.get();
+ }
+
private:
FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
DeletedFilterDetached);
FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
DeletedFilterDetachedRedirect);
// Non-owning, may be NULL.
- CrossSiteResourceHandler* cross_site_handler_;
DetachableResourceHandler* detachable_handler_;
int process_type_;
@@ -249,6 +252,7 @@ class ResourceRequestInfoImpl : public ResourceRequestInfo,
scoped_refptr<ResourceRequestBodyImpl> body_;
bool initiated_in_secure_context_;
std::unique_ptr<NavigationUIData> navigation_ui_data_;
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
DISALLOW_COPY_AND_ASSIGN(ResourceRequestInfoImpl);
};
diff --git a/chromium/content/browser/loader/resource_scheduler.cc b/chromium/content/browser/loader/resource_scheduler.cc
index 2253b57d4a9..ad67fa91cd5 100644
--- a/chromium/content/browser/loader/resource_scheduler.cc
+++ b/chromium/content/browser/loader/resource_scheduler.cc
@@ -10,6 +10,7 @@
#include <utility>
#include <vector>
+#include "base/feature_list.h"
#include "base/macros.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
@@ -31,6 +32,13 @@ namespace content {
namespace {
+// When kPrioritySupportedRequestsDelayable is enabled, requests for
+// H2/QUIC/SPDY resources can be delayed by the ResourceScheduler just as
+// HTTP/1.1 resources are. Disabling this appears to have negative performance
+// impact, see https://crbug.com/655585.
+const base::Feature kPrioritySupportedRequestsDelayable{
+ "PrioritySupportedRequestsDelayable", base::FEATURE_DISABLED_BY_DEFAULT};
+
enum StartMode {
START_SYNC,
START_ASYNC
@@ -170,6 +178,7 @@ class ResourceScheduler::ScheduledResourceRequest : public ResourceThrottle {
scheduler_(scheduler),
priority_(priority),
fifo_ordering_(0),
+ host_port_pair_(net::HostPortPair::FromURL(request->url())),
weak_ptr_factory_(this) {
DCHECK(!request_->GetUserData(kUserDataKey));
request_->SetUserData(kUserDataKey, new UnownedPointer(this));
@@ -235,6 +244,7 @@ class ResourceScheduler::ScheduledResourceRequest : public ResourceThrottle {
void set_attributes(RequestAttributes attributes) {
attributes_ = attributes;
}
+ const net::HostPortPair& host_port_pair() const { return host_port_pair_; }
private:
class UnownedPointer : public base::SupportsUserData::Data {
@@ -268,6 +278,8 @@ class ResourceScheduler::ScheduledResourceRequest : public ResourceThrottle {
ResourceScheduler* scheduler_;
RequestPriorityParams priority_;
uint32_t fifo_ordering_;
+ // Cached to excessive recomputation in ShouldKeepSearching.
+ const net::HostPortPair host_port_pair_;
base::WeakPtrFactory<ResourceScheduler::ScheduledResourceRequest>
weak_ptr_factory_;
@@ -304,12 +316,13 @@ void ResourceScheduler::RequestQueue::Insert(
// Each client represents a tab.
class ResourceScheduler::Client {
public:
- explicit Client(ResourceScheduler* scheduler)
+ explicit Client(bool priority_requests_delayable)
: is_loaded_(false),
has_html_body_(false),
using_spdy_proxy_(false),
in_flight_delayable_count_(0),
- total_layout_blocking_count_(0) {}
+ total_layout_blocking_count_(0),
+ priority_requests_delayable_(priority_requests_delayable) {}
~Client() {}
@@ -513,14 +526,20 @@ class ResourceScheduler::Client {
attributes |= kAttributeLayoutBlocking;
} else if (request->url_request()->priority() <
kDelayablePriorityThreshold) {
- // Resources below the delayable priority threshold that are being
- // requested from a server that does not support native prioritization are
- // considered delayable.
- url::SchemeHostPort scheme_host_port(request->url_request()->url());
- net::HttpServerProperties& http_server_properties =
- *request->url_request()->context()->http_server_properties();
- if (!http_server_properties.SupportsRequestPriority(scheme_host_port))
+ if (priority_requests_delayable_) {
+ // Resources below the delayable priority threshold that are considered
+ // delayable.
attributes |= kAttributeDelayable;
+ } else {
+ // Resources below the delayable priority threshold that are being
+ // requested from a server that does not support native prioritization
+ // are considered delayable.
+ url::SchemeHostPort scheme_host_port(request->url_request()->url());
+ net::HttpServerProperties& http_server_properties =
+ *request->url_request()->context()->http_server_properties();
+ if (!http_server_properties.SupportsRequestPriority(scheme_host_port))
+ attributes |= kAttributeDelayable;
+ }
}
return attributes;
@@ -531,9 +550,7 @@ class ResourceScheduler::Client {
size_t same_host_count = 0;
for (RequestSet::const_iterator it = in_flight_requests_.begin();
it != in_flight_requests_.end(); ++it) {
- net::HostPortPair host_port_pair =
- net::HostPortPair::FromURL((*it)->url_request()->url());
- if (active_request_host.Equals(host_port_pair)) {
+ if (active_request_host.Equals((*it)->host_port_pair())) {
same_host_count++;
if (same_host_count >= kMaxNumDelayableRequestsPerHostPerClient)
return true;
@@ -595,20 +612,23 @@ class ResourceScheduler::Client {
if (!url_request.url().SchemeIsHTTPOrHTTPS())
return START_REQUEST;
- if (using_spdy_proxy_ && url_request.url().SchemeIs(url::kHttpScheme))
- return START_REQUEST;
+ const net::HostPortPair& host_port_pair = request->host_port_pair();
- net::HostPortPair host_port_pair =
- net::HostPortPair::FromURL(url_request.url());
- url::SchemeHostPort scheme_host_port(url_request.url());
- net::HttpServerProperties& http_server_properties =
- *url_request.context()->http_server_properties();
+ if (!priority_requests_delayable_) {
+ if (using_spdy_proxy_ && url_request.url().SchemeIs(url::kHttpScheme))
+ return START_REQUEST;
- // TODO(willchan): We should really improve this algorithm as described in
- // crbug.com/164101. Also, theoretically we should not count a
- // request-priority capable request against the delayable requests limit.
- if (http_server_properties.SupportsRequestPriority(scheme_host_port))
- return START_REQUEST;
+ url::SchemeHostPort scheme_host_port(url_request.url());
+
+ net::HttpServerProperties& http_server_properties =
+ *url_request.context()->http_server_properties();
+
+ // TODO(willchan): We should really improve this algorithm as described in
+ // crbug.com/164101. Also, theoretically we should not count a
+ // request-priority capable request against the delayable requests limit.
+ if (http_server_properties.SupportsRequestPriority(scheme_host_port))
+ return START_REQUEST;
+ }
// Non-delayable requests.
if (!RequestAttributesAreSet(request->attributes(), kAttributeDelayable))
@@ -698,9 +718,15 @@ class ResourceScheduler::Client {
size_t in_flight_delayable_count_;
// The number of layout-blocking in-flight requests.
size_t total_layout_blocking_count_;
+
+ // True if requests to servers that support priorities (e.g., H2/QUIC) can
+ // be delayed.
+ bool priority_requests_delayable_;
};
-ResourceScheduler::ResourceScheduler() {}
+ResourceScheduler::ResourceScheduler()
+ : priority_requests_delayable_(
+ base::FeatureList::IsEnabled(kPrioritySupportedRequestsDelayable)) {}
ResourceScheduler::~ResourceScheduler() {
DCHECK(unowned_requests_.empty());
@@ -757,7 +783,7 @@ void ResourceScheduler::OnClientCreated(int child_id,
ClientId client_id = MakeClientId(child_id, route_id);
DCHECK(!base::ContainsKey(client_map_, client_id));
- Client* client = new Client(this);
+ Client* client = new Client(priority_requests_delayable_);
client_map_[client_id] = client;
}
diff --git a/chromium/content/browser/loader/resource_scheduler.h b/chromium/content/browser/loader/resource_scheduler.h
index 0b4218227b9..76b455c409f 100644
--- a/chromium/content/browser/loader/resource_scheduler.h
+++ b/chromium/content/browser/loader/resource_scheduler.h
@@ -20,7 +20,6 @@
#include "net/base/request_priority.h"
namespace net {
-class HostPortPair;
class URLRequest;
}
@@ -137,6 +136,10 @@ class CONTENT_EXPORT ResourceScheduler : public base::NonThreadSafe {
size_t max_num_delayable_requests_;
RequestSet unowned_requests_;
+ // True if requests to servers that support priorities (e.g., H2/QUIC) can
+ // be delayed.
+ bool priority_requests_delayable_;
+
DISALLOW_COPY_AND_ASSIGN(ResourceScheduler);
};
diff --git a/chromium/content/browser/loader/resource_scheduler_unittest.cc b/chromium/content/browser/loader/resource_scheduler_unittest.cc
index 51b8a47b68e..cc40deabab4 100644
--- a/chromium/content/browser/loader/resource_scheduler_unittest.cc
+++ b/chromium/content/browser/loader/resource_scheduler_unittest.cc
@@ -8,18 +8,17 @@
#include "base/memory/ptr_util.h"
#include "base/memory/scoped_vector.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "base/timer/mock_timer.h"
#include "base/timer/timer.h"
-#include "content/browser/browser_thread_impl.h"
-#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/public/browser/resource_context.h"
#include "content/public/browser/resource_controller.h"
#include "content/public/browser/resource_throttle.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "content/test/test_render_view_host_factory.h"
#include "content/test/test_web_contents.h"
#include "net/base/host_port_pair.h"
@@ -46,6 +45,9 @@ const int kRouteId2 = 67;
const int kBackgroundChildId = 35;
const int kBackgroundRouteId = 43;
+const char kPrioritySupportedRequestsDelayable[] =
+ "PrioritySupportedRequestsDelayable";
+
class TestRequest : public ResourceController {
public:
TestRequest(std::unique_ptr<net::URLRequest> url_request,
@@ -124,9 +126,7 @@ class FakeResourceContext : public ResourceContext {
class ResourceSchedulerTest : public testing::Test {
protected:
- ResourceSchedulerTest()
- : ui_thread_(BrowserThread::UI, &message_loop_),
- io_thread_(BrowserThread::IO, &message_loop_) {
+ ResourceSchedulerTest() {
InitializeScheduler();
context_.set_http_server_properties(&http_server_properties_);
}
@@ -242,10 +242,7 @@ class ResourceSchedulerTest : public testing::Test {
return scheduler_.get();
}
- base::MessageLoopForIO message_loop_;
- BrowserThreadImpl ui_thread_;
- BrowserThreadImpl io_thread_;
- ResourceDispatcherHostImpl rdh_;
+ TestBrowserThreadBundle thread_bundle_;
std::unique_ptr<ResourceScheduler> scheduler_;
base::MockTimer* mock_timer_;
net::HttpServerPropertiesImpl http_server_properties_;
@@ -314,6 +311,11 @@ TEST_F(ResourceSchedulerTest, MediumDoesNotBlockCriticalComplete) {
}
TEST_F(ResourceSchedulerTest, OneLowLoadsUntilBodyInsertedExceptSpdy) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine("",
+ kPrioritySupportedRequestsDelayable);
+ InitializeScheduler();
+
http_server_properties_.SetSupportsSpdy(
url::SchemeHostPort("https", "spdyhost", 443), true);
std::unique_ptr<TestRequest> high(
@@ -333,6 +335,32 @@ TEST_F(ResourceSchedulerTest, OneLowLoadsUntilBodyInsertedExceptSpdy) {
EXPECT_TRUE(low2->started());
}
+TEST_F(ResourceSchedulerTest,
+ OneLowLoadsUntilBodyInsertedEvenSpdyWhenDelayable) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(kPrioritySupportedRequestsDelayable,
+ "");
+
+ InitializeScheduler();
+ http_server_properties_.SetSupportsSpdy(
+ url::SchemeHostPort("https", "spdyhost", 443), true);
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low_spdy(
+ NewRequest("https://spdyhost/low", net::LOWEST));
+ EXPECT_TRUE(high->started());
+ EXPECT_TRUE(low->started());
+ EXPECT_FALSE(low2->started());
+ EXPECT_FALSE(low_spdy->started());
+
+ scheduler()->OnWillInsertBody(kChildId, kRouteId);
+ high.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(low2->started());
+}
+
TEST_F(ResourceSchedulerTest, SpdyLowBlocksOtherLowUntilBodyInserted) {
http_server_properties_.SetSupportsSpdy(
url::SchemeHostPort("https", "spdyhost", 443), true);
@@ -631,6 +659,11 @@ TEST_F(ResourceSchedulerTest, NonHTTPSchedulesImmediately) {
}
TEST_F(ResourceSchedulerTest, SpdyProxySchedulesImmediately) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine("",
+ kPrioritySupportedRequestsDelayable);
+ InitializeScheduler();
+
std::unique_ptr<TestRequest> high(
NewRequest("http://host/high", net::HIGHEST));
std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
@@ -648,7 +681,35 @@ TEST_F(ResourceSchedulerTest, SpdyProxySchedulesImmediately) {
EXPECT_TRUE(after->started());
}
+TEST_F(ResourceSchedulerTest, SpdyProxyDelayable) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(kPrioritySupportedRequestsDelayable,
+ "");
+ InitializeScheduler();
+
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+
+ std::unique_ptr<TestRequest> request(
+ NewRequest("http://host/req", net::IDLE));
+ EXPECT_FALSE(request->started());
+
+ scheduler()->OnReceivedSpdyProxiedHttpResponse(kChildId, kRouteId);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(request->started());
+
+ std::unique_ptr<TestRequest> after(
+ NewRequest("http://host/after", net::IDLE));
+ EXPECT_FALSE(after->started());
+}
+
TEST_F(ResourceSchedulerTest, NewSpdyHostInDelayableRequests) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine("",
+ kPrioritySupportedRequestsDelayable);
+ InitializeScheduler();
+
scheduler()->OnWillInsertBody(kChildId, kRouteId);
const int kMaxNumDelayableRequestsPerClient = 10; // Should match the .cc.
@@ -682,6 +743,45 @@ TEST_F(ResourceSchedulerTest, NewSpdyHostInDelayableRequests) {
EXPECT_TRUE(low2->started());
}
+TEST_F(ResourceSchedulerTest, NewDelayableSpdyHostInDelayableRequests) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(kPrioritySupportedRequestsDelayable,
+ "");
+ InitializeScheduler();
+
+ scheduler()->OnWillInsertBody(kChildId, kRouteId);
+ const int kMaxNumDelayableRequestsPerClient = 10; // Should match the .cc.
+
+ std::unique_ptr<TestRequest> low1_spdy(
+ NewRequest("http://spdyhost1:8080/low", net::LOWEST));
+ // Cancel a request after we learn the server supports SPDY.
+ ScopedVector<TestRequest> lows;
+ for (int i = 0; i < kMaxNumDelayableRequestsPerClient - 1; ++i) {
+ string url = "http://host" + base::IntToString(i) + "/low";
+ lows.push_back(NewRequest(url.c_str(), net::LOWEST));
+ }
+ std::unique_ptr<TestRequest> low1(NewRequest("http://host/low", net::LOWEST));
+ EXPECT_FALSE(low1->started());
+ http_server_properties_.SetSupportsSpdy(
+ url::SchemeHostPort("http", "spdyhost1", 8080), true);
+ low1_spdy.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(low1->started());
+
+ low1.reset();
+ base::RunLoop().RunUntilIdle();
+ std::unique_ptr<TestRequest> low2_spdy(
+ NewRequest("http://spdyhost2:8080/low", net::IDLE));
+ // Reprioritize a request after we learn the server supports SPDY.
+ EXPECT_TRUE(low2_spdy->started());
+ http_server_properties_.SetSupportsSpdy(
+ url::SchemeHostPort("http", "spdyhost2", 8080), true);
+ ChangeRequestPriority(low2_spdy.get(), net::LOWEST);
+ base::RunLoop().RunUntilIdle();
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ EXPECT_FALSE(low2->started());
+}
+
// Async revalidations which are not started when the tab is closed must be
// started at some point, or they will hang around forever and prevent other
// async revalidations to the same URL from being issued.
diff --git a/chromium/content/browser/loader/sync_resource_handler.cc b/chromium/content/browser/loader/sync_resource_handler.cc
index 47991f5fe24..b0475ce0db1 100644
--- a/chromium/content/browser/loader/sync_resource_handler.cc
+++ b/chromium/content/browser/loader/sync_resource_handler.cc
@@ -4,6 +4,7 @@
#include "content/browser/loader/sync_resource_handler.h"
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "content/browser/loader/netlog_observer.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
@@ -20,25 +21,19 @@ namespace content {
SyncResourceHandler::SyncResourceHandler(
net::URLRequest* request,
- IPC::Message* result_message,
+ const SyncLoadResultCallback& result_handler,
ResourceDispatcherHostImpl* resource_dispatcher_host)
: ResourceHandler(request),
read_buffer_(new net::IOBuffer(kReadBufSize)),
- result_message_(result_message),
+ result_handler_(result_handler),
rdh_(resource_dispatcher_host),
total_transfer_size_(0) {
result_.final_url = request->url();
}
SyncResourceHandler::~SyncResourceHandler() {
- if (result_message_) {
- result_message_->set_reply_error();
- ResourceMessageFilter* filter = GetFilter();
- // If the filter doesn't exist at this point, the process has died and isn't
- // waiting for the result message anymore.
- if (filter)
- filter->Send(result_message_);
- }
+ if (result_handler_)
+ result_handler_.Run(nullptr);
}
bool SyncResourceHandler::OnRequestRedirected(
@@ -114,20 +109,13 @@ bool SyncResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
void SyncResourceHandler::OnResponseCompleted(
const net::URLRequestStatus& status,
bool* defer) {
- ResourceMessageFilter* filter = GetFilter();
- if (!filter)
- return;
-
result_.error_code = status.error();
int total_transfer_size = request()->GetTotalReceivedBytes();
result_.encoded_data_length = total_transfer_size_ + total_transfer_size;
result_.encoded_body_length = request()->GetRawBodyBytes();
- ResourceHostMsg_SyncLoad::WriteReplyParams(result_message_, result_);
- filter->Send(result_message_);
- result_message_ = NULL;
- return;
+ base::ResetAndReturn(&result_handler_).Run(&result_);
}
void SyncResourceHandler::OnDataDownloaded(int bytes_downloaded) {
diff --git a/chromium/content/browser/loader/sync_resource_handler.h b/chromium/content/browser/loader/sync_resource_handler.h
index 00e2794002c..2ab87a79ca5 100644
--- a/chromium/content/browser/loader/sync_resource_handler.h
+++ b/chromium/content/browser/loader/sync_resource_handler.h
@@ -9,6 +9,7 @@
#include <string>
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/loader/resource_handler.h"
#include "content/public/common/resource_response.h"
@@ -22,16 +23,16 @@ class URLRequest;
}
namespace content {
-class ResourceContext;
-class ResourceDispatcherHostImpl;
-class ResourceMessageFilter;
// Used to complete a synchronous resource request in response to resource load
// events from the resource dispatcher host.
class SyncResourceHandler : public ResourceHandler {
public:
+ using SyncLoadResultCallback =
+ ResourceDispatcherHostImpl::SyncLoadResultCallback;
+
SyncResourceHandler(net::URLRequest* request,
- IPC::Message* result_message,
+ const SyncLoadResultCallback& sync_result_handler,
ResourceDispatcherHostImpl* resource_dispatcher_host);
~SyncResourceHandler() override;
@@ -54,7 +55,7 @@ class SyncResourceHandler : public ResourceHandler {
scoped_refptr<net::IOBuffer> read_buffer_;
SyncLoadResult result_;
- IPC::Message* result_message_;
+ SyncLoadResultCallback result_handler_;
ResourceDispatcherHostImpl* rdh_;
int64_t total_transfer_size_;
};
diff --git a/chromium/content/browser/loader/test_resource_handler.cc b/chromium/content/browser/loader/test_resource_handler.cc
new file mode 100644
index 00000000000..0ee72ae6744
--- /dev/null
+++ b/chromium/content/browser/loader/test_resource_handler.cc
@@ -0,0 +1,111 @@
+// Copyright 2016 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 "content/browser/loader/test_resource_handler.h"
+
+#include "base/logging.h"
+#include "net/url_request/url_request_status.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+TestResourceHandler::TestResourceHandler(net::URLRequestStatus* request_status,
+ std::string* body)
+ : ResourceHandler(nullptr), request_status_(request_status), body_(body) {
+ SetBufferSize(2048);
+}
+
+TestResourceHandler::TestResourceHandler()
+ : TestResourceHandler(nullptr, nullptr) {}
+
+TestResourceHandler::~TestResourceHandler() {}
+
+void TestResourceHandler::SetController(ResourceController* controller) {}
+
+bool TestResourceHandler::OnRequestRedirected(
+ const net::RedirectInfo& redirect_info,
+ ResourceResponse* response,
+ bool* defer) {
+ NOTREACHED() << "Redirects are not supported by the TestResourceHandler.";
+ return false;
+}
+
+bool TestResourceHandler::OnResponseStarted(ResourceResponse* response,
+ bool* defer) {
+ EXPECT_EQ(1, on_will_start_called_);
+ EXPECT_EQ(0, on_response_started_called_);
+ EXPECT_EQ(0, on_response_completed_called_);
+ ++on_response_started_called_;
+
+ if (!on_response_started_result_)
+ return false;
+ *defer = defer_on_response_started_;
+ defer_on_response_started_ = false;
+ return true;
+}
+
+bool TestResourceHandler::OnWillStart(const GURL& url, bool* defer) {
+ EXPECT_EQ(0, on_response_started_called_);
+ EXPECT_EQ(0, on_will_start_called_);
+ EXPECT_EQ(0, on_response_completed_called_);
+ ++on_will_start_called_;
+
+ if (!on_will_start_result_)
+ return false;
+
+ *defer = defer_on_will_start_;
+ return true;
+}
+
+bool TestResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ int min_size) {
+ EXPECT_EQ(0, on_response_completed_called_);
+ ++on_will_read_called_;
+
+ *buf = buffer_;
+ *buf_size = buffer_size_;
+ memset(buffer_->data(), '\0', buffer_size_);
+ return on_will_read_result_;
+}
+
+bool TestResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
+ EXPECT_EQ(1, on_will_start_called_);
+ EXPECT_EQ(1, on_response_started_called_);
+ EXPECT_EQ(0, on_response_completed_called_);
+ ++on_read_completed_called_;
+
+ EXPECT_LE(static_cast<size_t>(bytes_read), buffer_size_);
+ if (body_)
+ body_->append(buffer_->data(), bytes_read);
+ if (!on_read_completed_result_)
+ return false;
+ *defer = defer_on_read_completed_;
+ defer_on_read_completed_ = false;
+ return true;
+}
+
+void TestResourceHandler::OnResponseCompleted(
+ const net::URLRequestStatus& status,
+ bool* defer) {
+ EXPECT_EQ(0, on_response_completed_called_);
+ ++on_response_completed_called_;
+
+ if (request_status_)
+ *request_status_ = status;
+ *defer = defer_on_response_completed_;
+ defer_on_response_completed_ = false;
+}
+
+void TestResourceHandler::OnDataDownloaded(int bytes_downloaded) {
+ NOTREACHED() << "Saving to file is not supported by the TestResourceHandler.";
+}
+
+void TestResourceHandler::SetBufferSize(int buffer_size) {
+ buffer_ = new net::IOBuffer(buffer_size);
+ buffer_size_ = buffer_size;
+ memset(buffer_->data(), '\0', buffer_size);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/loader/test_resource_handler.h b/chromium/content/browser/loader/test_resource_handler.h
new file mode 100644
index 00000000000..134f9a6e42c
--- /dev/null
+++ b/chromium/content/browser/loader/test_resource_handler.h
@@ -0,0 +1,132 @@
+// Copyright 2016 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 CONTENT_BROWSER_LOADER_TEST_RESOURCE_HANDLER_H_
+#define CONTENT_BROWSER_LOADER_TEST_RESOURCE_HANDLER_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "content/browser/loader/resource_handler.h"
+#include "net/base/io_buffer.h"
+
+class GURL;
+
+namespace net {
+class URLRequest;
+class URLRequestStatus;
+}
+
+namespace content {
+
+class ResourceHandler;
+struct ResourceResponse;
+
+// A test version of a ResourceHandler. It returns a configurable buffer in
+// response to OnWillStart. It records what ResourceHandler methods are called,
+// and verifies that they are called in the correct order. It can optionally
+// defer or fail the request at any stage, and record the response body and
+// final status it sees. Redirects currently not supported.
+class TestResourceHandler : public ResourceHandler {
+ public:
+ // If non-null, |request_status| will be updated when the response is complete
+ // with the final status of the request received by the handler and |body|
+ // will be updated on each OnReadCompleted call.
+ TestResourceHandler(net::URLRequestStatus* request_status, std::string* body);
+ TestResourceHandler();
+ ~TestResourceHandler() override;
+
+ // ResourceHandler implementation:
+ void SetController(ResourceController* controller) override;
+ bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
+ ResourceResponse* response,
+ bool* defer) override;
+ bool OnResponseStarted(ResourceResponse* response, bool* defer) override;
+ bool OnWillStart(const GURL& url, bool* defer) override;
+ bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ int min_size) override;
+ bool OnReadCompleted(int bytes_read, bool* defer) override;
+ void OnResponseCompleted(const net::URLRequestStatus& status,
+ bool* defer) override;
+ void OnDataDownloaded(int bytes_downloaded) override;
+
+ // Sets the size of the read buffer returned by OnWillRead. Releases reference
+ // to previous read buffer. Default size is 2048 bytes.
+ void SetBufferSize(int buffer_size);
+
+ scoped_refptr<net::IOBuffer> buffer() const { return buffer_; }
+
+ // Sets the result returned by each method. All default to returning true.
+ void set_on_will_start_result(bool on_will_start_result) {
+ on_will_start_result_ = on_will_start_result;
+ }
+ void set_on_response_started_result(bool on_response_started_result) {
+ on_response_started_result_ = on_response_started_result;
+ }
+ void set_on_will_read_result(bool on_will_read_result) {
+ on_will_read_result_ = on_will_read_result;
+ }
+ void set_on_read_completed_result(bool on_read_completed_result) {
+ on_read_completed_result_ = on_read_completed_result;
+ }
+
+ // Cause |defer| to be set to true when the specified method is invoked. The
+ // test itself is responsible for resuming the request after deferral.
+
+ void set_defer_on_will_start(bool defer_on_will_start) {
+ defer_on_will_start_ = defer_on_will_start;
+ }
+ void set_defer_on_response_started(bool defer_on_response_started) {
+ defer_on_response_started_ = defer_on_response_started;
+ }
+ // Only the next OnReadCompleted call will set |defer| to true.
+ void set_defer_on_read_completed(bool defer_on_read_completed) {
+ defer_on_read_completed_ = defer_on_read_completed;
+ }
+ void set_defer_on_response_completed(bool defer_on_response_completed) {
+ defer_on_response_completed_ = defer_on_response_completed;
+ }
+
+ // Return the number of times the corresponding method was invoked.
+
+ int on_will_start_called() const { return on_will_start_called_; }
+ // Redirection currently not supported.
+ int on_request_redirected_called() const { return 0; }
+ int on_response_started_called() const { return on_response_started_called_; }
+ int on_will_read_called() const { return on_will_read_called_; }
+ int on_read_completed_called() const { return on_read_completed_called_; }
+ int on_response_completed_called() const {
+ return on_response_completed_called_;
+ }
+
+ private:
+ net::URLRequestStatus* request_status_;
+ std::string* body_;
+ scoped_refptr<net::IOBuffer> buffer_;
+ size_t buffer_size_;
+
+ bool on_will_start_result_ = true;
+ bool on_response_started_result_ = true;
+ bool on_will_read_result_ = true;
+ bool on_read_completed_result_ = true;
+
+ bool defer_on_will_start_ = false;
+ bool defer_on_response_started_ = false;
+ bool defer_on_read_completed_ = false;
+ bool defer_on_response_completed_ = false;
+
+ int on_will_start_called_ = 0;
+ int on_response_started_called_ = 0;
+ int on_will_read_called_ = 0;
+ int on_read_completed_called_ = 0;
+ int on_response_completed_called_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(TestResourceHandler);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_LOADER_TEST_RESOURCE_HANDLER_H_
diff --git a/chromium/content/browser/loader/test_url_loader_client.cc b/chromium/content/browser/loader/test_url_loader_client.cc
index 035a050d28a..caa858312f4 100644
--- a/chromium/content/browser/loader/test_url_loader_client.cc
+++ b/chromium/content/browser/loader/test_url_loader_client.cc
@@ -4,7 +4,9 @@
#include "content/browser/loader/test_url_loader_client.h"
+#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
namespace content {
@@ -15,8 +17,31 @@ void TestURLLoaderClient::OnReceiveResponse(
const ResourceResponseHead& response_head) {
has_received_response_ = true;
response_head_ = response_head;
- if (quit_closure_for_on_received_response_)
- quit_closure_for_on_received_response_.Run();
+ if (quit_closure_for_on_receive_response_)
+ quit_closure_for_on_receive_response_.Run();
+}
+
+void TestURLLoaderClient::OnReceiveRedirect(
+ const net::RedirectInfo& redirect_info,
+ const ResourceResponseHead& response_head) {
+ EXPECT_FALSE(response_body_.is_valid());
+ EXPECT_FALSE(has_received_response_);
+ // Use ClearHasReceivedRedirect to accept more redirects.
+ EXPECT_FALSE(has_received_redirect_);
+ has_received_redirect_ = true;
+ redirect_info_ = redirect_info;
+ response_head_ = response_head;
+ if (quit_closure_for_on_receive_redirect_)
+ quit_closure_for_on_receive_redirect_.Run();
+}
+
+void TestURLLoaderClient::OnDataDownloaded(int64_t data_length,
+ int64_t encoded_data_length) {
+ has_data_downloaded_ = true;
+ download_data_length_ += data_length;
+ encoded_download_data_length_ += encoded_data_length;
+ if (quit_closure_for_on_data_downloaded_)
+ quit_closure_for_on_data_downloaded_.Run();
}
void TestURLLoaderClient::OnStartLoadingResponseBody(
@@ -34,8 +59,16 @@ void TestURLLoaderClient::OnComplete(
quit_closure_for_on_complete_.Run();
}
-mojom::URLLoaderClientPtr TestURLLoaderClient::CreateInterfacePtrAndBind() {
- return binding_.CreateInterfacePtrAndBind();
+void TestURLLoaderClient::ClearHasReceivedRedirect() {
+ has_received_redirect_ = false;
+}
+
+mojom::URLLoaderClientAssociatedPtrInfo
+TestURLLoaderClient::CreateRemoteAssociatedPtrInfo(
+ mojo::AssociatedGroup* associated_group) {
+ mojom::URLLoaderClientAssociatedPtrInfo client_ptr_info;
+ binding_.Bind(&client_ptr_info, associated_group);
+ return client_ptr_info;
}
void TestURLLoaderClient::Unbind() {
@@ -45,9 +78,23 @@ void TestURLLoaderClient::Unbind() {
void TestURLLoaderClient::RunUntilResponseReceived() {
base::RunLoop run_loop;
- quit_closure_for_on_received_response_ = run_loop.QuitClosure();
+ quit_closure_for_on_receive_response_ = run_loop.QuitClosure();
+ run_loop.Run();
+ quit_closure_for_on_receive_response_.Reset();
+}
+
+void TestURLLoaderClient::RunUntilRedirectReceived() {
+ base::RunLoop run_loop;
+ quit_closure_for_on_receive_redirect_ = run_loop.QuitClosure();
+ run_loop.Run();
+ quit_closure_for_on_receive_redirect_.Reset();
+}
+
+void TestURLLoaderClient::RunUntilDataDownloaded() {
+ base::RunLoop run_loop;
+ quit_closure_for_on_data_downloaded_ = run_loop.QuitClosure();
run_loop.Run();
- quit_closure_for_on_received_response_.Reset();
+ quit_closure_for_on_data_downloaded_.Reset();
}
void TestURLLoaderClient::RunUntilResponseBodyArrived() {
diff --git a/chromium/content/browser/loader/test_url_loader_client.h b/chromium/content/browser/loader/test_url_loader_client.h
index 78cb46f3f27..a12709bcca6 100644
--- a/chromium/content/browser/loader/test_url_loader_client.h
+++ b/chromium/content/browser/loader/test_url_loader_client.h
@@ -5,13 +5,17 @@
#ifndef CONTENT_BROWSER_LOADER_TEST_URL_LOADER_CLIENT_H_
#define CONTENT_BROWSER_LOADER_TEST_URL_LOADER_CLIENT_H_
+#include <stdint.h>
+
#include "base/callback.h"
#include "base/macros.h"
#include "content/common/resource_request_completion_status.h"
#include "content/common/url_loader.mojom.h"
+#include "content/common/url_loader_factory.mojom.h"
#include "content/public/common/resource_response.h"
#include "mojo/public/c/system/data_pipe.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "net/url_request/redirect_info.h"
namespace content {
@@ -25,35 +29,61 @@ class TestURLLoaderClient final : public mojom::URLLoaderClient {
~TestURLLoaderClient() override;
void OnReceiveResponse(const ResourceResponseHead& response_head) override;
+ void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
+ const ResourceResponseHead& response_head) override;
+ void OnDataDownloaded(int64_t data_length, int64_t encoded_length) override;
void OnStartLoadingResponseBody(
mojo::ScopedDataPipeConsumerHandle body) override;
void OnComplete(const ResourceRequestCompletionStatus& status) override;
bool has_received_response() const { return has_received_response_; }
+ bool has_received_redirect() const { return has_received_redirect_; }
+ bool has_data_downloaded() const { return has_data_downloaded_; }
bool has_received_completion() const { return has_received_completion_; }
const ResourceResponseHead& response_head() const { return response_head_; }
+ const net::RedirectInfo& redirect_info() const { return redirect_info_; }
mojo::DataPipeConsumerHandle response_body() { return response_body_.get(); }
const ResourceRequestCompletionStatus& completion_status() const {
return completion_status_;
}
+ int64_t download_data_length() const { return download_data_length_; }
+ int64_t encoded_download_data_length() const {
+ return encoded_download_data_length_;
+ }
+
+ void ClearHasReceivedRedirect();
+ // Creates an AssociatedPtrInfo, binds it to |*this| and returns it. The
+ // returned PtrInfo is marked as remote, i.e., expected to be passed to the
+ // remote endpoint.
+ mojom::URLLoaderClientAssociatedPtrInfo CreateRemoteAssociatedPtrInfo(
+ mojo::AssociatedGroup* associated_group);
- mojom::URLLoaderClientPtr CreateInterfacePtrAndBind();
void Unbind();
void RunUntilResponseReceived();
+ void RunUntilRedirectReceived();
+ void RunUntilDataDownloaded();
void RunUntilResponseBodyArrived();
void RunUntilComplete();
private:
- mojo::Binding<mojom::URLLoaderClient> binding_;
+ mojo::AssociatedBinding<mojom::URLLoaderClient> binding_;
ResourceResponseHead response_head_;
+ net::RedirectInfo redirect_info_;
mojo::ScopedDataPipeConsumerHandle response_body_;
ResourceRequestCompletionStatus completion_status_;
bool has_received_response_ = false;
+ bool has_received_redirect_ = false;
+ bool has_data_downloaded_ = false;
bool has_received_completion_ = false;
- base::Closure quit_closure_for_on_received_response_;
+ base::Closure quit_closure_for_on_receive_response_;
+ base::Closure quit_closure_for_on_receive_redirect_;
+ base::Closure quit_closure_for_on_data_downloaded_;
base::Closure quit_closure_for_on_start_loading_response_body_;
base::Closure quit_closure_for_on_complete_;
+ mojom::URLLoaderFactoryPtr url_loader_factory_;
+ int64_t download_data_length_ = 0;
+ int64_t encoded_download_data_length_ = 0;
DISALLOW_COPY_AND_ASSIGN(TestURLLoaderClient);
};
diff --git a/chromium/content/browser/loader/upload_data_stream_builder.cc b/chromium/content/browser/loader/upload_data_stream_builder.cc
index f3d79c6fd5a..389a8e9b394 100644
--- a/chromium/content/browser/loader/upload_data_stream_builder.cc
+++ b/chromium/content/browser/loader/upload_data_stream_builder.cc
@@ -14,6 +14,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
#include "content/browser/fileapi/upload_file_system_file_element_reader.h"
#include "content/common/resource_request_body_impl.h"
#include "net/base/elements_upload_data_stream.h"
@@ -24,6 +25,10 @@
#include "storage/browser/blob/blob_storage_context.h"
#include "storage/browser/blob/upload_blob_element_reader.h"
+namespace base {
+class TaskRunner;
+}
+
namespace disk_cache {
class Entry;
}
diff --git a/chromium/content/browser/loader/url_loader_factory_impl.cc b/chromium/content/browser/loader/url_loader_factory_impl.cc
index 7b11666452e..c510c147f2b 100644
--- a/chromium/content/browser/loader/url_loader_factory_impl.cc
+++ b/chromium/content/browser/loader/url_loader_factory_impl.cc
@@ -13,6 +13,26 @@
namespace content {
+namespace {
+
+void DispatchSyncLoadResult(
+ const URLLoaderFactoryImpl::SyncLoadCallback& callback,
+ const SyncLoadResult* result) {
+ // |result| can be null when a loading task is aborted unexpectedly. Reply
+ // with a failure result on that case.
+ // TODO(tzik): Test null-result case.
+ if (!result) {
+ SyncLoadResult failure;
+ failure.error_code = net::ERR_FAILED;
+ callback.Run(failure);
+ return;
+ }
+
+ callback.Run(*result);
+}
+
+} // namespace
+
URLLoaderFactoryImpl::URLLoaderFactoryImpl(
scoped_refptr<ResourceMessageFilter> resource_message_filter)
: resource_message_filter_(std::move(resource_message_filter)) {
@@ -25,17 +45,53 @@ URLLoaderFactoryImpl::~URLLoaderFactoryImpl() {
}
void URLLoaderFactoryImpl::CreateLoaderAndStart(
- mojom::URLLoaderRequest request,
+ mojom::URLLoaderAssociatedRequest request,
int32_t routing_id,
int32_t request_id,
const ResourceRequest& url_request,
- mojom::URLLoaderClientPtr client) {
+ mojom::URLLoaderClientAssociatedPtrInfo client_ptr_info) {
+ CreateLoaderAndStart(std::move(request), routing_id, request_id, url_request,
+ std::move(client_ptr_info),
+ resource_message_filter_.get());
+}
+
+void URLLoaderFactoryImpl::SyncLoad(int32_t routing_id,
+ int32_t request_id,
+ const ResourceRequest& url_request,
+ const SyncLoadCallback& callback) {
+ SyncLoad(routing_id, request_id, url_request, callback,
+ resource_message_filter_.get());
+}
+
+// static
+void URLLoaderFactoryImpl::CreateLoaderAndStart(
+ mojom::URLLoaderAssociatedRequest request,
+ int32_t routing_id,
+ int32_t request_id,
+ const ResourceRequest& url_request,
+ mojom::URLLoaderClientAssociatedPtrInfo client_ptr_info,
+ ResourceMessageFilter* filter) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ mojom::URLLoaderClientAssociatedPtr client;
+ client.Bind(std::move(client_ptr_info));
+
ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
rdh->OnRequestResourceWithMojo(routing_id, request_id, url_request,
- std::move(request), std::move(client),
- resource_message_filter_.get());
+ std::move(request), std::move(client), filter);
+}
+
+// static
+void URLLoaderFactoryImpl::SyncLoad(int32_t routing_id,
+ int32_t request_id,
+ const ResourceRequest& url_request,
+ const SyncLoadCallback& callback,
+ ResourceMessageFilter* filter) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
+ rdh->OnSyncLoadWithMojo(routing_id, request_id, url_request, filter,
+ base::Bind(&DispatchSyncLoadResult, callback));
}
void URLLoaderFactoryImpl::Create(
diff --git a/chromium/content/browser/loader/url_loader_factory_impl.h b/chromium/content/browser/loader/url_loader_factory_impl.h
index a54c44bf6c6..e989c3d872b 100644
--- a/chromium/content/browser/loader/url_loader_factory_impl.h
+++ b/chromium/content/browser/loader/url_loader_factory_impl.h
@@ -9,7 +9,6 @@
#include "base/memory/ref_counted.h"
#include "content/common/content_export.h"
#include "content/common/url_loader_factory.mojom.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
namespace content {
@@ -21,11 +20,29 @@ class URLLoaderFactoryImpl final : public mojom::URLLoaderFactory {
public:
~URLLoaderFactoryImpl() override;
- void CreateLoaderAndStart(mojom::URLLoaderRequest request,
- int32_t routing_id,
- int32_t request_id,
- const ResourceRequest& url_request,
- mojom::URLLoaderClientPtr client) override;
+ void CreateLoaderAndStart(
+ mojom::URLLoaderAssociatedRequest request,
+ int32_t routing_id,
+ int32_t request_id,
+ const ResourceRequest& url_request,
+ mojom::URLLoaderClientAssociatedPtrInfo client_ptr_info) override;
+ void SyncLoad(int32_t routing_id,
+ int32_t request_id,
+ const ResourceRequest& request,
+ const SyncLoadCallback& callback) override;
+
+ static void CreateLoaderAndStart(
+ mojom::URLLoaderAssociatedRequest request,
+ int32_t routing_id,
+ int32_t request_id,
+ const ResourceRequest& url_request,
+ mojom::URLLoaderClientAssociatedPtrInfo client_ptr_info,
+ ResourceMessageFilter* filter);
+ static void SyncLoad(int32_t routing_id,
+ int32_t request_id,
+ const ResourceRequest& request,
+ const SyncLoadCallback& callback,
+ ResourceMessageFilter* filter);
// Creates a URLLoaderFactoryImpl instance. The instance is held by the
// StrongBinding in it, so this function doesn't return the instance.
diff --git a/chromium/content/browser/loader/url_loader_factory_impl_unittest.cc b/chromium/content/browser/loader/url_loader_factory_impl_unittest.cc
index 84d082b6292..97f81a3f83b 100644
--- a/chromium/content/browser/loader/url_loader_factory_impl_unittest.cc
+++ b/chromium/content/browser/loader/url_loader_factory_impl_unittest.cc
@@ -4,6 +4,8 @@
#include "content/browser/loader/url_loader_factory_impl.h"
+#include <stdint.h>
+
#include <memory>
#include <string>
#include <utility>
@@ -46,6 +48,7 @@
#include "net/http/http_util.h"
#include "net/test/url_request/url_request_failed_job.h"
#include "net/test/url_request/url_request_mock_http_job.h"
+#include "net/test/url_request/url_request_slow_download_job.h"
#include "net/url_request/url_request_filter.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -90,7 +93,6 @@ class URLLoaderFactoryImplTest : public ::testing::TestWithParam<size_t> {
nullptr,
nullptr,
nullptr,
- nullptr,
base::Bind(&URLLoaderFactoryImplTest::GetContexts,
base::Unretained(this)))) {
MojoAsyncResourceHandler::SetAllocationSizeForTesting(GetParam());
@@ -108,6 +110,7 @@ class URLLoaderFactoryImplTest : public ::testing::TestWithParam<size_t> {
rdh_.SetDelegate(nullptr);
net::URLRequestFilter::GetInstance()->ClearHandlers();
+ resource_message_filter_->OnChannelClosing();
rdh_.CancelRequestsForProcess(resource_message_filter_->child_id());
base::RunLoop().RunUntilIdle();
MojoAsyncResourceHandler::SetAllocationSizeForTesting(
@@ -136,7 +139,7 @@ TEST_P(URLLoaderFactoryImplTest, GetResponse) {
constexpr int32_t kRoutingId = 81;
constexpr int32_t kRequestId = 28;
NavigationResourceThrottle::set_ui_checks_always_succeed_for_testing(true);
- mojom::URLLoaderPtr loader;
+ mojom::URLLoaderAssociatedPtr loader;
base::FilePath root;
PathService::Get(DIR_TEST_DATA, &root);
net::URLRequestMockHTTPJob::AddUrlHandlers(root,
@@ -147,9 +150,10 @@ TEST_P(URLLoaderFactoryImplTest, GetResponse) {
request.url = net::URLRequestMockHTTPJob::GetMockUrl("hello.html");
request.method = "GET";
request.is_main_frame = true;
- factory_->CreateLoaderAndStart(mojo::GetProxy(&loader), kRoutingId,
- kRequestId, request,
- client.CreateInterfacePtrAndBind());
+ factory_->CreateLoaderAndStart(
+ mojo::GetProxy(&loader, factory_.associated_group()), kRoutingId,
+ kRequestId, request,
+ client.CreateRemoteAssociatedPtrInfo(factory_.associated_group()));
ASSERT_FALSE(client.has_received_response());
ASSERT_FALSE(client.response_body().is_valid());
@@ -168,7 +172,6 @@ TEST_P(URLLoaderFactoryImplTest, GetResponse) {
EXPECT_EQ(kRequestId, request_info->GetRequestID());
ASSERT_FALSE(client.has_received_completion());
- ASSERT_FALSE(client.has_received_completion());
client.RunUntilResponseBodyArrived();
ASSERT_TRUE(client.response_body().is_valid());
@@ -204,15 +207,16 @@ TEST_P(URLLoaderFactoryImplTest, GetResponse) {
TEST_P(URLLoaderFactoryImplTest, GetFailedResponse) {
NavigationResourceThrottle::set_ui_checks_always_succeed_for_testing(true);
- mojom::URLLoaderPtr loader;
+ mojom::URLLoaderAssociatedPtr loader;
ResourceRequest request;
TestURLLoaderClient client;
net::URLRequestFailedJob::AddUrlHandler();
request.url = net::URLRequestFailedJob::GetMockHttpUrlWithFailurePhase(
net::URLRequestFailedJob::START, net::ERR_TIMED_OUT);
request.method = "GET";
- factory_->CreateLoaderAndStart(mojo::GetProxy(&loader), 2, 1, request,
- client.CreateInterfacePtrAndBind());
+ factory_->CreateLoaderAndStart(
+ mojo::GetProxy(&loader, factory_.associated_group()), 2, 1, request,
+ client.CreateRemoteAssociatedPtrInfo(factory_.associated_group()));
client.RunUntilComplete();
ASSERT_FALSE(client.has_received_response());
@@ -223,14 +227,15 @@ TEST_P(URLLoaderFactoryImplTest, GetFailedResponse) {
// This test tests a case where resource loading is cancelled before started.
TEST_P(URLLoaderFactoryImplTest, InvalidURL) {
- mojom::URLLoaderPtr loader;
+ mojom::URLLoaderAssociatedPtr loader;
ResourceRequest request;
TestURLLoaderClient client;
request.url = GURL();
request.method = "GET";
ASSERT_FALSE(request.url.is_valid());
- factory_->CreateLoaderAndStart(mojo::GetProxy(&loader), 2, 1, request,
- client.CreateInterfacePtrAndBind());
+ factory_->CreateLoaderAndStart(
+ mojo::GetProxy(&loader, factory_.associated_group()), 2, 1, request,
+ client.CreateRemoteAssociatedPtrInfo(factory_.associated_group()));
client.RunUntilComplete();
ASSERT_FALSE(client.has_received_response());
@@ -241,15 +246,16 @@ TEST_P(URLLoaderFactoryImplTest, InvalidURL) {
// This test tests a case where resource loading is cancelled before started.
TEST_P(URLLoaderFactoryImplTest, ShouldNotRequestURL) {
- mojom::URLLoaderPtr loader;
+ mojom::URLLoaderAssociatedPtr loader;
RejectingResourceDispatcherHostDelegate rdh_delegate;
rdh_.SetDelegate(&rdh_delegate);
ResourceRequest request;
TestURLLoaderClient client;
request.url = GURL("http://localhost/");
request.method = "GET";
- factory_->CreateLoaderAndStart(mojo::GetProxy(&loader), 2, 1, request,
- client.CreateInterfacePtrAndBind());
+ factory_->CreateLoaderAndStart(
+ mojo::GetProxy(&loader, factory_.associated_group()), 2, 1, request,
+ client.CreateRemoteAssociatedPtrInfo(factory_.associated_group()));
client.RunUntilComplete();
rdh_.SetDelegate(nullptr);
@@ -260,6 +266,160 @@ TEST_P(URLLoaderFactoryImplTest, ShouldNotRequestURL) {
EXPECT_EQ(net::ERR_ABORTED, client.completion_status().error_code);
}
+TEST_P(URLLoaderFactoryImplTest, DownloadToFile) {
+ constexpr int32_t kRoutingId = 1;
+ constexpr int32_t kRequestId = 2;
+
+ mojom::URLLoaderAssociatedPtr loader;
+ base::FilePath root;
+ PathService::Get(DIR_TEST_DATA, &root);
+ net::URLRequestMockHTTPJob::AddUrlHandlers(root,
+ BrowserThread::GetBlockingPool());
+
+ ResourceRequest request;
+ TestURLLoaderClient client;
+ request.url = net::URLRequestMockHTTPJob::GetMockUrl("hello.html");
+ request.method = "GET";
+ request.resource_type = RESOURCE_TYPE_XHR;
+ request.download_to_file = true;
+ request.request_initiator = url::Origin();
+ factory_->CreateLoaderAndStart(
+ mojo::GetProxy(&loader, factory_.associated_group()), kRoutingId,
+ kRequestId, request,
+ client.CreateRemoteAssociatedPtrInfo(factory_.associated_group()));
+ ASSERT_FALSE(client.has_received_response());
+ ASSERT_FALSE(client.has_data_downloaded());
+ ASSERT_FALSE(client.has_received_completion());
+
+ client.RunUntilResponseReceived();
+
+ net::URLRequest* url_request =
+ rdh_.GetURLRequest(GlobalRequestID(kChildId, kRequestId));
+ ASSERT_TRUE(url_request);
+ ResourceRequestInfoImpl* request_info =
+ ResourceRequestInfoImpl::ForRequest(url_request);
+ ASSERT_TRUE(request_info);
+ EXPECT_EQ(kChildId, request_info->GetChildID());
+ EXPECT_EQ(kRoutingId, request_info->GetRouteID());
+ EXPECT_EQ(kRequestId, request_info->GetRequestID());
+
+ ASSERT_FALSE(client.has_received_completion());
+
+ client.RunUntilComplete();
+ ASSERT_TRUE(client.has_data_downloaded());
+ ASSERT_TRUE(client.has_received_completion());
+
+ EXPECT_EQ(200, client.response_head().headers->response_code());
+ std::string content_type;
+ client.response_head().headers->GetNormalizedHeader("content-type",
+ &content_type);
+ EXPECT_EQ("text/html", content_type);
+ EXPECT_EQ(0, client.completion_status().error_code);
+
+ std::string contents;
+ base::ReadFileToString(client.response_head().download_file_path, &contents);
+
+ EXPECT_EQ(static_cast<int64_t>(contents.size()),
+ client.download_data_length());
+ EXPECT_EQ(static_cast<int64_t>(contents.size()),
+ client.encoded_download_data_length());
+
+ std::string expected;
+ base::ReadFileToString(
+ root.Append(base::FilePath(FILE_PATH_LITERAL("hello.html"))), &expected);
+ EXPECT_EQ(expected, contents);
+}
+
+TEST_P(URLLoaderFactoryImplTest, DownloadToFileFailure) {
+ constexpr int32_t kRoutingId = 1;
+ constexpr int32_t kRequestId = 2;
+
+ mojom::URLLoaderAssociatedPtr loader;
+ base::FilePath root;
+ PathService::Get(DIR_TEST_DATA, &root);
+ net::URLRequestSlowDownloadJob::AddUrlHandler();
+
+ ResourceRequest request;
+ TestURLLoaderClient client;
+ request.url = GURL(net::URLRequestSlowDownloadJob::kKnownSizeUrl);
+ request.method = "GET";
+ request.resource_type = RESOURCE_TYPE_XHR;
+ request.download_to_file = true;
+ request.request_initiator = url::Origin();
+ factory_->CreateLoaderAndStart(
+ mojo::GetProxy(&loader, factory_.associated_group()), kRoutingId,
+ kRequestId, request,
+ client.CreateRemoteAssociatedPtrInfo(factory_.associated_group()));
+ ASSERT_FALSE(client.has_received_response());
+ ASSERT_FALSE(client.has_data_downloaded());
+ ASSERT_FALSE(client.has_received_completion());
+
+ client.RunUntilResponseReceived();
+
+ net::URLRequest* url_request =
+ rdh_.GetURLRequest(GlobalRequestID(kChildId, kRequestId));
+ ASSERT_TRUE(url_request);
+ ResourceRequestInfoImpl* request_info =
+ ResourceRequestInfoImpl::ForRequest(url_request);
+ ASSERT_TRUE(request_info);
+ EXPECT_EQ(kChildId, request_info->GetChildID());
+ EXPECT_EQ(kRoutingId, request_info->GetRouteID());
+ EXPECT_EQ(kRequestId, request_info->GetRequestID());
+
+ ASSERT_FALSE(client.has_received_completion());
+
+ client.RunUntilDataDownloaded();
+ ASSERT_TRUE(client.has_data_downloaded());
+ ASSERT_FALSE(client.has_received_completion());
+ EXPECT_LT(0, client.download_data_length());
+ EXPECT_GE(
+ static_cast<int64_t>(net::URLRequestSlowDownloadJob::kFirstDownloadSize),
+ client.download_data_length());
+ EXPECT_LT(0, client.encoded_download_data_length());
+ EXPECT_GE(
+ static_cast<int64_t>(net::URLRequestSlowDownloadJob::kFirstDownloadSize),
+ client.encoded_download_data_length());
+
+ url_request->Cancel();
+ client.RunUntilComplete();
+
+ ASSERT_TRUE(client.has_received_completion());
+
+ EXPECT_EQ(200, client.response_head().headers->response_code());
+ EXPECT_EQ(net::ERR_ABORTED, client.completion_status().error_code);
+}
+
+// Removing the loader in the remote side will cancel the request.
+TEST_P(URLLoaderFactoryImplTest, CancelFromRenderer) {
+ constexpr int32_t kRoutingId = 81;
+ constexpr int32_t kRequestId = 28;
+ NavigationResourceThrottle::set_ui_checks_always_succeed_for_testing(true);
+ mojom::URLLoaderAssociatedPtr loader;
+ base::FilePath root;
+ PathService::Get(DIR_TEST_DATA, &root);
+ net::URLRequestFailedJob::AddUrlHandler();
+ ResourceRequest request;
+ TestURLLoaderClient client;
+ // Assume the file contents is small enough to be stored in the data pipe.
+ request.url = net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_IO_PENDING);
+ request.method = "GET";
+ request.is_main_frame = true;
+ factory_->CreateLoaderAndStart(
+ mojo::GetProxy(&loader, factory_.associated_group()), kRoutingId,
+ kRequestId, request,
+ client.CreateRemoteAssociatedPtrInfo(factory_.associated_group()));
+
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(rdh_.GetURLRequest(GlobalRequestID(kChildId, kRequestId)));
+ ASSERT_FALSE(client.has_received_response());
+ ASSERT_FALSE(client.response_body().is_valid());
+ ASSERT_FALSE(client.has_received_completion());
+
+ loader = nullptr;
+ base::RunLoop().RunUntilIdle();
+ ASSERT_FALSE(rdh_.GetURLRequest(GlobalRequestID(kChildId, kRequestId)));
+}
+
INSTANTIATE_TEST_CASE_P(URLLoaderFactoryImplTest,
URLLoaderFactoryImplTest,
::testing::Values(128, 32 * 1024));