| 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 b04e98b3c15d949f752b8359940cfdef19f0ec7e..f2ad7061fcec7f06bc66239cebd552dec938a0c7 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,7 +4,8 @@
|
|
|
| #include "content/browser/service_worker/service_worker_write_to_cache_job.h"
|
|
|
| -#include "base/strings/stringprintf.h"
|
| +#include <algorithm>
|
| +
|
| #include "base/strings/stringprintf.h"
|
| #include "base/trace_event/trace_event.h"
|
| #include "content/browser/service_worker/service_worker_context_core.h"
|
| @@ -39,7 +40,259 @@ 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,
|
| @@ -48,12 +301,14 @@ ServiceWorkerWriteToCacheJob::ServiceWorkerWriteToCacheJob(
|
| base::WeakPtr<ServiceWorkerContextCore> context,
|
| ServiceWorkerVersion* version,
|
| int extra_load_flags,
|
| - int64 response_id)
|
| + int64 response_id,
|
| + int64 incumbent_response_id)
|
| : net::URLRequestJob(request, network_delegate),
|
| resource_type_(resource_type),
|
| context_(context),
|
| url_(request->url()),
|
| response_id_(response_id),
|
| + incumbent_response_id_(incumbent_response_id),
|
| version_(version),
|
| has_been_killed_(false),
|
| did_notify_started_(false),
|
| @@ -76,6 +331,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));
|
| + }
|
| +
|
| version_->script_cache_map()->NotifyStartedCaching(
|
| url_, response_id_);
|
| did_notify_started_ = true;
|
| @@ -140,20 +403,25 @@ void ServiceWorkerWriteToCacheJob::SetExtraRequestHeaders(
|
| net_request_->SetExtraRequestHeaders(headers);
|
| }
|
|
|
| -bool ServiceWorkerWriteToCacheJob::ReadRawData(
|
| - net::IOBuffer* buf,
|
| - int buf_size,
|
| - int *bytes_read) {
|
| +bool ServiceWorkerWriteToCacheJob::ReadRawData(net::IOBuffer* buf,
|
| + int buf_size,
|
| + int* bytes_read) {
|
| net::URLRequestStatus status = ReadNetData(buf, buf_size, bytes_read);
|
| SetStatus(status);
|
| if (status.is_io_pending())
|
| return false;
|
|
|
| - // No more data to process, the job is complete.
|
| - io_buffer_ = NULL;
|
| - version_->script_cache_map()->NotifyFinishedCaching(
|
| - url_, writer_->amount_written(), status, std::string());
|
| - did_notify_finished_ = true;
|
| + if (!status.is_success()) {
|
| + AsyncNotifyDoneHelper(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())
|
| + return false;
|
| return status.is_success();
|
| }
|
|
|
| @@ -190,12 +458,12 @@ void ServiceWorkerWriteToCacheJob::StartNetRequest() {
|
| net::URLRequestStatus ServiceWorkerWriteToCacheJob::ReadNetData(
|
| net::IOBuffer* buf,
|
| int buf_size,
|
| - int *bytes_read) {
|
| + 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())
|
| @@ -205,7 +473,7 @@ net::URLRequestStatus ServiceWorkerWriteToCacheJob::ReadNetData(
|
| }
|
|
|
| if (net_bytes_read != 0) {
|
| - WriteDataToCache(net_bytes_read);
|
| + HandleNetData(net_bytes_read);
|
| DCHECK(GetStatus().is_io_pending());
|
| return GetStatus();
|
| }
|
| @@ -214,7 +482,7 @@ net::URLRequestStatus ServiceWorkerWriteToCacheJob::ReadNetData(
|
| return net_request_->status();
|
| }
|
|
|
| -void ServiceWorkerWriteToCacheJob::WriteHeadersToCache() {
|
| +void ServiceWorkerWriteToCacheJob::WriteHeaders(const base::Closure& callback) {
|
| if (!context_) {
|
| AsyncNotifyDoneHelper(
|
| net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
|
| @@ -223,20 +491,20 @@ void ServiceWorkerWriteToCacheJob::WriteHeadersToCache() {
|
| }
|
| TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker",
|
| "ServiceWorkerWriteToCacheJob::ExecutingJob",
|
| - this,
|
| - "WriteHeadersToCache");
|
| + this, "WriteHeaders");
|
| writer_ = context_->storage()->CreateResponseWriter(response_id_);
|
| - info_buffer_ = new HttpResponseInfoIOBuffer(
|
| - new net::HttpResponseInfo(net_request_->response_info()));
|
| + scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
|
| + new HttpResponseInfoIOBuffer(
|
| + new net::HttpResponseInfo(net_request_->response_info()));
|
| writer_->WriteInfo(
|
| - info_buffer_.get(),
|
| + info_buffer.get(),
|
| base::Bind(&ServiceWorkerWriteToCacheJob::OnWriteHeadersComplete,
|
| - weak_factory_.GetWeakPtr()));
|
| - SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
|
| + weak_factory_.GetWeakPtr(), callback));
|
| }
|
|
|
| -void ServiceWorkerWriteToCacheJob::OnWriteHeadersComplete(int result) {
|
| - SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status
|
| +void ServiceWorkerWriteToCacheJob::OnWriteHeadersComplete(
|
| + const base::Closure& callback,
|
| + int result) {
|
| if (result < 0) {
|
| ServiceWorkerMetrics::CountWriteResponseResult(
|
| ServiceWorkerMetrics::WRITE_HEADERS_ERROR);
|
| @@ -245,33 +513,31 @@ void ServiceWorkerWriteToCacheJob::OnWriteHeadersComplete(int result) {
|
| kFetchScriptError);
|
| return;
|
| }
|
| - http_info_.reset(info_buffer_->http_info.release());
|
| - info_buffer_ = NULL;
|
| TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker",
|
| "ServiceWorkerWriteToCacheJob::ExecutingJob",
|
| - this,
|
| - "WriteHeadersToCacheCompleted");
|
| - NotifyHeadersComplete();
|
| + this, "WriteHeadersCompleted");
|
| + callback.Run();
|
| }
|
|
|
| -void ServiceWorkerWriteToCacheJob::WriteDataToCache(int amount_to_write) {
|
| - DCHECK_NE(0, amount_to_write);
|
| - TRACE_EVENT_ASYNC_STEP_INTO1("ServiceWorker",
|
| - "ServiceWorkerWriteToCacheJob::ExecutingJob",
|
| - this,
|
| - "WriteDataToCache",
|
| - "Amount to write", amount_to_write);
|
| - SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
|
| +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(
|
| - io_buffer_.get(),
|
| - amount_to_write,
|
| + buf, bytes_to_write,
|
| base::Bind(&ServiceWorkerWriteToCacheJob::OnWriteDataComplete,
|
| - weak_factory_.GetWeakPtr()));
|
| + weak_factory_.GetWeakPtr(), callback));
|
| }
|
|
|
| -void ServiceWorkerWriteToCacheJob::OnWriteDataComplete(int result) {
|
| +void ServiceWorkerWriteToCacheJob::OnWriteDataComplete(
|
| + const base::Callback<void(int result)>& callback,
|
| + int result) {
|
| DCHECK_NE(0, result);
|
| - io_buffer_ = NULL;
|
| if (!context_) {
|
| AsyncNotifyDoneHelper(
|
| net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
|
| @@ -288,11 +554,9 @@ void ServiceWorkerWriteToCacheJob::OnWriteDataComplete(int result) {
|
| }
|
| ServiceWorkerMetrics::CountWriteResponseResult(
|
| ServiceWorkerMetrics::WRITE_OK);
|
| - SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status
|
| - NotifyReadComplete(result);
|
| + callback.Run(result);
|
| TRACE_EVENT_ASYNC_END0("ServiceWorker",
|
| - "ServiceWorkerWriteToCacheJob::ExecutingJob",
|
| - this);
|
| + "ServiceWorkerWriteToCacheJob::ExecutingJob", this);
|
| }
|
|
|
| void ServiceWorkerWriteToCacheJob::OnReceivedRedirect(
|
| @@ -411,7 +675,17 @@ void ServiceWorkerWriteToCacheJob::OnResponseStarted(
|
| if (net_request_->response_info().network_accessed)
|
| version_->embedded_worker()->OnNetworkAccessedForScriptLoad();
|
|
|
| - WriteHeadersToCache();
|
| + consumer_->OnResponseStarted();
|
| +}
|
| +
|
| +void ServiceWorkerWriteToCacheJob::CommitHeadersAndNotifyHeadersComplete() {
|
| + http_info_.reset(new net::HttpResponseInfo(net_request_->response_info()));
|
| + NotifyHeadersComplete();
|
| +}
|
| +
|
| +void ServiceWorkerWriteToCacheJob::HandleNetData(int bytes_read) {
|
| + io_buffer_bytes_ = bytes_read;
|
| + consumer_->HandleData(io_buffer_.get(), bytes_read);
|
| }
|
|
|
| void ServiceWorkerWriteToCacheJob::OnReadCompleted(
|
| @@ -424,17 +698,14 @@ void ServiceWorkerWriteToCacheJob::OnReadCompleted(
|
| return;
|
| }
|
| if (bytes_read > 0) {
|
| - WriteDataToCache(bytes_read);
|
| + HandleNetData(bytes_read);
|
| + DCHECK(GetStatus().is_io_pending());
|
| return;
|
| }
|
| +
|
| // No more data to process, the job is complete.
|
| DCHECK(request->status().is_success());
|
| - io_buffer_ = NULL;
|
| - version_->script_cache_map()->NotifyFinishedCaching(
|
| - url_, writer_->amount_written(), net::URLRequestStatus(), std::string());
|
| - did_notify_finished_ = true;
|
| - SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status
|
| - NotifyReadComplete(0);
|
| + HandleNetData(0);
|
| }
|
|
|
| bool ServiceWorkerWriteToCacheJob::CheckPathRestriction(
|
| @@ -456,20 +727,99 @@ bool ServiceWorkerWriteToCacheJob::CheckPathRestriction(
|
| 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(
|
| const net::URLRequestStatus& status,
|
| const std::string& status_message) {
|
| DCHECK(!status.is_io_pending());
|
| + NotifyFinishedCaching(status, status_message);
|
| + SetStatus(status);
|
| + NotifyDone(status);
|
| +}
|
| +
|
| +void ServiceWorkerWriteToCacheJob::NotifyFinishedCaching(
|
| + net::URLRequestStatus status,
|
| + const std::string& status_message) {
|
| DCHECK(!did_notify_finished_);
|
| int size = -1;
|
| - if (writer_.get()) {
|
| - size = writer_->amount_written();
|
| - }
|
| + if (status.is_success())
|
| + size = writer_ ? writer_->amount_written() : 0;
|
| version_->script_cache_map()->NotifyFinishedCaching(url_, size, status,
|
| status_message);
|
| did_notify_finished_ = true;
|
| - SetStatus(status);
|
| - NotifyDone(status);
|
| }
|
|
|
| } // namespace content
|
|
|