Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(52)

Unified Diff: content/browser/service_worker/service_worker_write_to_cache_job.cc

Issue 1351423002: Revert of ServiceWorkerWriteToCacheJob: refactor (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/browser/service_worker/service_worker_write_to_cache_job.h ('k') | content/content_browser.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « content/browser/service_worker/service_worker_write_to_cache_job.h ('k') | content/content_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698