[go: nahoru, domu]

blob: bab4004c90ec851aaab5d7a8373c9dfe8497a593 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_SUBRESOURCE_LOADER_H_
#define CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_SUBRESOURCE_LOADER_H_
#include <optional>
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "base/task/sequenced_task_runner.h"
#include "content/common/content_export.h"
#include "content/common/service_worker/forwarded_race_network_request_url_loader_factory.h"
#include "content/common/service_worker/race_network_request_url_loader_client.h"
#include "content/common/service_worker/service_worker_resource_loader.h"
#include "content/common/service_worker/service_worker_router_evaluator.h"
#include "content/renderer/service_worker/controller_service_worker_connector.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/redirect_info.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom-forward.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
#include "third_party/blink/public/mojom/blob/blob.mojom-forward.h"
#include "third_party/blink/public/mojom/blob/blob.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom-forward.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_fetch_response_callback.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_stream_handle.mojom-forward.h"
namespace network {
class SharedURLLoaderFactory;
} // namespace network
namespace content {
class ControllerServiceWorkerConnector;
class ServiceWorkerSubresourceLoaderFactory;
// A custom URLLoader implementation used by Service Worker controllees
// for loading subresources via the controller Service Worker.
// Currently an instance of this class is created and used only on
// the main thread (while the implementation itself is thread agnostic).
class CONTENT_EXPORT ServiceWorkerSubresourceLoader
: public network::mojom::URLLoader,
public blink::mojom::ServiceWorkerFetchResponseCallback,
public ControllerServiceWorkerConnector::Observer,
public ServiceWorkerResourceLoader {
public:
// See the comments for ServiceWorkerSubresourceLoaderFactory's ctor (below)
// to see how each parameter is used.
ServiceWorkerSubresourceLoader(
mojo::PendingReceiver<network::mojom::URLLoader>,
int32_t request_id,
uint32_t options,
const network::ResourceRequest& resource_request,
mojo::PendingRemote<network::mojom::URLLoaderClient> client,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
scoped_refptr<ControllerServiceWorkerConnector> controller_connector,
scoped_refptr<network::SharedURLLoaderFactory> fallback_factory,
scoped_refptr<base::SequencedTaskRunner> task_runner,
base::WeakPtr<ServiceWorkerSubresourceLoaderFactory>
service_worker_subresource_loader_factory);
ServiceWorkerSubresourceLoader(const ServiceWorkerSubresourceLoader&) =
delete;
ServiceWorkerSubresourceLoader& operator=(
const ServiceWorkerSubresourceLoader&) = delete;
~ServiceWorkerSubresourceLoader() override;
// ControllerServiceWorkerConnector::Observer overrides:
void OnConnectionClosed() override;
private:
class StreamWaiter;
enum class Status {
kNotStarted,
// |binding_| is bound and the fetch event is being dispatched to the
// service worker.
kStarted,
// A redirect happened, waiting for FollowRedirect().
kSentRedirect,
// The response head has been sent to |url_loader_client_|.
kSentHeader,
// The data pipe for the response body has been sent to
// |url_loader_client_|. The body is being written to the pipe.
kSentBody,
// OnComplete() was called on |url_loader_client_|, or fallback to network
// occurred so the request was not handled.
kCompleted,
};
void OnMojoDisconnect();
void StartRequest(const network::ResourceRequest& resource_request);
void DispatchFetchEvent();
void DispatchFetchEventForSubresource();
void OnFetchEventFinished(blink::mojom::ServiceWorkerEventStatus status);
// Called when this loader no longer needs to restart dispatching the fetch
// event on failure. Null |status| means the event dispatch was not attempted.
void SettleFetchEventDispatch(
std::optional<blink::ServiceWorkerStatusCode> status);
// blink::mojom::ServiceWorkerFetchResponseCallback overrides:
void OnResponse(
blink::mojom::FetchAPIResponsePtr response,
blink::mojom::ServiceWorkerFetchEventTimingPtr timing) override;
void OnResponseStream(
blink::mojom::FetchAPIResponsePtr response,
blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
blink::mojom::ServiceWorkerFetchEventTimingPtr timing) override;
void OnFallback(
std::optional<network::DataElementChunkedDataPipe> request_body,
blink::mojom::ServiceWorkerFetchEventTimingPtr timing) override;
void UpdateResponseTiming(
blink::mojom::ServiceWorkerFetchEventTimingPtr timing);
void StartResponse(blink::mojom::FetchAPIResponsePtr response,
blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream);
// network::mojom::URLLoader overrides:
void FollowRedirect(
const std::vector<std::string>& removed_headers,
const net::HttpRequestHeaders& modified_headers,
const net::HttpRequestHeaders& modified_cors_exempt_headers,
const std::optional<GURL>& new_url) override;
void SetPriority(net::RequestPriority priority,
int intra_priority_value) override;
void PauseReadingBodyFromNet() override;
void ResumeReadingBodyFromNet() override;
int StartBlobReading(mojo::ScopedDataPipeConsumerHandle* body_pipe);
void OnSideDataReadingComplete(mojo::ScopedDataPipeConsumerHandle data_pipe,
std::optional<mojo_base::BigBuffer> metadata);
void OnBodyReadingComplete(int net_error);
// ServiceWorkerResourceLoader overrides:
void CommitResponseHeaders(
const network::mojom::URLResponseHeadPtr&) override;
// Calls url_loader_client_->OnReceiveResponse() with given |response_head|,
// |response_body|, and |cached_metadata|.
void CommitResponseBody(
const network::mojom::URLResponseHeadPtr& response_head,
mojo::ScopedDataPipeConsumerHandle response_body,
std::optional<mojo_base::BigBuffer> cached_metadata) override;
// Creates and sends an empty response's body with the net::OK status.
// Sends net::ERR_INSUFFICIENT_RESOURCES when it can't be created.
void CommitEmptyResponseAndComplete() override;
// Calls url_loader_client_->OnComplete(). Expected to be called after
// CommitResponseHeaders (i.e. status_ == kSentHeader).
void CommitCompleted(int error_code, const char* reason) override;
// Calls url_loader_client_->OnReceiveRedirect(). Sends too many redirects
// error if it hits the redirect limit.
void HandleRedirect(
const net::RedirectInfo& redirect_info,
const network::mojom::URLResponseHeadPtr& response_head) override;
bool IsMainResourceLoader() override;
// Record loading milestones. Called after a response is completed or
// a request is fall back to network. Never called when an error is
// occurred.
bool InitRecordTimingMetricsIfEligible(
const net::LoadTimingInfo& load_timing);
// Called when the fetch handler handles the request.
void RecordTimingMetricsForFetchHandlerHandledCase();
// Called when the fetch handler doesn't handle the requset (i.e. network
// fallback case).
void RecordTimingMetricsForNetworkFallbackCase();
// Called when the response from RaceNetworkRequest is faster than the
// response from the fetch handler.
void RecordTimingMetricsForRaceNetworkReqestCase();
// Time between the request is made and the request is routed to this loader.
void RecordStartToForwardServiceWorkerTiming(
const net::LoadTimingInfo& load_timing);
// Mojo message delay. If the controller service worker lives in the same
// process this captures service worker thread -> background thread delay.
// Otherwise, this captures IPC delay (this renderer process -> other
// renderer process).
void RecordFetchHandlerEndToResponseReceivedTiming(
const net::LoadTimingInfo& load_timing);
// Time spent reading response body.
void RecordResponseReceivedToCompletedTiming(
const net::LoadTimingInfo& load_timing);
// Time spent for service worker startup including mojo message delay.
void RecordForwardServiceWorkerToWorkerReadyTiming(
const net::LoadTimingInfo& load_timing);
// Time spent by fetch handlers.
void RecordWorkerReadyToFetchHandlerEndTiming(
const net::LoadTimingInfo& load_timing);
// Renderer -> Browser IPC delay (network fallback case).
void RecordFetchHandlerEndToFallbackNetworkTiming(
const net::LoadTimingInfo& load_timing);
// Time between the request is made and complete reading response body.
void RecordStartToCompletedTiming(const net::LoadTimingInfo& load_timing);
base::TimeTicks completion_time_;
void TransitionToStatus(Status new_status);
// If eligible, dispatch the network request which races the ServiceWorker
// fetch handler.
bool MaybeStartRaceNetworkRequest();
// Returns false if fails to start race network request.
// A caller should handle the case.
bool StartRaceNetworkRequest();
std::optional<ServiceWorkerRouterEvaluator::Result>
MaybeEvaluateRouterConditions() const;
bool MaybeStartAutoPreload();
void DidCacheStorageMatch(base::TimeTicks event_dispatch_time,
blink::mojom::MatchResultPtr result);
network::mojom::URLResponseHeadPtr response_head_;
std::optional<net::RedirectInfo> redirect_info_;
int redirect_limit_;
mojo::Remote<network::mojom::URLLoaderClient> url_loader_client_;
mojo::Receiver<network::mojom::URLLoader> url_loader_receiver_;
// For handling FetchEvent response.
mojo::Receiver<blink::mojom::ServiceWorkerFetchResponseCallback>
response_callback_receiver_{this};
// The blob needs to be held while it's read to keep it alive.
mojo::Remote<blink::mojom::Blob> body_as_blob_;
uint64_t body_as_blob_size_;
// The blob needs to be held while it's read to keep it alive.
mojo::Remote<blink::mojom::Blob> side_data_as_blob_;
scoped_refptr<ControllerServiceWorkerConnector> controller_connector_;
// Observes |controller_connector_| while this loader dispatches a fetch event
// to the controller. If a broken connection is observed, this loader attempts
// to restart the controller and dispatch the event again.
base::ScopedObservation<ControllerServiceWorkerConnector,
ControllerServiceWorkerConnector::Observer>
controller_connector_observation_{this};
bool fetch_request_restarted_;
bool body_reading_complete_;
bool side_data_reading_complete_;
// These are given by the constructor (as the params for
// URLLoaderFactory::CreateLoaderAndStart).
const int request_id_;
const uint32_t options_;
net::MutableNetworkTrafficAnnotationTag traffic_annotation_;
// |resource_request_| is initialized in the constructor, and may change
// over the lifetime of this loader due to redirects.
network::ResourceRequest resource_request_;
std::unique_ptr<StreamWaiter> stream_waiter_;
// For network fallback.
scoped_refptr<network::SharedURLLoaderFactory> fallback_factory_;
Status status_ = Status::kNotStarted;
// The task runner where this loader is running.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
base::WeakPtr<ServiceWorkerSubresourceLoaderFactory>
service_worker_subresource_loader_factory_;
blink::mojom::ServiceWorkerFetchEventTimingPtr fetch_event_timing_;
network::mojom::FetchResponseSource response_source_;
scoped_refptr<network::SharedURLLoaderFactory>
race_network_request_url_loader_factory_;
std::optional<ServiceWorkerRaceNetworkRequestURLLoaderClient>
race_network_request_loader_client_;
std::optional<ServiceWorkerForwardedRaceNetworkRequestURLLoaderFactory>
forwarded_race_network_request_url_loader_factory_;
mojo::PendingRemote<network::mojom::URLLoaderFactory>
remote_forwarded_race_network_request_url_loader_factory_;
base::WeakPtrFactory<ServiceWorkerSubresourceLoader> weak_factory_{this};
};
// A custom URLLoaderFactory implementation used by Service Worker controllees
// for loading subresources via the controller Service Worker.
// Self destroys when no more bindings exist.
class CONTENT_EXPORT ServiceWorkerSubresourceLoaderFactory
: public network::mojom::URLLoaderFactory {
public:
// |controller_connector| is used to get a connection to the controller
// ServiceWorker.
// |fallback_factory| is used to get the associated loading context's
// default URLLoaderFactory for network fallback. This should be the
// URLLoaderFactory that directly goes to network without going through
// any custom URLLoader factories.
// |task_runner| is the runner where this loader runs. In production it runs,
// on a background thread.
static void Create(
scoped_refptr<ControllerServiceWorkerConnector> controller_connector,
scoped_refptr<network::SharedURLLoaderFactory> fallback_factory,
mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver,
scoped_refptr<base::SequencedTaskRunner> task_runner);
ServiceWorkerSubresourceLoaderFactory(
const ServiceWorkerSubresourceLoaderFactory&) = delete;
ServiceWorkerSubresourceLoaderFactory& operator=(
const ServiceWorkerSubresourceLoaderFactory&) = delete;
~ServiceWorkerSubresourceLoaderFactory() override;
// network::mojom::URLLoaderFactory overrides:
void CreateLoaderAndStart(
mojo::PendingReceiver<network::mojom::URLLoader> receiver,
int32_t request_id,
uint32_t options,
const network::ResourceRequest& resource_request,
mojo::PendingRemote<network::mojom::URLLoaderClient> client,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
override;
void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
override;
private:
ServiceWorkerSubresourceLoaderFactory(
scoped_refptr<ControllerServiceWorkerConnector> controller_connector,
scoped_refptr<network::SharedURLLoaderFactory> fallback_factory,
mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver,
scoped_refptr<base::SequencedTaskRunner> task_runner);
void OnMojoDisconnect();
scoped_refptr<ControllerServiceWorkerConnector> controller_connector_;
// Used when a request falls back to network.
scoped_refptr<network::SharedURLLoaderFactory> fallback_factory_;
mojo::ReceiverSet<network::mojom::URLLoaderFactory> receivers_;
// The task runner where this factory is running.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
base::WeakPtrFactory<ServiceWorkerSubresourceLoaderFactory> weak_factory_{
this};
};
} // namespace content
#endif // CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_SUBRESOURCE_LOADER_H_