| 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 c3ea949be39cfc3fd03215bc0dae57abeee37211..781a65257b61f1371eb8eaa703cdae73565c3dd0 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,11 +4,10 @@
|
|
|
| #include "content/browser/service_worker/service_worker_write_to_cache_job.h"
|
|
|
| -#include "base/bind.h"
|
| -#include "base/callback.h"
|
| +#include <algorithm>
|
| +
|
| #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"
|
| @@ -19,6 +18,7 @@
|
| #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,7 +40,259 @@
|
| "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,
|
| @@ -79,14 +331,14 @@
|
| net::URLRequestStatus::FAILED, net::ERR_FAILED));
|
| return;
|
| }
|
| -
|
| - // 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))));
|
| + 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));
|
| + }
|
| +
|
| version_->script_cache_map()->NotifyStartedCaching(
|
| url_, response_id_);
|
| did_notify_started_ = true;
|
| @@ -99,9 +351,12 @@
|
| weak_factory_.InvalidateWeakPtrs();
|
| has_been_killed_ = true;
|
| net_request_.reset();
|
| - if (did_notify_started_) {
|
| - NotifyFinishedCaching(net::URLRequestStatus::FromError(net::ERR_ABORTED),
|
| - kKilledError);
|
| + 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;
|
| }
|
| writer_.reset();
|
| context_.reset();
|
| @@ -157,15 +412,17 @@
|
| return false;
|
|
|
| if (!status.is_success()) {
|
| - NotifyDoneHelper(status, kFetchScriptError);
|
| + AsyncNotifyDoneHelper(status, kFetchScriptError);
|
| return false;
|
| }
|
|
|
| - HandleNetData(*bytes_read);
|
| - // 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;
|
| + DCHECK_EQ(0, *bytes_read);
|
| + consumer_->HandleData(buf, 0);
|
| + if (did_notify_finished_)
|
| + return GetStatus().is_success();
|
| + if (GetStatus().is_io_pending())
|
| + return false;
|
| + return status.is_success();
|
| }
|
|
|
| const net::HttpResponseInfo* ServiceWorkerWriteToCacheJob::http_info() const {
|
| @@ -204,12 +461,102 @@
|
| int* bytes_read) {
|
| DCHECK_GT(buf_size, 0);
|
| DCHECK(bytes_read);
|
| + *bytes_read = 0;
|
| io_buffer_ = buf;
|
| io_buffer_bytes_ = 0;
|
| - if (!net_request_->Read(buf, buf_size, bytes_read))
|
| - DCHECK_NE(net::URLRequestStatus::SUCCESS, net_request_->status().status());
|
| -
|
| + 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();
|
| + }
|
| +
|
| + 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(
|
| @@ -220,9 +567,9 @@
|
| TRACE_EVENT0("ServiceWorker",
|
| "ServiceWorkerWriteToCacheJob::OnReceivedRedirect");
|
| // Script resources can't redirect.
|
| - NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| - net::ERR_UNSAFE_REDIRECT),
|
| - kRedirectError);
|
| + AsyncNotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| + net::ERR_UNSAFE_REDIRECT),
|
| + kRedirectError);
|
| }
|
|
|
| void ServiceWorkerWriteToCacheJob::OnAuthRequired(
|
| @@ -232,7 +579,7 @@
|
| TRACE_EVENT0("ServiceWorker",
|
| "ServiceWorkerWriteToCacheJob::OnAuthRequired");
|
| // TODO(michaeln): Pass this thru to our jobs client.
|
| - NotifyDoneHelper(
|
| + AsyncNotifyDoneHelper(
|
| net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
|
| kClientAuthenticationError);
|
| }
|
| @@ -245,7 +592,7 @@
|
| "ServiceWorkerWriteToCacheJob::OnCertificateRequested");
|
| // TODO(michaeln): Pass this thru to our jobs client.
|
| // see NotifyCertificateRequested.
|
| - NotifyDoneHelper(
|
| + AsyncNotifyDoneHelper(
|
| net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
|
| kClientAuthenticationError);
|
| }
|
| @@ -259,9 +606,9 @@
|
| "ServiceWorkerWriteToCacheJob::OnSSLCertificateError");
|
| // TODO(michaeln): Pass this thru to our jobs client,
|
| // see NotifySSLCertificateError.
|
| - NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| - net::ERR_INSECURE_RESPONSE),
|
| - kSSLError);
|
| + AsyncNotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| + net::ERR_INSECURE_RESPONSE),
|
| + kSSLError);
|
| }
|
|
|
| void ServiceWorkerWriteToCacheJob::OnBeforeNetworkStart(
|
| @@ -277,15 +624,15 @@
|
| net::URLRequest* request) {
|
| DCHECK_EQ(net_request_, request);
|
| if (!request->status().is_success()) {
|
| - NotifyDoneHelper(request->status(), kFetchScriptError);
|
| + AsyncNotifyDoneHelper(request->status(), kFetchScriptError);
|
| return;
|
| }
|
| if (request->GetResponseCode() / 100 != 2) {
|
| std::string error_message =
|
| base::StringPrintf(kBadHTTPResponseError, request->GetResponseCode());
|
| - NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| - net::ERR_INVALID_RESPONSE),
|
| - error_message);
|
| + AsyncNotifyDoneHelper(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;
|
| @@ -296,9 +643,9 @@
|
| const net::HttpNetworkSession::Params* session_params =
|
| request->context()->GetNetworkSessionParams();
|
| if (!session_params || !session_params->ignore_certificate_errors) {
|
| - NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| - net::ERR_INSECURE_RESPONSE),
|
| - kSSLError);
|
| + AsyncNotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| + net::ERR_INSECURE_RESPONSE),
|
| + kSSLError);
|
| return;
|
| }
|
| }
|
| @@ -313,9 +660,9 @@
|
| mime_type.empty()
|
| ? kNoMIMEError
|
| : base::StringPrintf(kBadMIMEError, mime_type.c_str());
|
| - NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| - net::ERR_INSECURE_RESPONSE),
|
| - error_message);
|
| + AsyncNotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| + net::ERR_INSECURE_RESPONSE),
|
| + error_message);
|
| return;
|
| }
|
|
|
| @@ -328,47 +675,17 @@
|
| if (net_request_->response_info().network_accessed)
|
| version_->embedded_worker()->OnNetworkAccessedForScriptLoad();
|
|
|
| + consumer_->OnResponseStarted();
|
| +}
|
| +
|
| +void ServiceWorkerWriteToCacheJob::CommitHeadersAndNotifyHeadersComplete() {
|
| 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::OnWriteHeadersComplete(net::Error error) {
|
| - SetStatus(net::URLRequestStatus::FromError(error));
|
| NotifyHeadersComplete();
|
| }
|
|
|
| void ServiceWorkerWriteToCacheJob::HandleNetData(int bytes_read) {
|
| io_buffer_bytes_ = 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) {
|
| - NotifyFinishedCaching(net::URLRequestStatus::FromError(error),
|
| - std::string());
|
| - }
|
| - NotifyReadComplete(error == net::OK ? io_buffer_bytes_ : error);
|
| + consumer_->HandleData(io_buffer_.get(), bytes_read);
|
| }
|
|
|
| void ServiceWorkerWriteToCacheJob::OnReadCompleted(
|
| @@ -377,10 +694,18 @@
|
| DCHECK_EQ(net_request_, request);
|
| if (bytes_read < 0) {
|
| DCHECK(!request->status().is_success());
|
| - NotifyDoneHelper(request->status(), kFetchScriptError);
|
| - return;
|
| - }
|
| - HandleNetData(bytes_read);
|
| + AsyncNotifyDoneHelper(request->status(), kFetchScriptError);
|
| + return;
|
| + }
|
| + if (bytes_read > 0) {
|
| + HandleNetData(bytes_read);
|
| + DCHECK(GetStatus().is_io_pending());
|
| + return;
|
| + }
|
| +
|
| + // No more data to process, the job is complete.
|
| + DCHECK(request->status().is_success());
|
| + HandleNetData(0);
|
| }
|
|
|
| bool ServiceWorkerWriteToCacheJob::CheckPathRestriction(
|
| @@ -394,15 +719,89 @@
|
| if (!ServiceWorkerUtils::IsPathRestrictionSatisfied(
|
| version_->scope(), url_,
|
| has_header ? &service_worker_allowed : nullptr, &error_message)) {
|
| - NotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| - net::ERR_INSECURE_RESPONSE),
|
| - error_message);
|
| + AsyncNotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
| + net::ERR_INSECURE_RESPONSE),
|
| + error_message);
|
| return false;
|
| }
|
| return true;
|
| }
|
|
|
| -void ServiceWorkerWriteToCacheJob::NotifyDoneHelper(
|
| +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(
|
| const net::URLRequestStatus& status,
|
| const std::string& status_message) {
|
| DCHECK(!status.is_io_pending());
|
| @@ -414,39 +813,13 @@
|
| void ServiceWorkerWriteToCacheJob::NotifyFinishedCaching(
|
| net::URLRequestStatus status,
|
| const std::string& status_message) {
|
| - 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);
|
| - }
|
| -
|
| + DCHECK(!did_notify_finished_);
|
| int size = -1;
|
| if (status.is_success())
|
| - size = cache_writer_->bytes_written();
|
| -
|
| + size = writer_ ? writer_->amount_written() : 0;
|
| 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
|
|
|