blob: 84553df3fb677b0e956fb5b05adafd7d61b08dc0 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_URL_LOADER_JOB_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_URL_LOADER_JOB_H_
#include <memory>
#include <vector>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/loader/url_loader_request_handler.h"
#include "content/browser/service_worker/service_worker_fetch_dispatcher.h"
#include "content/browser/service_worker/service_worker_metrics.h"
#include "content/browser/service_worker/service_worker_response_type.h"
#include "content/browser/service_worker/service_worker_url_job_wrapper.h"
#include "content/browser/url_loader_factory_getter.h"
#include "content/common/service_worker/service_worker_status_code.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/public/common/url_loader.mojom.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "third_party/WebKit/public/platform/modules/serviceworker/service_worker_stream_handle.mojom.h"
namespace net {
struct RedirectInfo;
}
namespace storage {
class BlobStorageContext;
}
namespace content {
struct ServiceWorkerResponse;
class ServiceWorkerVersion;
// S13nServiceWorker:
// ServiceWorkerURLLoaderJob works similar to ServiceWorkerURLRequestJob
// but with mojom::URLLoader instead of URLRequest.
// This also works as a URLLoaderClient for BlobURLLoader while reading
// the blob content returned by SW.
class CONTENT_EXPORT ServiceWorkerURLLoaderJob : public mojom::URLLoader,
public mojom::URLLoaderClient {
public:
using Delegate = ServiceWorkerURLJobWrapper::Delegate;
using ResponseType = ServiceWorkerResponseType;
// Created by ServiceWorkerControlleeRequestHandler::MaybeCreateLoader
// when starting to load a page for navigation.
//
// This job typically works in the following order:
// 1. One of the FallbackTo* or ForwardTo* methods are called via
// URLJobWrapper by ServiceWorkerControlleeRequestHandler, which
// determines how the request should be served (e.g. should fallback
// to network or should be sent to the SW). If it decides to fallback
// to the network this will call |loader_callback| with null
// StartLoaderCallback (which will be then handled by
// NavigationURLLoaderNetworkService).
// 2. If it is decided that the request should be sent to the SW,
// this job dispatches a FetchEvent in StartRequest.
// 3. In DidDispatchFetchEvent() this job determines the request's
// final destination, and may still call |loader_callback| with null
// StartLoaderCallback if it turns out that we need to fallback to
// the network.
// 4. Otherwise if the SW returned a stream or blob as a response
// this job calls |loader_callback| with a bound method for
// StartResponse().
// 5. Then StartResponse() will be called with mojom::URLLoaderClientPtr
// that is connected to NavigationURLLoaderNetworkService (for resource
// loading for navigation). This job may set up BlobURLLoader and
// act as URLLoaderClient for the BlobURLLoader if the response includes
// blob uuid as a response body, or may forward the stream data pipe to
// the NavigationURLLoader if response body was sent as a stream.
ServiceWorkerURLLoaderJob(
LoaderCallback loader_callback,
Delegate* delegate,
const ResourceRequest& resource_request,
scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter,
base::WeakPtr<storage::BlobStorageContext> blob_storage_context);
~ServiceWorkerURLLoaderJob() override;
// Called via URLJobWrapper.
void FallbackToNetwork();
void FallbackToNetworkOrRenderer();
void ForwardToServiceWorker();
bool ShouldFallbackToNetwork();
void FailDueToLostController();
ui::PageTransition GetPageTransition();
size_t GetURLChainSize() const;
void Cancel();
bool WasCanceled() const;
private:
class StreamWaiter;
// For FORWARD_TO_SERVICE_WORKER case.
void StartRequest();
void DidPrepareFetchEvent(scoped_refptr<ServiceWorkerVersion> version);
void DidDispatchFetchEvent(
ServiceWorkerStatusCode status,
ServiceWorkerFetchDispatcher::FetchEventResult fetch_result,
const ServiceWorkerResponse& response,
blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
blink::mojom::BlobPtr body_as_blob,
scoped_refptr<ServiceWorkerVersion> version);
// Used as the StartLoaderCallback passed to |loader_callback_| when the
// service worker provided a response. Returns the response to |client|.
// |body_as_blob| is kept around until BlobDataHandle is created from
// blob_uuid just to make sure the blob is kept alive.
void StartResponse(const ServiceWorkerResponse& response,
scoped_refptr<ServiceWorkerVersion> version,
blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
blink::mojom::BlobPtr body_as_blob,
mojom::URLLoaderRequest request,
mojom::URLLoaderClientPtr client);
// Used as the StartLoaderCallback passed to |loader_callback_| on error.
// Returns a network error to |client|.
void StartErrorResponse(mojom::URLLoaderRequest request,
mojom::URLLoaderClientPtr client);
// Calls url_loader_client_->OnReceiveResopnse() with |response_head_|.
void CommitResponseHeaders();
// Calls url_loader_client_->OnComplete(). Expected to be called after
// CommitResponseHeaders (i.e. status_ == kSentHeader).
void CommitCompleted(int error_code);
// Calls |loader_callback_| with StartErrorResponse callback. Must not be
// called once either StartResponse or StartErrorResponse is called.
void ReturnNetworkError();
// mojom::URLLoader:
void FollowRedirect() override;
void SetPriority(net::RequestPriority priority,
int32_t intra_priority_value) override;
void PauseReadingBodyFromNet() override;
void ResumeReadingBodyFromNet() override;
// mojom::URLLoaderClient for Blob response reading (used only when
// the SW response had valid blob UUID):
void OnReceiveResponse(const ResourceResponseHead& response_head,
const base::Optional<net::SSLInfo>& ssl_info,
mojom::DownloadedTempFilePtr downloaded_file) override;
void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
const ResourceResponseHead& response_head) override;
void OnDataDownloaded(int64_t data_len, int64_t encoded_data_len) override;
void OnUploadProgress(int64_t current_position,
int64_t total_size,
OnUploadProgressCallback ack_callback) override;
void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override;
void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
void OnStartLoadingResponseBody(
mojo::ScopedDataPipeConsumerHandle body) override;
void OnComplete(const network::URLLoaderCompletionStatus& status) override;
ResponseType response_type_ = ResponseType::NOT_DETERMINED;
LoaderCallback loader_callback_;
Delegate* delegate_;
ResourceRequest resource_request_;
scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter_;
base::WeakPtr<storage::BlobStorageContext> blob_storage_context_;
std::unique_ptr<ServiceWorkerFetchDispatcher> fetch_dispatcher_;
std::unique_ptr<StreamWaiter> stream_waiter_;
bool did_navigation_preload_ = false;
ResourceResponseHead response_head_;
base::Optional<net::SSLInfo> ssl_info_;
// URLLoaderClient binding for loading a blob.
mojo::Binding<mojom::URLLoaderClient> blob_client_binding_;
// Pointer to the URLLoaderClient (i.e. NavigationURLLoader).
mojom::URLLoaderClientPtr url_loader_client_;
mojo::Binding<mojom::URLLoader> binding_;
enum class Status {
kNotStarted,
kStarted,
kSentHeader,
kCompleted,
kCancelled
};
Status status_ = Status::kNotStarted;
base::WeakPtrFactory<ServiceWorkerURLLoaderJob> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerURLLoaderJob);
};
} // namespace content
#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_URL_LOADER_JOB_H_