blob: 42b34d5d5379de42de1568f30e0efed7fd91683f [file] [log] [blame]
// Copyright 2014 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_REQUEST_JOB_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_URL_REQUEST_JOB_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <string>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/time/time.h"
#include "content/browser/service_worker/embedded_worker_status.h"
#include "content/browser/service_worker/service_worker_metrics.h"
#include "content/common/content_export.h"
#include "content/common/service_worker/service_worker_status_code.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/public/common/request_context_frame_type.h"
#include "content/public/common/request_context_type.h"
#include "content/public/common/resource_type.h"
#include "net/http/http_byte_range.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_job.h"
#include "net/url_request/url_request_status.h"
#include "storage/common/blob_storage/blob_storage_constants.h"
#include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerResponseType.h"
#include "url/gurl.h"
namespace net {
class IOBuffer;
} // namespace net
namespace storage {
class BlobDataHandle;
class BlobStorageContext;
} // namespace storage
namespace content {
class ResourceContext;
class ResourceRequestBodyImpl;
class ServiceWorkerBlobReader;
class ServiceWorkerStreamReader;
class ServiceWorkerFetchDispatcher;
class ServiceWorkerVersion;
class Stream;
class CONTENT_EXPORT ServiceWorkerURLRequestJob : public net::URLRequestJob {
public:
class CONTENT_EXPORT Delegate {
public:
virtual ~Delegate() {}
// Will be invoked before the request is restarted. The caller
// can use this opportunity to grab state from the
// ServiceWorkerURLRequestJob to determine how it should behave when the
// request is restarted.
virtual void OnPrepareToRestart() = 0;
// Returns the ServiceWorkerVersion fetch events for this request job should
// be dispatched to. If no appropriate worker can be determined, returns
// nullptr and sets |*result| to an appropriate error.
virtual ServiceWorkerVersion* GetServiceWorkerVersion(
ServiceWorkerMetrics::URLRequestJobResult* result) = 0;
// Called after dispatching the fetch event to determine if processing of
// the request should still continue, or if processing should be aborted.
// When false is returned, this sets |*result| to an appropriate error.
virtual bool RequestStillValid(
ServiceWorkerMetrics::URLRequestJobResult* result);
// Called to signal that loading failed, and that the resource being loaded
// was a main resource.
virtual void MainResourceLoadFailed() {}
};
ServiceWorkerURLRequestJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
const std::string& client_id,
base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
const ResourceContext* resource_context,
FetchRequestMode request_mode,
FetchCredentialsMode credentials_mode,
FetchRedirectMode redirect_mode,
ResourceType resource_type,
RequestContextType request_context_type,
RequestContextFrameType frame_type,
scoped_refptr<ResourceRequestBodyImpl> body,
ServiceWorkerFetchType fetch_type,
const base::Optional<base::TimeDelta>& timeout,
Delegate* delegate);
~ServiceWorkerURLRequestJob() override;
const ResourceContext* resource_context() const { return resource_context_; }
// Sets the response type.
// When an in-flight request possibly needs CORS check, use
// FallbackToNetworkOrRenderer. This method will decide whether the request
// can directly go to the network or should fallback to a renderer to send
// CORS preflight. You can use FallbackToNetwork only when, like main resource
// or foreign fetch cases, it's apparent that the request should go to the
// network directly.
// TODO(shimazu): Update the comment when what should we do at foreign fetch
// fallback is determined: crbug.com/604084
void FallbackToNetwork();
void FallbackToNetworkOrRenderer();
void ForwardToServiceWorker();
bool ShouldFallbackToNetwork() const {
return response_type_ == FALLBACK_TO_NETWORK;
}
bool ShouldForwardToServiceWorker() const {
return response_type_ == FORWARD_TO_SERVICE_WORKER;
}
// net::URLRequestJob overrides:
void Start() override;
void Kill() override;
net::LoadState GetLoadState() const override;
bool GetCharset(std::string* charset) override;
bool GetMimeType(std::string* mime_type) const override;
void GetResponseInfo(net::HttpResponseInfo* info) override;
void GetLoadTimingInfo(net::LoadTimingInfo* load_timing_info) const override;
int GetResponseCode() const override;
void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
int ReadRawData(net::IOBuffer* buf, int buf_size) override;
//----------------------------------------------------------------------------
// The following are intended for use by ServiceWorker(Blob|Stream)Reader.
void OnResponseStarted();
void OnReadRawDataComplete(int bytes_read);
void RecordResult(ServiceWorkerMetrics::URLRequestJobResult result);
//----------------------------------------------------------------------------
base::WeakPtr<ServiceWorkerURLRequestJob> GetWeakPtr();
private:
class FileSizeResolver;
enum ResponseType {
NOT_DETERMINED,
FALLBACK_TO_NETWORK,
FALLBACK_TO_RENDERER, // Use this when falling back with CORS check
FORWARD_TO_SERVICE_WORKER,
};
enum ResponseBodyType {
UNKNOWN,
BLOB,
STREAM,
};
// We start processing the request if Start() is called AND response_type_
// is determined.
void MaybeStartRequest();
void StartRequest();
// Creates ServiceWorkerFetchRequest from |request_| and |body_|.
std::unique_ptr<ServiceWorkerFetchRequest> CreateFetchRequest();
// Creates BlobDataHandle of the request body from |body_|. This handle
// |request_body_blob_data_handle_| will be deleted when
// ServiceWorkerURLRequestJob is deleted.
// This must not be called until all files in |body_| with unknown size have
// their sizes populated.
void CreateRequestBodyBlob(std::string* blob_uuid, uint64_t* blob_size);
// For FORWARD_TO_SERVICE_WORKER case.
void DidPrepareFetchEvent(scoped_refptr<ServiceWorkerVersion> version);
void DidDispatchFetchEvent(
ServiceWorkerStatusCode status,
ServiceWorkerFetchEventResult fetch_result,
const ServiceWorkerResponse& response,
const scoped_refptr<ServiceWorkerVersion>& version);
void SetResponse(const ServiceWorkerResponse& response);
// Populates |http_response_headers_|.
void CreateResponseHeader(int status_code,
const std::string& status_text,
const ServiceWorkerHeaderMap& headers);
// Creates |http_response_info_| using |http_response_headers_| and calls
// NotifyHeadersComplete.
void CommitResponseHeader();
// Creates and commits a response header indicating error.
void DeliverErrorResponse();
// Restarts this job to fallback to network.
// This can be called after StartRequest.
void FinalizeFallbackToNetwork();
// Sends back a response with fall_back_required set as true to trigger
// subsequent network requests with CORS checking.
// This can be called after StartRequest.
void FinalizeFallbackToRenderer();
// True if need to send back a response with fall_back_required set as true to
// trigger subsequent network requests with CORS checking.
bool IsFallbackToRendererNeeded() const;
// For UMA.
void SetResponseBodyType(ResponseBodyType type);
bool ShouldRecordResult();
void RecordStatusZeroResponseError(
blink::WebServiceWorkerResponseError error);
const net::HttpResponseInfo* http_info() const;
// Invoke callbacks before invoking corresponding URLRequestJob methods.
void NotifyHeadersComplete();
void NotifyStartError(net::URLRequestStatus status);
void NotifyRestartRequired();
// Wrapper that gathers parameters to |on_start_completed_callback_| and then
// calls it.
void OnStartCompleted() const;
bool IsMainResourceLoad() const;
// For waiting for files sizes of request body files with unknown sizes.
bool HasRequestBody();
void RequestBodyFileSizesResolved(bool success);
// Not owned.
Delegate* delegate_;
// Timing info to show on the popup in Devtools' Network tab.
net::LoadTimingInfo load_timing_info_;
base::TimeTicks worker_start_time_;
base::TimeTicks worker_ready_time_;
base::Time response_time_;
ResponseType response_type_;
bool is_started_;
net::HttpByteRange byte_range_;
std::unique_ptr<net::HttpResponseInfo> range_response_info_;
std::unique_ptr<net::HttpResponseInfo> http_response_info_;
// Headers that have not yet been committed to |http_response_info_|.
scoped_refptr<net::HttpResponseHeaders> http_response_headers_;
GURL response_url_;
blink::WebServiceWorkerResponseType service_worker_response_type_;
// Used when response type is FORWARD_TO_SERVICE_WORKER.
std::unique_ptr<ServiceWorkerFetchDispatcher> fetch_dispatcher_;
std::string client_id_;
base::WeakPtr<storage::BlobStorageContext> blob_storage_context_;
const ResourceContext* resource_context_;
// Only one of |blob_reader_| and |stream_reader_| can be non-null.
std::unique_ptr<ServiceWorkerBlobReader> blob_reader_;
std::unique_ptr<ServiceWorkerStreamReader> stream_reader_;
FetchRequestMode request_mode_;
FetchCredentialsMode credentials_mode_;
FetchRedirectMode redirect_mode_;
const ResourceType resource_type_;
RequestContextType request_context_type_;
RequestContextFrameType frame_type_;
bool fall_back_required_;
// ResourceRequestBody has a collection of BlobDataHandles attached to it
// using the userdata mechanism. So we have to keep it not to free the blobs.
scoped_refptr<ResourceRequestBodyImpl> body_;
std::unique_ptr<storage::BlobDataHandle> request_body_blob_data_handle_;
ServiceWorkerFetchType fetch_type_;
base::Optional<base::TimeDelta> timeout_;
ResponseBodyType response_body_type_ = UNKNOWN;
bool did_record_result_ = false;
bool response_is_in_cache_storage_ = false;
std::string response_cache_storage_cache_name_;
ServiceWorkerHeaderList cors_exposed_header_names_;
std::unique_ptr<FileSizeResolver> file_size_resolver_;
bool worker_already_activated_ = false;
EmbeddedWorkerStatus initial_worker_status_ = EmbeddedWorkerStatus::STOPPED;
base::WeakPtrFactory<ServiceWorkerURLRequestJob> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerURLRequestJob);
};
} // namespace content
#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_URL_REQUEST_JOB_H_