blob: 81fb3763c49d0898328d6eff5dbfaf27bc2efd3c [file] [log] [blame]
// Copyright 2018 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/shared_worker/shared_worker_script_loader.h"
#include "content/browser/loader/navigation_loader_interceptor.h"
#include "content/browser/service_worker/service_worker_provider_host.h"
#include "content/public/browser/resource_context.h"
#include "net/url_request/redirect_util.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "third_party/blink/public/common/service_worker/service_worker_utils.h"
namespace content {
SharedWorkerScriptLoader::SharedWorkerScriptLoader(
int32_t routing_id,
int32_t request_id,
uint32_t options,
const network::ResourceRequest& resource_request,
network::mojom::URLLoaderClientPtr client,
base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host,
ResourceContext* resource_context,
scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
: routing_id_(routing_id),
request_id_(request_id),
options_(options),
resource_request_(resource_request),
client_(std::move(client)),
service_worker_provider_host_(service_worker_provider_host),
resource_context_(resource_context),
default_loader_factory_(std::move(default_loader_factory)),
traffic_annotation_(traffic_annotation),
url_loader_client_binding_(this),
weak_factory_(this) {
DCHECK(blink::ServiceWorkerUtils::IsServicificationEnabled());
if (service_worker_provider_host_) {
service_worker_interceptor_ =
ServiceWorkerRequestHandler::InitializeForSharedWorker(
resource_request_, service_worker_provider_host_);
}
Start();
}
SharedWorkerScriptLoader::~SharedWorkerScriptLoader() = default;
void SharedWorkerScriptLoader::Start() {
if (service_worker_interceptor_) {
service_worker_interceptor_->MaybeCreateLoader(
resource_request_, resource_context_,
base::BindOnce(&SharedWorkerScriptLoader::MaybeStartLoader,
weak_factory_.GetWeakPtr(),
service_worker_interceptor_.get()));
return;
}
LoadFromNetwork();
}
void SharedWorkerScriptLoader::MaybeStartLoader(
NavigationLoaderInterceptor* interceptor,
SingleRequestURLLoaderFactory::RequestHandler single_request_handler) {
if (single_request_handler) {
// The interceptor elected to handle the request. Use it.
network::mojom::URLLoaderClientPtr client;
url_loader_client_binding_.Bind(mojo::MakeRequest(&client));
url_loader_factory_ = base::MakeRefCounted<SingleRequestURLLoaderFactory>(
std::move(single_request_handler));
url_loader_factory_->CreateLoaderAndStart(
mojo::MakeRequest(&url_loader_), routing_id_, request_id_, options_,
resource_request_, std::move(client), traffic_annotation_);
// We continue in URLLoaderClient calls.
return;
}
LoadFromNetwork();
}
void SharedWorkerScriptLoader::LoadFromNetwork() {
network::mojom::URLLoaderClientPtr client;
url_loader_client_binding_.Bind(mojo::MakeRequest(&client));
url_loader_factory_ = default_loader_factory_;
url_loader_factory_->CreateLoaderAndStart(
mojo::MakeRequest(&url_loader_), routing_id_, request_id_, options_,
resource_request_, std::move(client), traffic_annotation_);
// We continue in URLLoaderClient calls.
}
// URLLoader -------------------------------------------------------------------
// When this class gets a FollowRedirect IPC from the renderer, it restarts with
// the new URL.
void SharedWorkerScriptLoader::FollowRedirect(
const base::Optional<std::vector<std::string>>&
to_be_removed_request_headers,
const base::Optional<net::HttpRequestHeaders>& modified_request_headers) {
DCHECK(!modified_request_headers.has_value()) << "Redirect with modified "
"headers was not supported "
"yet. crbug.com/845683";
DCHECK(redirect_info_);
// |should_clear_upload| is unused because there is no body anyway.
DCHECK(!resource_request_.request_body);
bool should_clear_upload = false;
net::RedirectUtil::UpdateHttpRequest(
resource_request_.url, resource_request_.method, *redirect_info_,
modified_request_headers, &resource_request_.headers,
&should_clear_upload);
resource_request_.url = redirect_info_->new_url;
resource_request_.method = redirect_info_->new_method;
resource_request_.site_for_cookies = redirect_info_->new_site_for_cookies;
resource_request_.referrer = GURL(redirect_info_->new_referrer);
resource_request_.referrer_policy = redirect_info_->new_referrer_policy;
// Restart the request.
url_loader_client_binding_.Unbind();
redirect_info_.reset();
Start();
}
void SharedWorkerScriptLoader::ProceedWithResponse() {
// Only for navigations.
NOTREACHED();
}
// Below we make a small effort to support the other URLLoader functions by
// forwarding to the current |url_loader_| if any, but don't bother queuing
// state or propagating state to a new URLLoader upon redirect.
void SharedWorkerScriptLoader::SetPriority(net::RequestPriority priority,
int32_t intra_priority_value) {
if (url_loader_)
url_loader_->SetPriority(priority, intra_priority_value);
}
void SharedWorkerScriptLoader::PauseReadingBodyFromNet() {
if (url_loader_)
url_loader_->PauseReadingBodyFromNet();
}
void SharedWorkerScriptLoader::ResumeReadingBodyFromNet() {
if (url_loader_)
url_loader_->ResumeReadingBodyFromNet();
}
// URLLoaderClient ----------------------------------------------------------
// This class forwards any client messages to the outer client in the renderer.
// Additionally, on redirects it saves the redirect info so if the renderer
// calls FollowRedirect(), it can do so.
void SharedWorkerScriptLoader::OnReceiveResponse(
const network::ResourceResponseHead& response_head) {
client_->OnReceiveResponse(response_head);
}
void SharedWorkerScriptLoader::OnReceiveRedirect(
const net::RedirectInfo& redirect_info,
const network::ResourceResponseHead& response_head) {
if (--redirect_limit_ == 0) {
client_->OnComplete(
network::URLLoaderCompletionStatus(net::ERR_TOO_MANY_REDIRECTS));
return;
}
redirect_info_ = redirect_info;
client_->OnReceiveRedirect(redirect_info, response_head);
}
void SharedWorkerScriptLoader::OnUploadProgress(
int64_t current_position,
int64_t total_size,
OnUploadProgressCallback ack_callback) {
client_->OnUploadProgress(current_position, total_size,
std::move(ack_callback));
}
void SharedWorkerScriptLoader::OnReceiveCachedMetadata(
const std::vector<uint8_t>& data) {
client_->OnReceiveCachedMetadata(data);
}
void SharedWorkerScriptLoader::OnTransferSizeUpdated(
int32_t transfer_size_diff) {
client_->OnTransferSizeUpdated(transfer_size_diff);
}
void SharedWorkerScriptLoader::OnStartLoadingResponseBody(
mojo::ScopedDataPipeConsumerHandle consumer) {
client_->OnStartLoadingResponseBody(std::move(consumer));
}
void SharedWorkerScriptLoader::OnComplete(
const network::URLLoaderCompletionStatus& status) {
if (status.error_code == net::OK)
service_worker_provider_host_->CompleteSharedWorkerPreparation();
client_->OnComplete(status);
}
} // namespace content