Chromium Code Reviews| 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..5685cf6a83c24744d215ea86440a58e47548b982 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,7 @@ |
| #include "content/browser/service_worker/service_worker_write_to_cache_job.h" |
| -#include "base/strings/stringprintf.h" |
| +#include <algorithm> |
|
nhiroki
2015/06/03 05:36:14
nit: Can you insert an empty line after <algorithm
falken
2015/06/03 09:07:41
Done.
|
| #include "base/strings/stringprintf.h" |
| #include "base/trace_event/trace_event.h" |
| #include "content/browser/service_worker/service_worker_context_core.h" |
| @@ -39,7 +39,271 @@ 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) { |
| + Complete(SERVICE_WORKER_ERROR_FAILED); |
| + return; |
| + } |
| + if (result == 0) { |
| + // We hit EOF 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; |
| + |
| + // Must call |owner_|->NotifyReadComplete() when done. Can be called with |
| + // |size| of 0 when |owner_| asynchronously read 0 bytes from the net request, |
| + // which signifies end of data. |
| + virtual void HandleData(net::IOBuffer* buf, int size) = 0; |
| + |
| + // Called when |owner_| synchronously read 0 bytes from the net request. |
| + // Returns true if there's no more work to be done. |
| + virtual bool OnResponseEnded() = 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_->NotifyFinishedCaching(); |
| + owner_->ClearPendingIO(); |
| + owner_->NotifyReadComplete(0); |
| + return; |
| + } |
| + |
| + owner_->WriteData(buf, size, |
| + base::Bind(&PassThroughConsumer::OnWriteDataComplete, |
| + weak_factory_.GetWeakPtr())); |
| + owner_->SetPendingIO(); |
| + } |
| + |
| + bool OnResponseEnded() override { |
| + owner_->NotifyFinishedCaching(); |
| + return true; |
| + } |
| + |
| + private: |
| + void OnWriteHeadersComplete() { |
| + owner_->ClearPendingIO(); |
| + owner_->NotifyHeadersComplete(); |
| + } |
| + |
| + 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_->NotifyHeadersComplete(); } |
| + |
| + void HandleData(net::IOBuffer* buf, int size) override { |
| + if (size == 0) { |
| + OnResponseEnded(); |
| + return; |
| + } |
| + |
| + net_data_ = buf->data(); |
| + net_data_size_ = size; |
| + pos_ = net_data_; |
| + |
| + owner_->SetPendingIO(); |
| + if (!info_) { |
| + io_buffer_ = new net::IOBuffer(kBufferSize); |
| + info_ = new HttpResponseInfoIOBuffer; |
| + reader_->ReadInfo(info_.get(), base::Bind(&Comparer::OnReadInfoComplete, |
| + weak_factory_.GetWeakPtr())); |
| + return; |
| + } |
| + ReadSomeData(); |
| + } |
| + |
| + bool OnResponseEnded() override { |
| + owner_->OnCompareComplete( |
| + bytes_matched_, info_ && info_->response_data_size == bytes_matched_); |
| + return false; |
| + } |
| + |
| + private: |
| + int bytes_remaining() { |
| + DCHECK(net_data_ && pos_); |
| + return net_data_ + net_data_size_ - pos_; |
| + } |
| + |
| + void OnReadInfoComplete(int result) { |
| + if (result < 0) { |
| + Complete(false); |
| + return; |
| + } |
| + ReadSomeData(); |
| + } |
| + |
| + void ReadSomeData() { |
| + DCHECK_LE(0, bytes_remaining()); |
| + int bytes_to_read = std::min(bytes_remaining(), kBufferSize); |
| + reader_->ReadData( |
| + io_buffer_.get(), bytes_to_read, |
| + base::Bind(&Comparer::OnReadDataComplete, weak_factory_.GetWeakPtr())); |
| + } |
| + |
| + void OnReadDataComplete(int result) { |
| + if (result < 0) { |
| + Complete(false); |
| + return; |
| + } |
| + if (result == 0) { |
| + // We hit EOF but had more to compare. |
| + Complete(false); |
| + return; |
| + } |
| + |
| + DCHECK_LE(result, bytes_remaining()); |
| + if (memcmp(pos_, io_buffer_->data(), result) != 0) { |
| + Complete(false); |
| + return; |
| + } |
| + |
| + bytes_matched_ += result; |
| + pos_ += result; |
| + if (bytes_remaining() == 0) { |
| + Complete(true); |
| + return; |
| + } |
| + |
| + ReadSomeData(); |
| + } |
| + |
| + // Completes one HandleData() call. |
| + void Complete(bool is_equal) { |
| + net_data_ = nullptr; |
| + pos_ = nullptr; |
| + int size = net_data_size_; |
| + net_data_size_ = 0; |
| + if (is_equal) { |
| + owner_->ClearPendingIO(); |
| + owner_->NotifyReadComplete(size); |
| + } else { |
| + owner_->OnCompareComplete(bytes_matched_, false); |
| + } |
| + } |
| + |
| + ServiceWorkerWriteToCacheJob* owner_; |
| + scoped_ptr<ServiceWorkerResponseReader> reader_; |
| + scoped_refptr<net::IOBuffer> io_buffer_; |
| + scoped_refptr<HttpResponseInfoIOBuffer> info_; |
| + |
| + // Cumulative number of bytes successfully compared. |
| + int bytes_matched_ = 0; |
| + |
| + // State used for one HandleData() call. |
| + const char* net_data_ = nullptr; |
| + const char* pos_ = nullptr; |
| + int net_data_size_ = 0; |
| + |
| + base::WeakPtrFactory<Comparer> weak_factory_; |
| +}; |
| ServiceWorkerWriteToCacheJob::ServiceWorkerWriteToCacheJob( |
| net::URLRequest* request, |
| @@ -48,12 +312,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 +342,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,21 +414,21 @@ 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; |
| + if (!status.is_success()) { |
| + AsyncNotifyDoneHelper(status, kFetchScriptError); |
| + 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; |
| - return status.is_success(); |
| + return consumer_->OnResponseEnded(); |
| } |
| const net::HttpResponseInfo* ServiceWorkerWriteToCacheJob::http_info() const { |
| @@ -190,12 +464,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 +479,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 +488,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 +497,19 @@ 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())); |
| writer_->WriteInfo( |
| 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 +518,32 @@ void ServiceWorkerWriteToCacheJob::OnWriteHeadersComplete(int result) { |
| kFetchScriptError); |
| return; |
| } |
| - http_info_.reset(info_buffer_->http_info.release()); |
| - info_buffer_ = NULL; |
| + info_buffer_ = nullptr; |
| 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 +560,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 +681,13 @@ void ServiceWorkerWriteToCacheJob::OnResponseStarted( |
| if (net_request_->response_info().network_accessed) |
| version_->embedded_worker()->OnNetworkAccessedForScriptLoad(); |
| - WriteHeadersToCache(); |
| + http_info_.reset(new net::HttpResponseInfo(net_request_->response_info())); |
| + consumer_->OnResponseStarted(); |
| +} |
| + |
| +void ServiceWorkerWriteToCacheJob::HandleNetData(int bytes_read) { |
| + io_buffer_bytes_ = bytes_read; |
| + consumer_->HandleData(io_buffer_.get(), bytes_read); |
| } |
| void ServiceWorkerWriteToCacheJob::OnReadCompleted( |
| @@ -424,17 +700,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,6 +729,73 @@ bool ServiceWorkerWriteToCacheJob::CheckPathRestriction( |
| return true; |
| } |
| +void ServiceWorkerWriteToCacheJob::SetPendingIO() { |
| + SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); |
| +} |
| + |
| +void ServiceWorkerWriteToCacheJob::ClearPendingIO() { |
| + SetStatus(net::URLRequestStatus()); |
| +} |
| + |
| +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()); |
| + return; |
|
nhiroki
2015/06/03 05:36:14
nit: this return is not necessary.
falken
2015/06/03 09:07:41
Done.
|
| +} |
| + |
| +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(); |
| + ClearPendingIO(); |
| + NotifyReadComplete(0); |
| +} |
| + |
| void ServiceWorkerWriteToCacheJob::AsyncNotifyDoneHelper( |
| const net::URLRequestStatus& status, |
| const std::string& status_message) { |
| @@ -472,4 +812,11 @@ void ServiceWorkerWriteToCacheJob::AsyncNotifyDoneHelper( |
| NotifyDone(status); |
| } |
| +void ServiceWorkerWriteToCacheJob::NotifyFinishedCaching() { |
| + version_->script_cache_map()->NotifyFinishedCaching( |
| + url_, writer_ ? writer_->amount_written() : 0, net::URLRequestStatus(), |
| + std::string()); |
| + did_notify_finished_ = true; |
| +} |
| + |
| } // namespace content |