0

ServiceWorkerImportedScriptUpdateCheck uses throttles on the browser

Previously it doesn't care about the throttles, but it means the update requests
will be missed from the embedder. This CL is to use ThrottlingURLLoader in
ServiceWorkerSingleScriptUpdateChecker, and also this makes
ServiceWorkerNewScriptLoader be able to inherit the throttling loader if it's
resuming a cache writer.

Now throttles work only on the UI thread, so this CL introduces a thin wrapper to
invoke method calls on the UI thread.

After this CL lands, I'm going to add code to send the paused state to the
renderer as a resource override so that the renderer doesn't create
ThrottlingURLLoader for the request which is already using ThrottlingURLLoader
in the browser process.

Bug: 988957
Change-Id: I32e19d3cd7071dddc056ffdab2bfad36679d5b0f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1728889
Auto-Submit: Makoto Shimazu <shimazu@chromium.org>
Reviewed-by: Kinuko Yasuda <kinuko@chromium.org>
Reviewed-by: Josh Karlin <jkarlin@chromium.org>
Reviewed-by: Hiroki Nakagawa <nhiroki@chromium.org>
Commit-Queue: Makoto Shimazu <shimazu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#686419}
This commit is contained in:
Makoto Shimazu
2019-08-13 15:18:27 +00:00
committed by Commit Bot
parent 439397de58
commit f47a94c519
11 changed files with 316 additions and 74 deletions

@ -40,6 +40,7 @@
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/service_worker/service_worker_utils.h"
#include "url/gurl.h"
namespace {
@ -135,6 +136,8 @@ class VariationsHttpHeadersBrowserTest : public InProcessBrowserTest {
return it->second.find(header) != it->second.end();
}
void ClearReceivedHeaders() { received_headers_.clear(); }
bool FetchResource(const GURL& url) {
if (!url.is_valid())
return false;
@ -164,11 +167,9 @@ class VariationsHttpHeadersBrowserTest : public InProcessBrowserTest {
GURL url =
GetGoogleUrlWithPath("/service_worker/create_service_worker.html");
EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
const std::string scope = "/";
EXPECT_EQ("DONE",
EvalJs(GetWebContents(), base::StrCat({"register('", worker_path,
"', '", scope, "');"})));
EXPECT_EQ("DONE", EvalJs(GetWebContents(),
base::StringPrintf("register('%s', '/');",
worker_path.c_str())));
}
// Registers the given service worker for google.com then tests navigation and
@ -426,7 +427,7 @@ IN_PROC_BROWSER_TEST_F(VariationsHttpHeadersBrowserTest,
}
// Verify in an integration test that the variations header (X-Client-Data) is
// attached to requests for service worker scripts.
// attached to requests for service worker scripts when installing and updating.
IN_PROC_BROWSER_TEST_F(VariationsHttpHeadersBrowserTest, ServiceWorkerScript) {
// Register a service worker that imports scripts.
GURL absolute_import = GetExampleUrlWithPath("/service_worker/empty.js");
@ -445,6 +446,24 @@ IN_PROC_BROWSER_TEST_F(VariationsHttpHeadersBrowserTest, ServiceWorkerScript) {
// But not on requests not to Google.
EXPECT_FALSE(HasReceivedHeader(absolute_import, "X-Client-Data"));
// Prepare for the update case.
ClearReceivedHeaders();
// Tries to update the service worker.
EXPECT_EQ("DONE", EvalJs(GetWebContents(), "update();"));
// Test that the header is present on the main script request.
EXPECT_TRUE(
HasReceivedHeader(GetGoogleUrlWithPath(worker_path), "X-Client-Data"));
if (blink::ServiceWorkerUtils::IsImportedScriptUpdateCheckEnabled()) {
// And on import script requests to Google.
EXPECT_TRUE(HasReceivedHeader(
GetGoogleUrlWithPath("/service_worker/empty.js"), "X-Client-Data"));
// But not on requests not to Google.
EXPECT_FALSE(HasReceivedHeader(absolute_import, "X-Client-Data"));
}
}
// Verify in an integration test that the variations header (X-Client-Data) is

@ -14,12 +14,17 @@
#include "content/browser/service_worker/service_worker_consts.h"
#include "content/browser/service_worker/service_worker_loader_helpers.h"
#include "content/common/service_worker/service_worker_utils.h"
#include "content/common/throttling_url_loader.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/common/content_client.h"
#include "content/public/common/resource_type.h"
#include "mojo/public/cpp/system/simple_watcher.h"
#include "net/base/ip_endpoint.h"
#include "net/base/load_flags.h"
#include "services/network/public/cpp/net_adapters.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "third_party/blink/public/common/loader/url_loader_throttle.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom.h"
// TODO(momohatt): Add UMA to capture the result of the update checking.
@ -94,6 +99,8 @@ ServiceWorkerSingleScriptUpdateChecker::ServiceWorkerSingleScriptUpdateChecker(
blink::mojom::ServiceWorkerUpdateViaCache update_via_cache,
base::TimeDelta time_since_last_check,
const net::HttpRequestHeaders& default_headers,
ServiceWorkerUpdatedScriptLoader::BrowserContextGetter
browser_context_getter,
scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
std::unique_ptr<ServiceWorkerResponseReader> compare_reader,
std::unique_ptr<ServiceWorkerResponseReader> copy_reader,
@ -193,20 +200,20 @@ ServiceWorkerSingleScriptUpdateChecker::ServiceWorkerSingleScriptUpdateChecker(
cache_writer_ = ServiceWorkerCacheWriter::CreateForComparison(
std::move(compare_reader), std::move(copy_reader), std::move(writer),
true /* pause_when_not_identical */);
/*pause_when_not_identical=*/true);
network::mojom::URLLoaderClientPtr network_client;
network::mojom::URLLoaderClientPtrInfo network_client;
network_client_binding_.Bind(mojo::MakeRequest(&network_client));
// Use NavigationURLLoaderImpl to get a unique request id across
// browser-initiated navigations and worker script fetch.
const int request_id =
NavigationURLLoaderImpl::MakeGlobalRequestID().request_id;
loader_factory->CreateLoaderAndStart(
mojo::MakeRequest(&network_loader_), MSG_ROUTING_NONE, request_id,
network::mojom::kURLLoadOptionNone, resource_request,
std::move(network_client),
net::MutableNetworkTrafficAnnotationTag(kUpdateCheckTrafficAnnotation));
network_loader_ = ServiceWorkerUpdatedScriptLoader::
ThrottlingURLLoaderIOWrapper::CreateLoaderAndStart(
loader_factory->Clone(), browser_context_getter, MSG_ROUTING_NONE,
request_id, network::mojom::kURLLoadOptionNone, resource_request,
std::move(network_client), kUpdateCheckTrafficAnnotation);
DCHECK_EQ(network_loader_state_,
ServiceWorkerUpdatedScriptLoader::LoaderState::kNotStarted);
network_loader_state_ =
@ -577,7 +584,9 @@ void ServiceWorkerSingleScriptUpdateChecker::Finish(
ServiceWorkerSingleScriptUpdateChecker::PausedState::PausedState(
std::unique_ptr<ServiceWorkerCacheWriter> cache_writer,
network::mojom::URLLoaderPtr network_loader,
std::unique_ptr<
ServiceWorkerUpdatedScriptLoader::ThrottlingURLLoaderIOWrapper>
network_loader,
network::mojom::URLLoaderClientRequest network_client_request,
mojo::ScopedDataPipeConsumerHandle network_consumer,
ServiceWorkerUpdatedScriptLoader::LoaderState network_loader_state,

@ -58,7 +58,9 @@ class CONTENT_EXPORT ServiceWorkerSingleScriptUpdateChecker
struct CONTENT_EXPORT PausedState {
PausedState(
std::unique_ptr<ServiceWorkerCacheWriter> cache_writer,
network::mojom::URLLoaderPtr network_loader,
std::unique_ptr<
ServiceWorkerUpdatedScriptLoader::ThrottlingURLLoaderIOWrapper>
network_loader,
network::mojom::URLLoaderClientRequest network_client_request,
mojo::ScopedDataPipeConsumerHandle network_consumer,
ServiceWorkerUpdatedScriptLoader::LoaderState network_loader_state,
@ -68,7 +70,9 @@ class CONTENT_EXPORT ServiceWorkerSingleScriptUpdateChecker
~PausedState();
std::unique_ptr<ServiceWorkerCacheWriter> cache_writer;
network::mojom::URLLoaderPtr network_loader;
std::unique_ptr<
ServiceWorkerUpdatedScriptLoader::ThrottlingURLLoaderIOWrapper>
network_loader;
network::mojom::URLLoaderClientRequest network_client_request;
mojo::ScopedDataPipeConsumerHandle network_consumer;
ServiceWorkerUpdatedScriptLoader::LoaderState network_loader_state;
@ -100,6 +104,8 @@ class CONTENT_EXPORT ServiceWorkerSingleScriptUpdateChecker
blink::mojom::ServiceWorkerUpdateViaCache update_via_cache,
base::TimeDelta time_since_last_check,
const net::HttpRequestHeaders& default_headers,
ServiceWorkerUpdatedScriptLoader::BrowserContextGetter
browser_context_getter,
scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
std::unique_ptr<ServiceWorkerResponseReader> compare_reader,
std::unique_ptr<ServiceWorkerResponseReader> copy_reader,
@ -159,7 +165,9 @@ class CONTENT_EXPORT ServiceWorkerSingleScriptUpdateChecker
const base::TimeDelta time_since_last_check_;
bool network_accessed_ = false;
network::mojom::URLLoaderPtr network_loader_;
std::unique_ptr<
ServiceWorkerUpdatedScriptLoader::ThrottlingURLLoaderIOWrapper>
network_loader_;
mojo::Binding<network::mojom::URLLoaderClient> network_client_binding_;
mojo::ScopedDataPipeConsumerHandle network_consumer_;
mojo::SimpleWatcher network_watcher_;

@ -13,6 +13,7 @@
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_storage.h"
#include "content/browser/service_worker/service_worker_test_utils.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/base/load_flags.h"
#include "net/http/http_util.h"
@ -60,7 +61,11 @@ class ServiceWorkerSingleScriptUpdateCheckerTest : public testing::Test {
};
ServiceWorkerSingleScriptUpdateCheckerTest()
: thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
: thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
browser_context_(std::make_unique<TestBrowserContext>()) {
BrowserContext::EnsureResourceContextInitialized(browser_context_.get());
base::RunLoop().RunUntilIdle();
}
~ServiceWorkerSingleScriptUpdateCheckerTest() override = default;
ServiceWorkerStorage* storage() { return helper_->context()->storage(); }
@ -115,6 +120,8 @@ class ServiceWorkerSingleScriptUpdateCheckerTest : public testing::Test {
GURL(url), url == main_script_url, GURL(main_script_url), scope,
force_bypass_cache, update_via_cache, time_since_last_check,
net::HttpRequestHeaders(),
base::BindRepeating([](BrowserContext* context) { return context; },
browser_context_.get()),
helper_->context()->GetLoaderFactoryBundleForUpdateCheck(),
std::move(compare_reader), std::move(copy_reader), std::move(writer),
base::BindOnce(
@ -154,6 +161,7 @@ class ServiceWorkerSingleScriptUpdateCheckerTest : public testing::Test {
TestBrowserThreadBundle thread_bundle_;
std::unique_ptr<EmbeddedWorkerTestHelper> helper_;
base::test::ScopedFeatureList feature_list_;
std::unique_ptr<TestBrowserContext> browser_context_;
private:
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerSingleScriptUpdateCheckerTest);

@ -22,6 +22,7 @@
#include "content/common/frame.mojom.h"
#include "content/common/frame_messages.h"
#include "content/common/frame_messages.mojom.h"
#include "content/common/throttling_url_loader.h"
#include "content/public/common/child_process_host.h"
#include "content/public/common/transferrable_url_loader.mojom.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
@ -624,13 +625,11 @@ ServiceWorkerUpdateCheckTestUtils::CreateUpdateCheckerPausedState(
ServiceWorkerUpdatedScriptLoader::LoaderState network_loader_state,
ServiceWorkerUpdatedScriptLoader::WriterState body_writer_state,
mojo::ScopedDataPipeConsumerHandle network_consumer) {
network::mojom::URLLoaderPtr network_loader;
network::mojom::URLLoaderClientPtr network_loader_client;
mojo::MakeRequest(&network_loader);
network::mojom::URLLoaderClientRequest network_loader_client_request =
mojo::MakeRequest(&network_loader_client);
return std::make_unique<ServiceWorkerSingleScriptUpdateChecker::PausedState>(
std::move(cache_writer), std::move(network_loader),
std::move(cache_writer), /*network_loader=*/nullptr,
std::move(network_loader_client_request), std::move(network_consumer),
network_loader_state, body_writer_state);
}

@ -26,13 +26,17 @@ namespace content {
namespace {
base::Optional<net::HttpRequestHeaders> GetDefaultHeadersOnUI(
base::WeakPtr<ServiceWorkerProcessManager> process_manager) {
void SetUpOnUI(
base::WeakPtr<ServiceWorkerProcessManager> process_manager,
base::OnceCallback<void(
net::HttpRequestHeaders,
ServiceWorkerUpdatedScriptLoader::BrowserContextGetter)> callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!process_manager) {
// If no process manager is found, maybe it's being shut down.
// ServiceWorkerUpdateChecker is destroyed after posting this task.
return base::nullopt;
// ServiceWorkerUpdateChecker is going to be destroyed after this task, so
// just do nothing here.
return;
}
net::HttpRequestHeaders headers;
@ -49,7 +53,20 @@ base::Optional<net::HttpRequestHeaders> GetDefaultHeadersOnUI(
&headers, browser_context, /*should_update_existing_headers=*/false,
renderer_preferences);
return headers;
ServiceWorkerUpdatedScriptLoader::BrowserContextGetter
browser_context_getter = base::BindRepeating(
[](base::WeakPtr<ServiceWorkerProcessManager> process_manager)
-> BrowserContext* {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (process_manager)
return process_manager->browser_context();
return nullptr;
},
process_manager);
base::PostTask(FROM_HERE, {BrowserThread::IO},
base::BindOnce(std::move(callback), std::move(headers),
browser_context_getter));
}
} // namespace
@ -80,25 +97,19 @@ void ServiceWorkerUpdateChecker::Start(UpdateStatusCallback callback) {
DCHECK(!scripts_to_compare_.empty());
callback_ = std::move(callback);
// TODO(shimazu): Add UMA to capture the number of update.
base::PostTaskAndReplyWithResult(
base::PostTask(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(&GetDefaultHeadersOnUI,
context_->process_manager()->AsWeakPtr()),
base::BindOnce(&ServiceWorkerUpdateChecker::OnGetDefaultHeaders,
weak_factory_.GetWeakPtr()));
base::BindOnce(&SetUpOnUI, context_->process_manager()->AsWeakPtr(),
base::BindOnce(&ServiceWorkerUpdateChecker::DidSetUpOnUI,
weak_factory_.GetWeakPtr())));
}
void ServiceWorkerUpdateChecker::OnGetDefaultHeaders(
base::Optional<net::HttpRequestHeaders> header) {
// |header| is always valid because it could be base::nullopt when the process
// manager is destroyed, but it means that the ServiceWorkerContextCore is
// also destroyed. In that case, ServiceWorkerUpdateChecker is destroyed
// because it's owned by ServiceWorkerContextCore through
// ServiceWorkerJobCoordinator and ServiceWorkerRegisterJob.
DCHECK(header);
default_headers_ = std::move(header.value());
void ServiceWorkerUpdateChecker::DidSetUpOnUI(
net::HttpRequestHeaders header,
ServiceWorkerUpdatedScriptLoader::BrowserContextGetter
browser_context_getter) {
default_headers_ = std::move(header);
browser_context_getter_ = std::move(browser_context_getter);
CheckOneScript(main_script_url_, main_script_resource_id_);
}
@ -198,8 +209,8 @@ void ServiceWorkerUpdateChecker::CheckOneScript(const GURL& url,
running_checker_ = std::make_unique<ServiceWorkerSingleScriptUpdateChecker>(
url, is_main_script, main_script_url_, version_to_update_->scope(),
force_bypass_cache_, update_via_cache_, time_since_last_check_,
default_headers_, loader_factory_, std::move(compare_reader),
std::move(copy_reader), std::move(writer),
default_headers_, browser_context_getter_, loader_factory_,
std::move(compare_reader), std::move(copy_reader), std::move(writer),
base::BindOnce(&ServiceWorkerUpdateChecker::OnOneUpdateCheckFinished,
weak_factory_.GetWeakPtr(), resource_id));
}

@ -8,6 +8,7 @@
#include "base/callback.h"
#include "content/browser/service_worker/service_worker_database.h"
#include "content/browser/service_worker/service_worker_single_script_update_checker.h"
#include "content/browser/service_worker/service_worker_updated_script_loader.h"
namespace network {
class SharedURLLoaderFactory;
@ -106,7 +107,9 @@ class CONTENT_EXPORT ServiceWorkerUpdateChecker {
private:
void CheckOneScript(const GURL& url, const int64_t resource_id);
void OnGetDefaultHeaders(base::Optional<net::HttpRequestHeaders> header);
void DidSetUpOnUI(net::HttpRequestHeaders header,
ServiceWorkerUpdatedScriptLoader::BrowserContextGetter
browser_context_getter);
std::vector<ServiceWorkerDatabase::ResourceRecord> scripts_to_compare_;
size_t next_script_index_to_compare_ = 0;
@ -130,6 +133,9 @@ class CONTENT_EXPORT ServiceWorkerUpdateChecker {
// Headers that need to be added to network requests for update checking.
net::HttpRequestHeaders default_headers_;
ServiceWorkerUpdatedScriptLoader::BrowserContextGetter
browser_context_getter_;
// True if any at least one of the scripts is fetched by network.
bool network_accessed_ = false;

@ -20,6 +20,7 @@
#include "content/browser/service_worker/service_worker_version.h"
#include "content/browser/url_loader_factory_getter.h"
#include "content/common/service_worker/service_worker_utils.h"
#include "content/common/throttling_url_loader.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/content_browser_client.h"
#include "net/base/ip_endpoint.h"
@ -34,6 +35,116 @@ namespace content {
// We chose this size because the AppCache uses this.
const uint32_t ServiceWorkerUpdatedScriptLoader::kReadBufferSize = 32768;
ServiceWorkerUpdatedScriptLoader::ThrottlingURLLoaderIOWrapper::LoaderOnUI::
LoaderOnUI() = default;
ServiceWorkerUpdatedScriptLoader::ThrottlingURLLoaderIOWrapper::LoaderOnUI::
~LoaderOnUI() = default;
ServiceWorkerUpdatedScriptLoader::ThrottlingURLLoaderIOWrapper::
ThrottlingURLLoaderIOWrapper()
: loader_on_ui_(new LoaderOnUI()) {}
ServiceWorkerUpdatedScriptLoader::ThrottlingURLLoaderIOWrapper::
~ThrottlingURLLoaderIOWrapper() = default;
// static
std::unique_ptr<ServiceWorkerUpdatedScriptLoader::ThrottlingURLLoaderIOWrapper>
ServiceWorkerUpdatedScriptLoader::ThrottlingURLLoaderIOWrapper::
CreateLoaderAndStart(
std::unique_ptr<network::SharedURLLoaderFactoryInfo>
loader_factory_info,
BrowserContextGetter browser_context_getter,
int32_t routing_id,
int32_t request_id,
uint32_t options,
const network::ResourceRequest& resource_request,
network::mojom::URLLoaderClientPtrInfo client,
const net::NetworkTrafficAnnotationTag& traffic_annotation) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
auto wrapper = base::WrapUnique(new ThrottlingURLLoaderIOWrapper());
base::PostTask(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(&ThrottlingURLLoaderIOWrapper::StartInternalOnUI,
std::move(loader_factory_info),
std::move(browser_context_getter), routing_id, request_id,
options, network::ResourceRequest(resource_request),
std::move(client),
net::NetworkTrafficAnnotationTag(traffic_annotation),
base::Unretained(wrapper->loader_on_ui_.get())));
return wrapper;
}
// static
void ServiceWorkerUpdatedScriptLoader::ThrottlingURLLoaderIOWrapper::
StartInternalOnUI(std::unique_ptr<network::SharedURLLoaderFactoryInfo>
loader_factory_info,
BrowserContextGetter browser_context_getter,
int32_t routing_id,
int32_t request_id,
uint32_t options,
network::ResourceRequest resource_request,
network::mojom::URLLoaderClientPtrInfo client_info,
net::NetworkTrafficAnnotationTag traffic_annotation,
LoaderOnUI* loader_on_ui) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
BrowserContext* browser_context = browser_context_getter.Run();
if (!browser_context)
return;
// Service worker update checking doesn't have a relevant frame and tab, so
// that |wc_getter| returns nullptr and the frame id is set to
// kNoFrameTreeNodeId.
base::RepeatingCallback<WebContents*()> wc_getter =
base::BindRepeating([]() -> WebContents* { return nullptr; });
std::vector<std::unique_ptr<blink::URLLoaderThrottle>> throttles =
GetContentClient()->browser()->CreateURLLoaderThrottles(
resource_request, browser_context, std::move(wc_getter),
/*navigation_ui_data=*/nullptr, RenderFrameHost::kNoFrameTreeNodeId);
network::mojom::URLLoaderClientPtr client(std::move(client_info));
auto loader = ThrottlingURLLoader::CreateLoaderAndStart(
network::SharedURLLoaderFactory::Create(std::move(loader_factory_info)),
std::move(throttles), routing_id, request_id, options, &resource_request,
client.get(), traffic_annotation, base::ThreadTaskRunnerHandle::Get());
loader_on_ui->loader = std::move(loader);
loader_on_ui->client = std::move(client);
}
void ServiceWorkerUpdatedScriptLoader::ThrottlingURLLoaderIOWrapper::
SetPriority(net::RequestPriority priority, int32_t intra_priority_value) {
base::PostTask(FROM_HERE, {BrowserThread::UI},
base::BindOnce(
[](LoaderOnUI* loader_on_ui, net::RequestPriority priority,
int32_t intra_priority_value) {
DCHECK(loader_on_ui->loader);
loader_on_ui->loader->SetPriority(priority,
intra_priority_value);
},
base::Unretained(loader_on_ui_.get()), priority,
intra_priority_value));
}
void ServiceWorkerUpdatedScriptLoader::ThrottlingURLLoaderIOWrapper::
PauseReadingBodyFromNet() {
base::PostTask(FROM_HERE, {BrowserThread::UI},
base::BindOnce(
[](LoaderOnUI* loader_on_ui) {
DCHECK(loader_on_ui->loader);
loader_on_ui->loader->PauseReadingBodyFromNet();
},
base::Unretained(loader_on_ui_.get())));
}
void ServiceWorkerUpdatedScriptLoader::ThrottlingURLLoaderIOWrapper::
ResumeReadingBodyFromNet() {
base::PostTask(FROM_HERE, {BrowserThread::UI},
base::BindOnce(
[](LoaderOnUI* loader_on_ui) {
DCHECK(loader_on_ui->loader);
loader_on_ui->loader->ResumeReadingBodyFromNet();
},
base::Unretained(loader_on_ui_.get())));
}
// This is for debugging https://crbug.com/959627.
// The purpose is to see where the IOBuffer comes from by checking |__vfptr|.
class ServiceWorkerUpdatedScriptLoader::WrappedIOBuffer

@ -20,7 +20,9 @@
namespace content {
class BrowserContext;
class ServiceWorkerVersion;
class ThrottlingURLLoader;
struct HttpResponseInfoIOBuffer;
// Used only for ServiceWorkerImportedScriptUpdateCheck.
@ -49,7 +51,7 @@ struct HttpResponseInfoIOBuffer;
// scheme, e.g., a chrome-extension:// URL. Regardless, that is still called a
// "network" request in comments and naming. "network" is meant to distinguish
// from the load this URLLoader does for its client:
// "network" <------> SWResumeScriptLoader <------> client
// "network" <------> SWUpdatedScriptLoader <------> client
class CONTENT_EXPORT ServiceWorkerUpdatedScriptLoader final
: public network::mojom::URLLoader,
public network::mojom::URLLoaderClient,
@ -65,6 +67,62 @@ class CONTENT_EXPORT ServiceWorkerUpdatedScriptLoader final
enum class WriterState { kNotStarted, kWriting, kCompleted };
using BrowserContextGetter = base::RepeatingCallback<BrowserContext*(void)>;
// A wrapper to use ThrottlingURLLoader on the IO thread.
// TODO(crbug.com/824858): Remove this once this loader is moved to UI thread.
class ThrottlingURLLoaderIOWrapper {
public:
// Creates a ThrottlingURLLoader and starts the request.
// Called on the IO thread.
static std::unique_ptr<ThrottlingURLLoaderIOWrapper> CreateLoaderAndStart(
std::unique_ptr<network::SharedURLLoaderFactoryInfo>
loader_factory_info,
BrowserContextGetter browser_context_getter,
int32_t routing_id,
int32_t request_id,
uint32_t options,
const network::ResourceRequest& resource_request,
network::mojom::URLLoaderClientPtrInfo client,
const net::NetworkTrafficAnnotationTag& traffic_annotation);
// Called on the IO thread.
void SetPriority(net::RequestPriority priority,
int32_t intra_priority_value);
void PauseReadingBodyFromNet();
void ResumeReadingBodyFromNet();
~ThrottlingURLLoaderIOWrapper();
private:
ThrottlingURLLoaderIOWrapper();
// The real loader to be used in ThrottlingURLLoaderIOWrapper.
// Created and deleted on the UI thread via BrowserThread::DeleteOnUIThread
// to ensure the order of posted tasks and destruction of this instance.
struct LoaderOnUI {
LoaderOnUI();
~LoaderOnUI();
std::unique_ptr<ThrottlingURLLoader> loader;
network::mojom::URLLoaderClientPtr client;
};
static void StartInternalOnUI(
std::unique_ptr<network::SharedURLLoaderFactoryInfo>
loader_factory_info,
BrowserContextGetter browser_context_getter,
int32_t routing_id,
int32_t request_id,
uint32_t options,
network::ResourceRequest resource_request,
network::mojom::URLLoaderClientPtrInfo client,
net::NetworkTrafficAnnotationTag traffic_annotation,
LoaderOnUI* loader_on_ui);
std::unique_ptr<LoaderOnUI, BrowserThread::DeleteOnUIThread> loader_on_ui_;
};
// Creates a loader to continue downloading of a script paused during update
// check.
static std::unique_ptr<ServiceWorkerUpdatedScriptLoader> CreateAndStart(
@ -165,7 +223,7 @@ class CONTENT_EXPORT ServiceWorkerUpdatedScriptLoader final
// Used for fetching the script from network (or other loaders like extensions
// sometimes).
network::mojom::URLLoaderPtr network_loader_;
std::unique_ptr<ThrottlingURLLoaderIOWrapper> network_loader_;
mojo::Binding<network::mojom::URLLoaderClient> network_client_binding_;
mojo::ScopedDataPipeConsumerHandle network_consumer_;

@ -228,31 +228,6 @@ ThrottlingURLLoader::~ThrottlingURLLoader() {
}
}
void ThrottlingURLLoader::FollowRedirect(
const std::vector<std::string>& removed_headers,
const net::HttpRequestHeaders& modified_headers) {
MergeRemovedHeaders(&removed_headers_, removed_headers);
modified_headers_.MergeFrom(modified_headers);
if (!throttle_will_start_redirect_url_.is_empty()) {
throttle_will_start_redirect_url_ = GURL();
// This is a synthesized redirect, so no need to tell the URLLoader.
StartNow();
return;
}
if (url_loader_) {
base::Optional<GURL> new_url;
if (!throttle_will_redirect_redirect_url_.is_empty())
new_url = throttle_will_redirect_redirect_url_;
url_loader_->FollowRedirect(removed_headers_, modified_headers_, new_url);
throttle_will_redirect_redirect_url_ = GURL();
}
removed_headers_.clear();
modified_headers_.Clear();
}
void ThrottlingURLLoader::FollowRedirectForcingRestart() {
url_loader_.reset();
client_binding_.Close();
@ -280,6 +255,31 @@ void ThrottlingURLLoader::RestartWithFactory(
StartNow();
}
void ThrottlingURLLoader::FollowRedirect(
const std::vector<std::string>& removed_headers,
const net::HttpRequestHeaders& modified_headers) {
MergeRemovedHeaders(&removed_headers_, removed_headers);
modified_headers_.MergeFrom(modified_headers);
if (!throttle_will_start_redirect_url_.is_empty()) {
throttle_will_start_redirect_url_ = GURL();
// This is a synthesized redirect, so no need to tell the URLLoader.
StartNow();
return;
}
if (url_loader_) {
base::Optional<GURL> new_url;
if (!throttle_will_redirect_redirect_url_.is_empty())
new_url = throttle_will_redirect_redirect_url_;
url_loader_->FollowRedirect(removed_headers_, modified_headers_, new_url);
throttle_will_redirect_redirect_url_ = GURL();
}
removed_headers_.clear();
modified_headers_.Clear();
}
void ThrottlingURLLoader::SetPriority(net::RequestPriority priority,
int32_t intra_priority_value) {
if (!url_loader_) {
@ -300,6 +300,14 @@ void ThrottlingURLLoader::SetPriority(net::RequestPriority priority,
url_loader_->SetPriority(priority, intra_priority_value);
}
void ThrottlingURLLoader::PauseReadingBodyFromNet() {
PauseReadingBodyFromNet(/*throttle=*/nullptr);
}
void ThrottlingURLLoader::ResumeReadingBodyFromNet() {
ResumeReadingBodyFromNet(/*throttle=*/nullptr);
}
network::mojom::URLLoaderClientEndpointsPtr ThrottlingURLLoader::Unbind() {
return network::mojom::URLLoaderClientEndpoints::New(
url_loader_.PassInterface(), client_binding_.Unbind());

@ -49,12 +49,15 @@ class CONTENT_EXPORT ThrottlingURLLoader
~ThrottlingURLLoader() override;
void FollowRedirect(const std::vector<std::string>& removed_headers,
const net::HttpRequestHeaders& modified_headers);
// Follows a redirect, calling CreateLoaderAndStart() on the factory. This
// is useful if the factory uses different loaders for different URLs.
void FollowRedirectForcingRestart();
void FollowRedirect(const std::vector<std::string>& removed_headers,
const net::HttpRequestHeaders& modified_headers);
void SetPriority(net::RequestPriority priority, int32_t intra_priority_value);
void PauseReadingBodyFromNet();
void ResumeReadingBodyFromNet();
// Restarts the load immediately with |factory| and |url_loader_options|.
// It must only be called when the following conditions are met:
@ -179,6 +182,8 @@ class CONTENT_EXPORT ThrottlingURLLoader
std::vector<ThrottleEntry> throttles_;
std::set<blink::URLLoaderThrottle*> deferring_throttles_;
// nullptr is used when this loader is directly requested to pause reading
// body from net by calling PauseReadingBodyFromNet().
std::set<blink::URLLoaderThrottle*> pausing_reading_body_from_net_throttles_;
// NOTE: This may point to a native implementation (instead of a Mojo proxy