| Index: content/browser/service_worker/service_worker_write_to_cache_job.cc
|
| diff --git a/content/browser/service_worker/service_worker_write_to_cache_job.cc b/content/browser/service_worker/service_worker_write_to_cache_job.cc
|
| index 781a65257b61f1371eb8eaa703cdae73565c3dd0..ca801ca39c9bb713962fdc6a93ba9c2366603945 100644
|
| --- a/content/browser/service_worker/service_worker_write_to_cache_job.cc
|
| +++ b/content/browser/service_worker/service_worker_write_to_cache_job.cc
|
| @@ -4,10 +4,11 @@
|
|
|
| #include "content/browser/service_worker/service_worker_write_to_cache_job.h"
|
|
|
| -#include <algorithm>
|
| -
|
| +#include "base/bind.h"
|
| +#include "base/callback.h"
|
| #include "base/strings/stringprintf.h"
|
| #include "base/trace_event/trace_event.h"
|
| +#include "content/browser/service_worker/service_worker_cache_writer.h"
|
| #include "content/browser/service_worker/service_worker_context_core.h"
|
| #include "content/browser/service_worker/service_worker_disk_cache.h"
|
| #include "content/browser/service_worker/service_worker_metrics.h"
|
| @@ -18,7 +19,6 @@
|
| #include "net/http/http_network_session.h"
|
| #include "net/http/http_request_headers.h"
|
| #include "net/http/http_response_headers.h"
|
| -#include "net/http/http_util.h"
|
| #include "net/url_request/url_request.h"
|
| #include "net/url_request/url_request_context.h"
|
| #include "net/url_request/url_request_status.h"
|
| @@ -40,260 +40,8 @@ const char kRedirectError[] =
|
| "The script resource is behind a redirect, which is disallowed.";
|
| const char kServiceWorkerAllowed[] = "Service-Worker-Allowed";
|
|
|
| -const int kBufferSize = 16 * 1024;
|
| -
|
| } // namespace
|
|
|
| -// Reads an existing resource and copies it via
|
| -// ServiceWorkerWriteToCacheJob::WriteData.
|
| -class ServiceWorkerWriteToCacheJob::Copier : public base::RefCounted<Copier> {
|
| - public:
|
| - Copier(base::WeakPtr<ServiceWorkerWriteToCacheJob> owner,
|
| - scoped_ptr<ServiceWorkerResponseReader> reader,
|
| - int bytes_to_copy,
|
| - const base::Callback<void(ServiceWorkerStatusCode)>& callback)
|
| - : owner_(owner),
|
| - reader_(reader.release()),
|
| - bytes_to_copy_(bytes_to_copy),
|
| - callback_(callback) {
|
| - DCHECK_LT(0, bytes_to_copy_);
|
| - }
|
| -
|
| - void Start() {
|
| - io_buffer_ = new net::IOBuffer(kBufferSize);
|
| - ReadSomeData();
|
| - }
|
| -
|
| - private:
|
| - friend class base::RefCounted<Copier>;
|
| - ~Copier() {}
|
| -
|
| - void ReadSomeData() {
|
| - reader_->ReadData(io_buffer_.get(), kBufferSize,
|
| - base::Bind(&Copier::OnReadDataComplete, this));
|
| - }
|
| -
|
| - void OnReadDataComplete(int result) {
|
| - if (!owner_)
|
| - return;
|
| - if (result <= 0) {
|
| - // We hit EOF or error but weren't done copying.
|
| - Complete(SERVICE_WORKER_ERROR_FAILED);
|
| - return;
|
| - }
|
| -
|
| - int bytes_to_write = std::min(bytes_to_copy_, result);
|
| - owner_->WriteData(io_buffer_.get(), bytes_to_write,
|
| - base::Bind(&Copier::OnWriteDataComplete, this));
|
| - }
|
| -
|
| - void OnWriteDataComplete(int result) {
|
| - if (result < 0) {
|
| - Complete(SERVICE_WORKER_ERROR_FAILED);
|
| - return;
|
| - }
|
| -
|
| - DCHECK_LE(result, bytes_to_copy_);
|
| - bytes_to_copy_ -= result;
|
| - if (bytes_to_copy_ == 0) {
|
| - Complete(SERVICE_WORKER_OK);
|
| - return;
|
| - }
|
| -
|
| - ReadSomeData();
|
| - }
|
| -
|
| - void Complete(ServiceWorkerStatusCode status) {
|
| - if (!owner_)
|
| - return;
|
| - callback_.Run(status);
|
| - }
|
| -
|
| - base::WeakPtr<ServiceWorkerWriteToCacheJob> owner_;
|
| - scoped_ptr<ServiceWorkerResponseReader> reader_;
|
| - int bytes_to_copy_ = 0;
|
| - base::Callback<void(ServiceWorkerStatusCode)> callback_;
|
| - scoped_refptr<net::IOBuffer> io_buffer_;
|
| -};
|
| -
|
| -// Abstract consumer for ServiceWorkerWriteToCacheJob that processes data from
|
| -// the network.
|
| -class ServiceWorkerWriteToCacheJob::NetDataConsumer {
|
| - public:
|
| - virtual ~NetDataConsumer() {}
|
| -
|
| - // Called by |owner_|'s OnResponseStarted.
|
| - virtual void OnResponseStarted() = 0;
|
| -
|
| - // HandleData should call |owner_|->NotifyReadComplete() when done.
|
| - virtual void HandleData(net::IOBuffer* buf, int size) = 0;
|
| -};
|
| -
|
| -// Dumb consumer that just writes everything it sees to disk.
|
| -class ServiceWorkerWriteToCacheJob::PassThroughConsumer
|
| - : public ServiceWorkerWriteToCacheJob::NetDataConsumer {
|
| - public:
|
| - explicit PassThroughConsumer(ServiceWorkerWriteToCacheJob* owner)
|
| - : owner_(owner), weak_factory_(this) {}
|
| - ~PassThroughConsumer() override {}
|
| -
|
| - void OnResponseStarted() override {
|
| - owner_->WriteHeaders(
|
| - base::Bind(&PassThroughConsumer::OnWriteHeadersComplete,
|
| - weak_factory_.GetWeakPtr()));
|
| - owner_->SetPendingIO();
|
| - }
|
| -
|
| - void HandleData(net::IOBuffer* buf, int size) override {
|
| - if (size == 0) {
|
| - owner_->OnPassThroughComplete();
|
| - return;
|
| - }
|
| -
|
| - owner_->WriteData(buf, size,
|
| - base::Bind(&PassThroughConsumer::OnWriteDataComplete,
|
| - weak_factory_.GetWeakPtr()));
|
| - owner_->SetPendingIO();
|
| - }
|
| -
|
| - private:
|
| - void OnWriteHeadersComplete() {
|
| - owner_->ClearPendingIO();
|
| - owner_->CommitHeadersAndNotifyHeadersComplete();
|
| - }
|
| -
|
| - void OnWriteDataComplete(int result) {
|
| - owner_->ClearPendingIO();
|
| - owner_->NotifyReadComplete(result);
|
| - }
|
| -
|
| - ServiceWorkerWriteToCacheJob* owner_;
|
| - base::WeakPtrFactory<PassThroughConsumer> weak_factory_;
|
| -};
|
| -
|
| -// Compares an existing resource with data progressively fed to it.
|
| -// Calls back to |owner|->OnCompareComplete once done.
|
| -class ServiceWorkerWriteToCacheJob::Comparer
|
| - : public ServiceWorkerWriteToCacheJob::NetDataConsumer {
|
| - public:
|
| - Comparer(ServiceWorkerWriteToCacheJob* owner,
|
| - scoped_ptr<ServiceWorkerResponseReader> reader)
|
| - : owner_(owner), reader_(reader.release()), weak_factory_(this) {}
|
| - ~Comparer() override {}
|
| -
|
| - void OnResponseStarted() override {
|
| - owner_->CommitHeadersAndNotifyHeadersComplete();
|
| - }
|
| -
|
| - void HandleData(net::IOBuffer* buf, int size) override {
|
| - net_data_ = buf;
|
| - net_data_offset_ = 0;
|
| - net_data_size_ = size;
|
| -
|
| - if (size == 0 && info_) {
|
| - Complete(bytes_matched_ == info_->response_data_size);
|
| - return;
|
| - }
|
| -
|
| - if (!info_) {
|
| - read_buffer_ = new net::IOBuffer(kBufferSize);
|
| - info_ = new HttpResponseInfoIOBuffer;
|
| - reader_->ReadInfo(info_.get(), base::Bind(&Comparer::OnReadInfoComplete,
|
| - weak_factory_.GetWeakPtr()));
|
| - owner_->SetPendingIO();
|
| - return;
|
| - }
|
| -
|
| - ReadSomeData();
|
| - owner_->SetPendingIO();
|
| - }
|
| -
|
| - private:
|
| - int bytes_remaining() {
|
| - DCHECK(net_data_);
|
| - DCHECK_LE(0, net_data_offset_);
|
| - DCHECK_LE(net_data_offset_, net_data_size_);
|
| - return net_data_size_ - net_data_offset_;
|
| - }
|
| -
|
| - void OnReadInfoComplete(int result) {
|
| - if (result < 0) {
|
| - Complete(false);
|
| - return;
|
| - }
|
| -
|
| - if (bytes_remaining() == 0) {
|
| - Complete(bytes_matched_ == info_->response_data_size);
|
| - return;
|
| - }
|
| -
|
| - ReadSomeData();
|
| - }
|
| -
|
| - void ReadSomeData() {
|
| - DCHECK_LT(0, bytes_remaining());
|
| - int bytes_to_read = std::min(bytes_remaining(), kBufferSize);
|
| - reader_->ReadData(
|
| - read_buffer_.get(), bytes_to_read,
|
| - base::Bind(&Comparer::OnReadDataComplete, weak_factory_.GetWeakPtr()));
|
| - }
|
| -
|
| - void OnReadDataComplete(int result) {
|
| - if (result <= 0) {
|
| - // We hit error or EOF but had more to compare.
|
| - Complete(false);
|
| - return;
|
| - }
|
| -
|
| - DCHECK_LE(result, bytes_remaining());
|
| - if (memcmp(net_data_->data() + net_data_offset_, read_buffer_->data(),
|
| - result) != 0) {
|
| - Complete(false);
|
| - return;
|
| - }
|
| -
|
| - net_data_offset_ += result;
|
| - if (bytes_remaining() == 0) {
|
| - NotifyReadComplete();
|
| - return;
|
| - }
|
| -
|
| - ReadSomeData();
|
| - }
|
| -
|
| - // Completes one HandleData() call.
|
| - void NotifyReadComplete() {
|
| - int size = net_data_size_;
|
| - net_data_ = nullptr;
|
| - net_data_offset_ = 0;
|
| - net_data_size_ = 0;
|
| -
|
| - bytes_matched_ += size;
|
| - owner_->ClearPendingIO();
|
| - owner_->NotifyReadComplete(size);
|
| - }
|
| -
|
| - // Completes the entire Comparer.
|
| - void Complete(bool is_equal) {
|
| - owner_->OnCompareComplete(bytes_matched_, is_equal);
|
| - }
|
| -
|
| - ServiceWorkerWriteToCacheJob* owner_;
|
| - scoped_ptr<ServiceWorkerResponseReader> reader_;
|
| - scoped_refptr<net::IOBuffer> read_buffer_;
|
| - scoped_refptr<HttpResponseInfoIOBuffer> info_;
|
| -
|
| - // Cumulative number of bytes successfully compared.
|
| - int bytes_matched_ = 0;
|
| -
|
| - // State used for one HandleData() call.
|
| - scoped_refptr<net::IOBuffer> net_data_;
|
| - int net_data_offset_ = 0;
|
| - int net_data_size_ = 0;
|
| -
|
| - base::WeakPtrFactory<Comparer> weak_factory_;
|
| -};
|
| -
|
| ServiceWorkerWriteToCacheJob::ServiceWorkerWriteToCacheJob(
|
| net::URLRequest* request,
|
| net::NetworkDelegate* network_delegate,
|
| @@ -331,14 +79,14 @@ void ServiceWorkerWriteToCacheJob::Start() {
|
| net::URLRequestStatus::FAILED, net::ERR_FAILED));
|
| return;
|
| }
|
| - if (incumbent_response_id_ != kInvalidServiceWorkerResourceId) {
|
| - scoped_ptr<ServiceWorkerResponseReader> incumbent_reader =
|
| - context_->storage()->CreateResponseReader(incumbent_response_id_);
|
| - consumer_.reset(new Comparer(this, incumbent_reader.Pass()));
|
| - } else {
|
| - consumer_.reset(new PassThroughConsumer(this));
|
| - }
|
|
|
| + // These uses of Unretained are safe because this object is the sole owner of
|
| + // |cache_writer_|, which in turn is the sole user of these callbacks.
|
| + cache_writer_.reset(new ServiceWorkerCacheWriter(
|
| + base::Bind(&ServiceWorkerWriteToCacheJob::CreateCacheResponseReader,
|
| + base::Unretained(this)),
|
| + base::Bind(&ServiceWorkerWriteToCacheJob::CreateCacheResponseWriter,
|
| + base::Unretained(this))));
|
| version_->script_cache_map()->NotifyStartedCaching(
|
| url_, response_id_);
|
| did_notify_started_ = true;
|
| @@ -351,12 +99,9 @@ void ServiceWorkerWriteToCacheJob::Kill() {
|
| weak_factory_.InvalidateWeakPtrs();
|
| has_been_killed_ = true;
|
| net_request_.reset();
|
| - if (did_notify_started_ && !did_notify_finished_) {
|
| - version_->script_cache_map()->NotifyFinishedCaching(
|
| - url_, -1,
|
| - net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_ABORTED),
|
| - kKilledError);
|
| - did_notify_finished_ = true;
|
| + if (did_notify_started_) {
|
| + NotifyFinishedCaching(net::URLRequestStatus::FromError(net::ERR_ABORTED),
|
| + kKilledError);
|
| }
|
| writer_.reset();
|
| context_.reset();
|
| @@ -412,17 +157,21 @@ bool ServiceWorkerWriteToCacheJob::ReadRawData(net::IOBuffer* buf,
|
| return false;
|
|
|
| if (!status.is_success()) {
|
| - AsyncNotifyDoneHelper(status, kFetchScriptError);
|
| + NotifyDoneHelper(status, kFetchScriptError);
|
| return false;
|
| }
|
|
|
| - DCHECK_EQ(0, *bytes_read);
|
| - consumer_->HandleData(buf, 0);
|
| - if (did_notify_finished_)
|
| - return GetStatus().is_success();
|
| - if (GetStatus().is_io_pending())
|
| + HandleNetData(*bytes_read);
|
| +
|
| + if (!status.is_success()) {
|
| + NotifyDoneHelper(status, "");
|
| return false;
|
| - return status.is_success();
|
| + }
|
| +
|
| + // Since URLRequestStatus::is_success() means "SUCCESS or IO_PENDING", but the
|
| + // contract of this function is "return true for synchronous successes only",
|
| + // it is important to test against SUCCESS explicitly here.
|
| + return GetStatus().status() == net::URLRequestStatus::SUCCESS;
|
| }
|
|
|
| const net::HttpResponseInfo* ServiceWorkerWriteToCacheJob::http_info() const {
|
| @@ -461,104 +210,14 @@ net::URLRequestStatus ServiceWorkerWriteToCacheJob::ReadNetData(
|
| int* bytes_read) {
|
| DCHECK_GT(buf_size, 0);
|
| DCHECK(bytes_read);
|
| - *bytes_read = 0;
|
| io_buffer_ = buf;
|
| io_buffer_bytes_ = 0;
|
| - int net_bytes_read = 0;
|
| - if (!net_request_->Read(buf, buf_size, &net_bytes_read)) {
|
| - if (net_request_->status().is_io_pending())
|
| - return net_request_->status();
|
| - DCHECK(!net_request_->status().is_success());
|
| - return net_request_->status();
|
| - }
|
| -
|
| - if (net_bytes_read != 0) {
|
| - HandleNetData(net_bytes_read);
|
| - DCHECK(GetStatus().is_io_pending());
|
| - return GetStatus();
|
| - }
|
| + if (!net_request_->Read(buf, buf_size, bytes_read))
|
| + DCHECK_NE(net::URLRequestStatus::SUCCESS, net_request_->status().status());
|
|
|
| - DCHECK(net_request_->status().is_success());
|
| return net_request_->status();
|
| }
|
|
|
| -void ServiceWorkerWriteToCacheJob::WriteHeaders(const base::Closure& callback) {
|
| - if (!context_) {
|
| - AsyncNotifyDoneHelper(
|
| - net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
|
| - kFetchScriptError);
|
| - return;
|
| - }
|
| - TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker",
|
| - "ServiceWorkerWriteToCacheJob::ExecutingJob",
|
| - this, "WriteHeaders");
|
| - writer_ = context_->storage()->CreateResponseWriter(response_id_);
|
| - scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
|
| - new HttpResponseInfoIOBuffer(
|
| - new net::HttpResponseInfo(net_request_->response_info()));
|
| - writer_->WriteInfo(
|
| - info_buffer.get(),
|
| - base::Bind(&ServiceWorkerWriteToCacheJob::OnWriteHeadersComplete,
|
| - weak_factory_.GetWeakPtr(), callback));
|
| -}
|
| -
|
| -void ServiceWorkerWriteToCacheJob::OnWriteHeadersComplete(
|
| - const base::Closure& callback,
|
| - int result) {
|
| - if (result < 0) {
|
| - ServiceWorkerMetrics::CountWriteResponseResult(
|
| - ServiceWorkerMetrics::WRITE_HEADERS_ERROR);
|
| - AsyncNotifyDoneHelper(
|
| - net::URLRequestStatus(net::URLRequestStatus::FAILED, result),
|
| - kFetchScriptError);
|
| - return;
|
| - }
|
| - TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker",
|
| - "ServiceWorkerWriteToCacheJob::ExecutingJob",
|
| - this, "WriteHeadersCompleted");
|
| - callback.Run();
|
| -}
|
| -
|
| -void ServiceWorkerWriteToCacheJob::WriteData(
|
| - net::IOBuffer* buf,
|
| - int bytes_to_write,
|
| - const base::Callback<void(int result)>& callback) {
|
| - DCHECK_LT(0, bytes_to_write);
|
| - TRACE_EVENT_ASYNC_STEP_INTO1(
|
| - "ServiceWorker", "ServiceWorkerWriteToCacheJob::ExecutingJob", this,
|
| - "WriteData", "Amount to write", bytes_to_write);
|
| -
|
| - writer_->WriteData(
|
| - buf, bytes_to_write,
|
| - base::Bind(&ServiceWorkerWriteToCacheJob::OnWriteDataComplete,
|
| - weak_factory_.GetWeakPtr(), callback));
|
| -}
|
| -
|
| -void ServiceWorkerWriteToCacheJob::OnWriteDataComplete(
|
| - const base::Callback<void(int result)>& callback,
|
| - int result) {
|
| - DCHECK_NE(0, result);
|
| - if (!context_) {
|
| - AsyncNotifyDoneHelper(
|
| - net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
|
| - kFetchScriptError);
|
| - return;
|
| - }
|
| - if (result < 0) {
|
| - ServiceWorkerMetrics::CountWriteResponseResult(
|
| - ServiceWorkerMetrics::WRITE_DATA_ERROR);
|
| - AsyncNotifyDoneHelper(
|
| - net::URLRequestStatus(net::URLRequestStatus::FAILED, result),
|
| - kFetchScriptError);
|
| - return;
|
| - }
|
| - ServiceWorkerMetrics::CountWriteResponseResult(
|
| - ServiceWorkerMetrics::WRITE_OK);
|
| - callback.Run(result);
|
| - TRACE_EVENT_ASYNC_END0("ServiceWorker",
|
| - "ServiceWorkerWriteToCacheJob::ExecutingJob", this);
|
| -}
|
| -
|
| void ServiceWorkerWriteToCacheJob::OnReceivedRedirect(
|
| net::URLRequest* request,
|
| const net::RedirectInfo& redirect_info,
|
| @@ -567,9 +226,9 @@ void ServiceWorkerWriteToCacheJob::OnReceivedRedirect(
|
| TRACE_EVENT0("ServiceWorker",
|
| "ServiceWorkerWriteToCacheJob::OnReceivedRedirect");
|
| // Script resources can't redirect.
|
| - AsyncNotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| - net::ERR_UNSAFE_REDIRECT),
|
| - kRedirectError);
|
| + NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| + net::ERR_UNSAFE_REDIRECT),
|
| + kRedirectError);
|
| }
|
|
|
| void ServiceWorkerWriteToCacheJob::OnAuthRequired(
|
| @@ -579,7 +238,7 @@ void ServiceWorkerWriteToCacheJob::OnAuthRequired(
|
| TRACE_EVENT0("ServiceWorker",
|
| "ServiceWorkerWriteToCacheJob::OnAuthRequired");
|
| // TODO(michaeln): Pass this thru to our jobs client.
|
| - AsyncNotifyDoneHelper(
|
| + NotifyDoneHelper(
|
| net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
|
| kClientAuthenticationError);
|
| }
|
| @@ -592,7 +251,7 @@ void ServiceWorkerWriteToCacheJob::OnCertificateRequested(
|
| "ServiceWorkerWriteToCacheJob::OnCertificateRequested");
|
| // TODO(michaeln): Pass this thru to our jobs client.
|
| // see NotifyCertificateRequested.
|
| - AsyncNotifyDoneHelper(
|
| + NotifyDoneHelper(
|
| net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
|
| kClientAuthenticationError);
|
| }
|
| @@ -606,9 +265,9 @@ void ServiceWorkerWriteToCacheJob::OnSSLCertificateError(
|
| "ServiceWorkerWriteToCacheJob::OnSSLCertificateError");
|
| // TODO(michaeln): Pass this thru to our jobs client,
|
| // see NotifySSLCertificateError.
|
| - AsyncNotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| - net::ERR_INSECURE_RESPONSE),
|
| - kSSLError);
|
| + NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| + net::ERR_INSECURE_RESPONSE),
|
| + kSSLError);
|
| }
|
|
|
| void ServiceWorkerWriteToCacheJob::OnBeforeNetworkStart(
|
| @@ -624,15 +283,15 @@ void ServiceWorkerWriteToCacheJob::OnResponseStarted(
|
| net::URLRequest* request) {
|
| DCHECK_EQ(net_request_, request);
|
| if (!request->status().is_success()) {
|
| - AsyncNotifyDoneHelper(request->status(), kFetchScriptError);
|
| + NotifyDoneHelper(request->status(), kFetchScriptError);
|
| return;
|
| }
|
| if (request->GetResponseCode() / 100 != 2) {
|
| std::string error_message =
|
| base::StringPrintf(kBadHTTPResponseError, request->GetResponseCode());
|
| - AsyncNotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| - net::ERR_INVALID_RESPONSE),
|
| - error_message);
|
| + NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| + net::ERR_INVALID_RESPONSE),
|
| + error_message);
|
| // TODO(michaeln): Instead of error'ing immediately, send the net
|
| // response to our consumer, just don't cache it?
|
| return;
|
| @@ -643,9 +302,9 @@ void ServiceWorkerWriteToCacheJob::OnResponseStarted(
|
| const net::HttpNetworkSession::Params* session_params =
|
| request->context()->GetNetworkSessionParams();
|
| if (!session_params || !session_params->ignore_certificate_errors) {
|
| - AsyncNotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| - net::ERR_INSECURE_RESPONSE),
|
| - kSSLError);
|
| + NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| + net::ERR_INSECURE_RESPONSE),
|
| + kSSLError);
|
| return;
|
| }
|
| }
|
| @@ -660,9 +319,9 @@ void ServiceWorkerWriteToCacheJob::OnResponseStarted(
|
| mime_type.empty()
|
| ? kNoMIMEError
|
| : base::StringPrintf(kBadMIMEError, mime_type.c_str());
|
| - AsyncNotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| - net::ERR_INSECURE_RESPONSE),
|
| - error_message);
|
| + NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| + net::ERR_INSECURE_RESPONSE),
|
| + error_message);
|
| return;
|
| }
|
|
|
| @@ -675,17 +334,46 @@ void ServiceWorkerWriteToCacheJob::OnResponseStarted(
|
| if (net_request_->response_info().network_accessed)
|
| version_->embedded_worker()->OnNetworkAccessedForScriptLoad();
|
|
|
| - consumer_->OnResponseStarted();
|
| + http_info_.reset(new net::HttpResponseInfo(net_request_->response_info()));
|
| + scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
|
| + new HttpResponseInfoIOBuffer(
|
| + new net::HttpResponseInfo(net_request_->response_info()));
|
| + net::Error error = cache_writer_->MaybeWriteHeaders(
|
| + info_buffer.get(),
|
| + base::Bind(&ServiceWorkerWriteToCacheJob::OnWriteHeadersComplete,
|
| + weak_factory_.GetWeakPtr()));
|
| + SetStatus(net::URLRequestStatus::FromError(error));
|
| + if (error != net::ERR_IO_PENDING)
|
| + NotifyHeadersComplete();
|
| }
|
|
|
| -void ServiceWorkerWriteToCacheJob::CommitHeadersAndNotifyHeadersComplete() {
|
| - http_info_.reset(new net::HttpResponseInfo(net_request_->response_info()));
|
| +void ServiceWorkerWriteToCacheJob::OnWriteHeadersComplete(net::Error error) {
|
| + SetStatus(net::URLRequestStatus::FromError(error));
|
| NotifyHeadersComplete();
|
| }
|
|
|
| void ServiceWorkerWriteToCacheJob::HandleNetData(int bytes_read) {
|
| io_buffer_bytes_ = bytes_read;
|
| - consumer_->HandleData(io_buffer_.get(), bytes_read);
|
| + net::Error error = cache_writer_->MaybeWriteData(
|
| + io_buffer_.get(), bytes_read,
|
| + base::Bind(&ServiceWorkerWriteToCacheJob::OnWriteDataComplete,
|
| + weak_factory_.GetWeakPtr()));
|
| + SetStatus(net::URLRequestStatus::FromError(error));
|
| +
|
| + // In case of ERR_IO_PENDING, this logic is done in OnWriteDataComplete.
|
| + if (error != net::ERR_IO_PENDING && bytes_read == 0) {
|
| + NotifyFinishedCaching(net::URLRequestStatus::FromError(error),
|
| + std::string());
|
| + }
|
| +}
|
| +
|
| +void ServiceWorkerWriteToCacheJob::OnWriteDataComplete(net::Error error) {
|
| + SetStatus(net::URLRequestStatus::FromError(error));
|
| + DCHECK_NE(net::ERR_IO_PENDING, error);
|
| + if (io_buffer_bytes_ == 0) {
|
| + NotifyDoneHelper(net::URLRequestStatus::FromError(error), std::string());
|
| + }
|
| + NotifyReadComplete(error == net::OK ? io_buffer_bytes_ : error);
|
| }
|
|
|
| void ServiceWorkerWriteToCacheJob::OnReadCompleted(
|
| @@ -694,18 +382,23 @@ void ServiceWorkerWriteToCacheJob::OnReadCompleted(
|
| DCHECK_EQ(net_request_, request);
|
| if (bytes_read < 0) {
|
| DCHECK(!request->status().is_success());
|
| - AsyncNotifyDoneHelper(request->status(), kFetchScriptError);
|
| + NotifyDoneHelper(request->status(), kFetchScriptError);
|
| return;
|
| }
|
| - if (bytes_read > 0) {
|
| - HandleNetData(bytes_read);
|
| - DCHECK(GetStatus().is_io_pending());
|
| - return;
|
| + HandleNetData(bytes_read);
|
| + // HandleNetData can cause status of this job to change. If the status changes
|
| + // to IO_PENDING, that means HandleNetData has pending IO, and
|
| + // NotifyReadComplete will be called later by the appropriate callback.
|
| + if (!GetStatus().is_io_pending()) {
|
| + int result = GetStatus().status() == net::URLRequestStatus::SUCCESS
|
| + ? bytes_read
|
| + : GetStatus().error();
|
| + // If bytes_read is 0, HandleNetData synchronously completed and this job is
|
| + // at EOF.
|
| + if (bytes_read == 0)
|
| + NotifyDoneHelper(GetStatus(), std::string());
|
| + NotifyReadComplete(result);
|
| }
|
| -
|
| - // No more data to process, the job is complete.
|
| - DCHECK(request->status().is_success());
|
| - HandleNetData(0);
|
| }
|
|
|
| bool ServiceWorkerWriteToCacheJob::CheckPathRestriction(
|
| @@ -719,89 +412,15 @@ bool ServiceWorkerWriteToCacheJob::CheckPathRestriction(
|
| if (!ServiceWorkerUtils::IsPathRestrictionSatisfied(
|
| version_->scope(), url_,
|
| has_header ? &service_worker_allowed : nullptr, &error_message)) {
|
| - AsyncNotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| - net::ERR_INSECURE_RESPONSE),
|
| - error_message);
|
| + NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| + net::ERR_INSECURE_RESPONSE),
|
| + error_message);
|
| return false;
|
| }
|
| return true;
|
| }
|
|
|
| -void ServiceWorkerWriteToCacheJob::SetPendingIO() {
|
| - SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
|
| -}
|
| -
|
| -void ServiceWorkerWriteToCacheJob::ClearPendingIO() {
|
| - SetStatus(net::URLRequestStatus());
|
| -}
|
| -
|
| -void ServiceWorkerWriteToCacheJob::OnPassThroughComplete() {
|
| - NotifyFinishedCaching(net::URLRequestStatus(), std::string());
|
| - if (GetStatus().is_io_pending()) {
|
| - ClearPendingIO();
|
| - NotifyReadComplete(0);
|
| - }
|
| -}
|
| -
|
| -void ServiceWorkerWriteToCacheJob::OnCompareComplete(int bytes_matched,
|
| - bool is_equal) {
|
| - if (is_equal) {
|
| - // This version is identical to the incumbent, so discard it and fail this
|
| - // job.
|
| - version_->SetStartWorkerStatusCode(SERVICE_WORKER_ERROR_EXISTS);
|
| - AsyncNotifyDoneHelper(
|
| - net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
|
| - kFetchScriptError);
|
| - return;
|
| - }
|
| -
|
| - // We must switch to the pass through consumer. Write what is known
|
| - // (headers + bytes matched) to disk.
|
| - WriteHeaders(base::Bind(&ServiceWorkerWriteToCacheJob::CopyIncumbent,
|
| - weak_factory_.GetWeakPtr(), bytes_matched));
|
| - SetPendingIO();
|
| -}
|
| -
|
| -void ServiceWorkerWriteToCacheJob::CopyIncumbent(int bytes_to_copy) {
|
| - if (bytes_to_copy == 0) {
|
| - OnCopyComplete(SERVICE_WORKER_OK);
|
| - return;
|
| - }
|
| - scoped_ptr<ServiceWorkerResponseReader> incumbent_reader =
|
| - context_->storage()->CreateResponseReader(incumbent_response_id_);
|
| - scoped_refptr<Copier> copier = new Copier(
|
| - weak_factory_.GetWeakPtr(), incumbent_reader.Pass(), bytes_to_copy,
|
| - base::Bind(&ServiceWorkerWriteToCacheJob::OnCopyComplete,
|
| - weak_factory_.GetWeakPtr()));
|
| - copier->Start(); // It deletes itself when done.
|
| - DCHECK(GetStatus().is_io_pending());
|
| -}
|
| -
|
| -void ServiceWorkerWriteToCacheJob::OnCopyComplete(
|
| - ServiceWorkerStatusCode status) {
|
| - if (status != SERVICE_WORKER_OK) {
|
| - AsyncNotifyDoneHelper(
|
| - net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
|
| - kFetchScriptError);
|
| - return;
|
| - }
|
| -
|
| - // Continue processing the net data that triggered the comparison fail and
|
| - // copy.
|
| - if (io_buffer_bytes_ > 0) {
|
| - consumer_.reset(new PassThroughConsumer(this));
|
| - consumer_->HandleData(io_buffer_.get(), io_buffer_bytes_);
|
| - return;
|
| - }
|
| -
|
| - // The copy was triggered by EOF from the network, which
|
| - // means the job is now done.
|
| - NotifyFinishedCaching(net::URLRequestStatus(), std::string());
|
| - ClearPendingIO();
|
| - NotifyReadComplete(0);
|
| -}
|
| -
|
| -void ServiceWorkerWriteToCacheJob::AsyncNotifyDoneHelper(
|
| +void ServiceWorkerWriteToCacheJob::NotifyDoneHelper(
|
| const net::URLRequestStatus& status,
|
| const std::string& status_message) {
|
| DCHECK(!status.is_io_pending());
|
| @@ -813,13 +432,39 @@ void ServiceWorkerWriteToCacheJob::AsyncNotifyDoneHelper(
|
| void ServiceWorkerWriteToCacheJob::NotifyFinishedCaching(
|
| net::URLRequestStatus status,
|
| const std::string& status_message) {
|
| - DCHECK(!did_notify_finished_);
|
| + if (did_notify_finished_)
|
| + return;
|
| +
|
| + // If all the calls to MaybeWriteHeaders/MaybeWriteData succeeded, but the
|
| + // incumbent entry wasn't actually replaced because the new entry was
|
| + // equivalent, the new version didn't actually install because it already
|
| + // exists.
|
| + if (status.status() == net::URLRequestStatus::SUCCESS &&
|
| + !cache_writer_->did_replace()) {
|
| + status =
|
| + net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED);
|
| + version_->SetStartWorkerStatusCode(SERVICE_WORKER_ERROR_EXISTS);
|
| + }
|
| +
|
| int size = -1;
|
| if (status.is_success())
|
| - size = writer_ ? writer_->amount_written() : 0;
|
| + size = cache_writer_->bytes_written();
|
| +
|
| version_->script_cache_map()->NotifyFinishedCaching(url_, size, status,
|
| status_message);
|
| did_notify_finished_ = true;
|
| }
|
|
|
| +scoped_ptr<ServiceWorkerResponseReader>
|
| +ServiceWorkerWriteToCacheJob::CreateCacheResponseReader() {
|
| + if (incumbent_response_id_ != kInvalidServiceWorkerResponseId)
|
| + return context_->storage()->CreateResponseReader(incumbent_response_id_);
|
| + return nullptr;
|
| +}
|
| +
|
| +scoped_ptr<ServiceWorkerResponseWriter>
|
| +ServiceWorkerWriteToCacheJob::CreateCacheResponseWriter() {
|
| + return context_->storage()->CreateResponseWriter(response_id_);
|
| +}
|
| +
|
| } // namespace content
|
|
|