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

Unified Diff: net/http/http_cache_transaction.cc

Issue 1230113012: [net] Better StopCaching() handling for HttpCache::Transaction. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add missing MockTransaction initializers 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
Index: net/http/http_cache_transaction.cc
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index db3f4968911b47ec29167190cf429a69007e00d7..9da268ffe51f0dd238e5d9acea601841103264cd 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -266,8 +266,10 @@ HttpCache::Transaction::Transaction(RequestPriority priority, HttpCache* cache)
done_reading_(false),
vary_mismatch_(false),
couldnt_conditionalize_request_(false),
+ stopped_caching_(false),
bypass_lock_for_test_(false),
fail_conditionalization_for_test_(false),
+ read_buf_len_(0),
io_buf_len_(0),
read_offset_(0),
effective_load_flags_(0),
@@ -290,22 +292,28 @@ HttpCache::Transaction::~Transaction() {
// after this point.
callback_.Reset();
- if (cache_) {
- if (entry_) {
- bool cancel_request = reading_ && response_.headers.get();
- if (cancel_request) {
- if (partial_) {
- entry_->disk_entry->CancelSparseIO();
- } else {
- cancel_request &= (response_.headers->response_code() == 200);
- }
- }
+ RecordHistograms();
+
+ if (!cache_)
+ return;
- cache_->DoneWithEntry(entry_, this, cancel_request);
- } else if (cache_pending_) {
+ if (!entry_) {
+ if (cache_pending_)
cache_->RemovePendingTransaction(this);
- }
+ return;
+ }
+
+ bool cancel_request = reading_ && response_.headers.get() &&
+ (response_.headers->response_code() == 200 || partial_);
+ if (cancel_request) {
+ if (partial_)
+ entry_->disk_entry->CancelSparseIO();
+
+ AbandonCacheEntry(CompletionCallback());
+ return;
}
+
+ ReleaseCacheEntry(EntryState::DOOM);
}
int HttpCache::Transaction::WriteMetadata(IOBuffer* buf, int buf_len,
@@ -324,26 +332,6 @@ int HttpCache::Transaction::WriteMetadata(IOBuffer* buf, int buf_len,
callback, true);
}
-bool HttpCache::Transaction::AddTruncatedFlag() {
- DCHECK(mode_ & WRITE || mode_ == NONE);
-
- // Don't set the flag for sparse entries.
- if (partial_ && !truncated_)
- return true;
-
- if (!CanResume(true))
- return false;
-
- // We may have received the whole resource already.
- if (done_reading_)
- return true;
-
- truncated_ = true;
- next_state_ = STATE_CACHE_WRITE_TRUNCATED_RESPONSE;
- DoLoop(OK);
- return true;
-}
-
LoadState HttpCache::Transaction::GetWriterLoadState() const {
if (network_trans_.get())
return network_trans_->GetLoadState();
@@ -458,7 +446,6 @@ int HttpCache::Transaction::Read(IOBuffer* buf, int buf_len,
DCHECK(buf);
DCHECK_GT(buf_len, 0);
DCHECK(!callback.is_null());
-
DCHECK(callback_.is_null());
if (!cache_.get())
@@ -470,14 +457,17 @@ int HttpCache::Transaction::Read(IOBuffer* buf, int buf_len,
if (auth_response_.headers.get() && mode_ != NONE) {
UpdateTransactionPattern(PATTERN_NOT_COVERED);
DCHECK(mode_ & WRITE);
- DoneWritingToEntry(mode_ == READ_WRITE);
- mode_ = NONE;
+ ReleaseCacheEntry(mode_ == READ_WRITE ? EntryState::KEEP
+ : EntryState::DOOM);
}
reading_ = true;
read_buf_ = buf;
- io_buf_len_ = buf_len;
- if (network_trans_) {
+ read_buf_len_ = buf_len;
+ if (stopped_caching_ && entry_) {
+ DCHECK(mode_ & WRITE);
+ next_state_ = STATE_SWITCH_TO_NETWORK;
+ } else if (network_trans_) {
DCHECK(mode_ == WRITE || mode_ == NONE ||
(mode_ == READ_WRITE && partial_));
next_state_ = STATE_NETWORK_READ;
@@ -496,21 +486,14 @@ int HttpCache::Transaction::Read(IOBuffer* buf, int buf_len,
}
void HttpCache::Transaction::StopCaching() {
- // We really don't know where we are now. Hopefully there is no operation in
- // progress, but nothing really prevents this method to be called after we
- // returned ERR_IO_PENDING. We cannot attempt to truncate the entry at this
- // point because we need the state machine for that (and even if we are really
- // free, that would be an asynchronous operation). In other words, keep the
- // entry how it is (it will be marked as truncated at destruction), and let
- // the next piece of code that executes know that we are now reading directly
- // from the net.
- // TODO(mmenke): This doesn't release the lock on the cache entry, so a
- // future request for the resource will be blocked on this one.
- // Fix this.
- if (cache_.get() && entry_ && (mode_ & WRITE) && network_trans_.get() &&
- !is_sparse_ && !range_requested_) {
- mode_ = NONE;
- }
+ DCHECK(callback_.is_null());
+ DCHECK(request_);
+
+ // StopCaching requires being able to restart partial network requests. Doing
+ // so is only reliable if the request is idempotent. In addition, StopCaching
+ // is only effective if the transaction is writing to the cache.
+ if ((!partial_ || request_->method == "GET") && (mode_ & WRITE))
+ stopped_caching_ = true;
rvargas (doing something else) 2015/09/21 22:06:00 It looks like we set the flag when method != GET.
}
bool HttpCache::Transaction::GetFullRequestHeaders(
@@ -537,18 +520,11 @@ int64_t HttpCache::Transaction::GetTotalSentBytes() const {
}
void HttpCache::Transaction::DoneReading() {
- if (cache_.get() && entry_) {
- DCHECK_NE(mode_, UPDATE);
- if (mode_ & WRITE) {
- DoneWritingToEntry(true);
- } else if (mode_ & READ) {
- // It is necessary to check mode_ & READ because it is possible
- // for mode_ to be NONE and entry_ non-NULL with a write entry
- // if StopCaching was called.
- cache_->DoneReadingFromEntry(entry_, this);
- entry_ = NULL;
- }
- }
+ DCHECK_NE(mode_, UPDATE);
+ if (!cache_ || !entry_)
+ return;
+ done_reading_ = true;
+ ReleaseCacheEntry(EntryState::KEEP);
}
const HttpResponseInfo* HttpCache::Transaction::GetResponseInfo() const {
@@ -910,6 +886,9 @@ int HttpCache::Transaction::DoLoop(int result) {
case STATE_CACHE_READ_METADATA_COMPLETE:
rv = DoCacheReadMetadataComplete(rv);
break;
+ case STATE_SWITCH_TO_NETWORK:
+ rv = DoSwitchToNetwork();
+ break;
case STATE_NETWORK_READ:
DCHECK_EQ(OK, rv);
rv = DoNetworkRead();
@@ -930,13 +909,6 @@ int HttpCache::Transaction::DoLoop(int result) {
case STATE_CACHE_WRITE_DATA_COMPLETE:
rv = DoCacheWriteDataComplete(rv);
break;
- case STATE_CACHE_WRITE_TRUNCATED_RESPONSE:
- DCHECK_EQ(OK, rv);
- rv = DoCacheWriteTruncatedResponse();
- break;
- case STATE_CACHE_WRITE_TRUNCATED_RESPONSE_COMPLETE:
- rv = DoCacheWriteTruncatedResponseComplete(rv);
- break;
default:
NOTREACHED() << "bad state";
rv = ERR_FAILED;
@@ -945,7 +917,8 @@ int HttpCache::Transaction::DoLoop(int result) {
} while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
if (rv != ERR_IO_PENDING && !callback_.is_null()) {
- read_buf_ = NULL; // Release the buffer before invoking the callback.
+ read_buf_ = nullptr; // Release the buffer before invoking the callback.
+ read_buf_len_ = 0;
base::ResetAndReturn(&callback_).Run(rv);
}
@@ -1077,6 +1050,7 @@ int HttpCache::Transaction::DoOpenEntryComplete(int result) {
next_state_ = STATE_CREATE_ENTRY;
return OK;
}
+
if (mode_ == UPDATE) {
// There is no cache entry to update; proceed without caching.
mode_ = NONE;
@@ -1294,7 +1268,7 @@ int HttpCache::Transaction::DoCacheToggleUnusedSincePrefetch() {
"422516 HttpCache::Transaction::DoCacheToggleUnusedSincePrefetch"));
next_state_ = STATE_TOGGLE_UNUSED_SINCE_PREFETCH_COMPLETE;
- return WriteResponseInfoToEntry(false);
+ return WriteResponseInfoToEntry(false, io_callback_);
}
int HttpCache::Transaction::DoCacheToggleUnusedSincePrefetchComplete(
@@ -1362,14 +1336,8 @@ int HttpCache::Transaction::DoStartPartialCacheValidation() {
int HttpCache::Transaction::DoCompletePartialCacheValidation(int result) {
if (!result) {
- // This is the end of the request.
- if (mode_ & WRITE) {
- DoneWritingToEntry(true);
- } else {
- cache_->DoneReadingFromEntry(entry_, this);
- entry_ = NULL;
- }
- return result;
+ ReleaseCacheEntry(EntryState::KEEP);
+ return 0;
}
if (result < 0)
@@ -1441,7 +1409,7 @@ int HttpCache::Transaction::DoSendRequestComplete(int result) {
DCHECK(response);
response_.cert_request_info = response->cert_request_info;
} else if (response_.was_cached) {
- DoneWritingToEntry(true);
+ ReleaseCacheEntry(EntryState::KEEP);
}
return result;
@@ -1497,11 +1465,27 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() {
return OK;
}
+ if (handling_206_ && stopped_caching_ && partial_ &&
+ partial_->IsLastRange() && !partial_->IsCurrentRangeCached() &&
+ (mode_ & WRITE) && entry_) {
+ // The current state of the transaction is:
+ // * The client has requested that no addtional data be cached.
+ // * The current network transaction spans the entire remainder of the
+ // requested range.
+ // * A cache entry exists and was being written to or updated.
+ // * The current range is not cached.
+ //
+ // At this point it is safe to abandon the cache entry and proceed with just
+ // the network transaction.
+ next_state_ = STATE_NETWORK_READ;
+ return AbandonCacheEntry(io_callback_);
+ }
+
if (handling_206_ && mode_ == READ_WRITE && !truncated_ && !is_sparse_) {
// We have stored the full entry, but it changed and the server is
// sending a range. We have to delete the old entry.
UpdateTransactionPattern(PATTERN_NOT_COVERED);
- DoneWritingToEntry(false);
+ ReleaseCacheEntry(EntryState::DOOM);
}
if (mode_ == WRITE &&
@@ -1516,9 +1500,7 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() {
int ret = cache_->DoomEntry(cache_key_, NULL);
DCHECK_EQ(OK, ret);
}
- cache_->DoneWritingToEntry(entry_, true);
- entry_ = NULL;
- mode_ = NONE;
+ ReleaseCacheEntry(EntryState::KEEP);
}
// Invalidate any cached GET with a successful POST.
@@ -1597,7 +1579,7 @@ int HttpCache::Transaction::DoCacheWriteUpdatedResponse() {
"422516 HttpCache::Transaction::DoCacheWriteUpdatedResponse"));
next_state_ = STATE_CACHE_WRITE_UPDATED_RESPONSE_COMPLETE;
- return WriteResponseInfoToEntry(false);
+ return WriteResponseInfoToEntry(false, io_callback_);
}
int HttpCache::Transaction::DoCacheWriteUpdatedResponseComplete(int result) {
@@ -1613,7 +1595,7 @@ int HttpCache::Transaction::DoUpdateCachedResponseComplete(int result) {
//
// By closing the cached entry now, we make sure that the 304 rather than
// the cached 200 response, is what will be returned to the user.
- DoneWritingToEntry(true);
+ ReleaseCacheEntry(EntryState::KEEP);
} else if (entry_ && !handling_206_) {
DCHECK_EQ(READ_WRITE, mode_);
if (!partial_ || partial_->IsLastRange()) {
@@ -1652,16 +1634,15 @@ int HttpCache::Transaction::DoOverwriteCachedResponse() {
if (request_->method == "HEAD") {
// This response is replacing the cached one.
- DoneWritingToEntry(false);
- mode_ = NONE;
- new_response_ = NULL;
+ ReleaseCacheEntry(EntryState::DOOM);
+ new_response_ = nullptr;
return OK;
}
if (handling_206_ && !CanResume(false)) {
// There is no point in storing this resource because it will never be used.
// This may change if we support LOAD_ONLY_FROM_CACHE with sparse entries.
- DoneWritingToEntry(false);
+ ReleaseCacheEntry(EntryState::DOOM);
if (partial_)
partial_->FixResponseHeaders(response_.headers.get(), true);
next_state_ = STATE_PARTIAL_HEADERS_RECEIVED;
@@ -1679,7 +1660,7 @@ int HttpCache::Transaction::DoCacheWriteResponse() {
"422516 HttpCache::Transaction::DoCacheWriteResponse"));
next_state_ = STATE_CACHE_WRITE_RESPONSE_COMPLETE;
- return WriteResponseInfoToEntry(truncated_);
+ return WriteResponseInfoToEntry(truncated_, io_callback_);
}
int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) {
@@ -1775,7 +1756,73 @@ int HttpCache::Transaction::DoCacheReadMetadataComplete(int result) {
return OK;
}
+int HttpCache::Transaction::DoSwitchToNetwork() {
+ DCHECK(entry_);
+ DCHECK(mode_ & WRITE);
+
+ // If the transaction is currently reading from the cache, then it should have
+ // a valid partial state. I.e. only part of the requested resource could be
+ // fulfiled via the cache. If the entire request was being fulfiled via the
+ // cache, the transaction shouldn't be trying to switch to the network at this
+ // point, and mode_ should be READ.
+ DCHECK_IMPLIES(!network_trans_, partial_);
+
+ // The network transaction can be trivially reused if it can promise to
+ // deliver all the bits necessary to fulfil the original request. If so,
+ // abandon the cache entry and continue with a network read.
+ if (network_trans_ && (!partial_ || partial_->IsLastRange())) {
+ next_state_ = STATE_NETWORK_READ;
+ return AbandonCacheEntry(io_callback_);
+ }
+
+ if (request_->method != "GET") {
+ // We have a non-GET request that the cache or network can partially fulfil.
+ // In other words, at some point the transaction is going to have to issue a
+ // partial network request to fulfil this non-GET request. Let's just ignore
+ // the StopCaching() directive for now.
+ stopped_caching_ = false;
+ next_state_ = network_trans_ ? STATE_NETWORK_READ : STATE_CACHE_READ_DATA;
+ return OK;
+ }
+
+ // The existing network transaction doesn't cover the entire range we wanted.
+ // Let's discard the network transaction and create a new one that will cover
+ // the entire range we need.
+ if (network_trans_)
+ ResetNetworkTransaction();
+
+ if (!partial_->SkipCacheForRemainder()) {
+ // PartialData only refuses to switch to network reads if the entire
+ // resource has been accounted for. There's nothing more to do.
+ return OK;
+ }
+
+ // The new network request that's going to be issued has to be validated
+ // against the existing cache entry. By extension, this also validates the new
+ // request against the portion that has already been sent to our client.
+ partial_->PrepareCacheValidation(entry_->disk_entry,
+ &custom_request_->extra_headers);
+
+ // Since we called SkipCacheForRemainder(), the partial_ state should now
+ // assume that the remainder of the resource is not cached.
+ DCHECK(!partial_->IsCurrentRangeCached());
+ DCHECK(partial_->IsLastRange());
+
+ // READ shouldn't reach here at all. WRITE/UPDATE require a network_trans_
+ // that spans the entire request range and is handled at the top of this
+ // function. At this point we should be left with just READ_WRITE.
+ DCHECK_EQ(mode_, READ_WRITE);
+
+ // Start validating the cache. DoSuccessfulSendRequest() will now bear the
+ // responsibility of abandoning the cache entry if the new network transaction
+ // is successfully validated.
+ return BeginCacheValidation();
+}
+
int HttpCache::Transaction::DoNetworkRead() {
+ DCHECK_GT(read_buf_len_, 0);
+
+ io_buf_len_ = read_buf_len_;
next_state_ = STATE_NETWORK_READ_COMPLETE;
return network_trans_->Read(read_buf_.get(), io_buf_len_, io_callback_);
}
@@ -1796,11 +1843,14 @@ int HttpCache::Transaction::DoNetworkReadComplete(int result) {
}
int HttpCache::Transaction::DoCacheReadData() {
+ DCHECK_GT(read_buf_len_, 0);
+
if (request_->method == "HEAD")
return 0;
DCHECK(entry_);
next_state_ = STATE_CACHE_READ_DATA_COMPLETE;
+ io_buf_len_ = read_buf_len_;
if (net_log_.IsCapturing())
net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_DATA);
@@ -1830,15 +1880,13 @@ int HttpCache::Transaction::DoCacheReadDataComplete(int result) {
return DoPartialCacheReadCompleted(result);
}
- if (result > 0) {
- read_offset_ += result;
- } else if (result == 0) { // End of file.
- RecordHistograms();
- cache_->DoneReadingFromEntry(entry_, this);
- entry_ = NULL;
- } else {
+ if (result < 0)
return OnCacheReadError(result, false);
- }
+
+ if (result == 0)
+ ReleaseCacheEntry(EntryState::KEEP);
+
+ read_offset_ += result;
return result;
}
@@ -1859,22 +1907,27 @@ int HttpCache::Transaction::DoCacheWriteData(int num_bytes) {
}
int HttpCache::Transaction::DoCacheWriteDataComplete(int result) {
- if (entry_) {
- if (net_log_.IsCapturing()) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_DATA,
- result);
- }
+ if (entry_ && net_log_.IsCapturing()) {
+ net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_DATA,
+ result);
}
+
if (!cache_.get())
return ERR_UNEXPECTED;
if (result != write_len_) {
DLOG(ERROR) << "failed to write response data to cache";
- DoneWritingToEntry(false);
+ ReleaseCacheEntry(EntryState::DOOM);
// We want to ignore errors writing to disk and just keep reading from
// the network.
result = write_len_;
+
+ // TODO(asanka): More needs to be done to ignore the error and keep reading
+ // from the network. E.g. if the cache entry was sparse, it is possible that
+ // the current network_trans_ can't fulfil the entire requested range.
+ // Consider setting up state to perform an immediate STATE_SWITCH_TO_NETWORK
+ // at the next Read() instead of releasing the entry now.
} else if (!done_reading_ && entry_ && (!partial_ || truncated_)) {
int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex);
int64 body_size = response_.headers->GetContentLength();
@@ -1883,34 +1936,53 @@ int HttpCache::Transaction::DoCacheWriteDataComplete(int result) {
}
if (partial_) {
- // This may be the last request.
- if (result != 0 || truncated_ ||
- !(partial_->IsLastRange() || mode_ == WRITE)) {
+ // The transaction needs to update partial state under the following
+ // circumstances:
+ const bool need_to_update_partial_state =
+ // Still reading. The partial state needs to be updated to account for
+ // the data read so far.
+ result != 0 ||
+
+ // Reached the end of one network request, but more transactions may be
+ // necessary to fulfil the request. DoPartialNetworkReadCompleted()
+ // initiates additional network transactions as needed.
+ truncated_ ||
+
+ // If this isn't the last range, then more network transactions may be
+ // necessary. But skip this step for new cache entries (mode_ == WRITE).
+ // Range requests with new cache entries will have
+ // partial_->IsLastRange() set to false. IsLastRange() is only set to
+ // true when validating the last range of an existing cache entry.
+ (!partial_->IsLastRange() && mode_ != WRITE);
+
+ if (need_to_update_partial_state)
return DoPartialNetworkReadCompleted(result);
- }
}
if (result == 0) {
- // End of file. This may be the result of a connection problem so see if we
- // have to keep the entry around to be flagged as truncated later on.
- if (done_reading_ || !entry_ || partial_ ||
- response_.headers->GetContentLength() <= 0) {
- DoneWritingToEntry(true);
+ // If the entire response body was successfully read, then the transaction
+ // should release the cache entry.
+ //
+ // While response == 0 typically indicates EOF, it is possible for that to
+ // happen due to a connection problem. In the latter case the resulting
rvargas (doing something else) 2015/09/21 22:06:00 tiny nit: maybe remove "the resulting" and "call"
+ // AbandonCacheEntry() call marks the cache entry as truncated.
+ //
+ // A succesful receipt of the response body is considered to be indicated by
+ // one of:
+ // * done_reading_ : Received response body was of expected size.
+ // * Content-Length <= 0 : Response body size was not known.
+ // * partial_ :
+ if (entry_ && (done_reading_ || partial_ ||
+ response_.headers->GetContentLength() <= 0)) {
+ ReleaseCacheEntry(EntryState::KEEP);
+ } else {
+ AbandonCacheEntry(CompletionCallback());
}
}
return result;
}
-int HttpCache::Transaction::DoCacheWriteTruncatedResponse() {
- next_state_ = STATE_CACHE_WRITE_TRUNCATED_RESPONSE_COMPLETE;
- return WriteResponseInfoToEntry(true);
-}
-
-int HttpCache::Transaction::DoCacheWriteTruncatedResponseComplete(int result) {
- return OnWriteResponseInfoToEntryComplete(result);
-}
-
//-----------------------------------------------------------------------------
void HttpCache::Transaction::ReadCertChain() {
@@ -2168,6 +2240,11 @@ int HttpCache::Transaction::BeginCacheValidation() {
// know we won't be falling back to using the cache entry in the
// LOAD_FROM_CACHE_IF_OFFLINE case.
if (!ConditionalizeRequest()) {
+ // Conditionalization should only depend on the state of the cache prior
+ // to starting the request and the request method. Failure is unexpected
+ // after the client has started reading the stream.
+ DCHECK(!reading_);
+
couldnt_conditionalize_request_ = true;
UpdateTransactionPattern(PATTERN_ENTRY_CANT_CONDITIONALIZE);
if (partial_)
@@ -2246,7 +2323,7 @@ int HttpCache::Transaction::BeginExternallyConditionalizedRequest() {
// The externally conditionalized request is not a validation request
// for our existing cache entry. Proceed with caching disabled.
UpdateTransactionPattern(PATTERN_NOT_COVERED);
- DoneWritingToEntry(true);
+ ReleaseCacheEntry(EntryState::KEEP);
}
}
@@ -2574,14 +2651,8 @@ void HttpCache::Transaction::IgnoreRangeRequest() {
// using the cache and see what happens. Most likely this is the first
// response from the server (it's not changing its mind midway, right?).
UpdateTransactionPattern(PATTERN_NOT_COVERED);
- if (mode_ & WRITE)
- DoneWritingToEntry(mode_ != WRITE);
- else if (mode_ & READ && entry_)
- cache_->DoneReadingFromEntry(entry_, this);
-
- partial_.reset(NULL);
- entry_ = NULL;
- mode_ = NONE;
+ ReleaseCacheEntry(mode_ == WRITE ? EntryState::DOOM : EntryState::KEEP);
+ partial_.reset();
}
void HttpCache::Transaction::FixHeadersForHead() {
@@ -2631,7 +2702,9 @@ int HttpCache::Transaction::WriteToEntry(int index, int offset,
return rv;
}
-int HttpCache::Transaction::WriteResponseInfoToEntry(bool truncated) {
+int HttpCache::Transaction::WriteResponseInfoToEntry(
+ bool truncated,
+ const CompletionCallback& callback) {
if (!entry_)
return OK;
@@ -2649,7 +2722,7 @@ int HttpCache::Transaction::WriteResponseInfoToEntry(bool truncated) {
// status to a net error and replay the net error.
if ((response_.headers->HasHeaderValue("cache-control", "no-store")) ||
IsCertStatusError(response_.ssl_info.cert_status)) {
- DoneWritingToEntry(false);
+ ReleaseCacheEntry(EntryState::DOOM);
if (net_log_.IsCapturing())
net_log_.EndEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO);
return OK;
@@ -2670,7 +2743,7 @@ int HttpCache::Transaction::WriteResponseInfoToEntry(bool truncated) {
io_buf_len_ = data->pickle()->size();
return entry_->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(),
- io_buf_len_, io_callback_, true);
+ io_buf_len_, callback, true);
}
int HttpCache::Transaction::OnWriteResponseInfoToEntryComplete(int result) {
@@ -2683,20 +2756,18 @@ int HttpCache::Transaction::OnWriteResponseInfoToEntryComplete(int result) {
if (result != io_buf_len_) {
DLOG(ERROR) << "failed to write response info to cache";
- DoneWritingToEntry(false);
+ ReleaseCacheEntry(EntryState::DOOM);
}
return OK;
}
-void HttpCache::Transaction::DoneWritingToEntry(bool success) {
- if (!entry_)
+void HttpCache::Transaction::ReleaseCacheEntry(EntryState entry_state) {
+ if (!cache_ || !entry_)
return;
- RecordHistograms();
-
- cache_->DoneWritingToEntry(entry_, success);
- entry_ = NULL;
- mode_ = NONE; // switch to 'pass through' mode
+ cache_->DoneWithEntry(entry_, this, entry_state);
+ entry_ = nullptr;
+ mode_ = NONE;
}
int HttpCache::Transaction::OnCacheReadError(int result, bool restart) {
@@ -2717,8 +2788,7 @@ int HttpCache::Transaction::OnCacheReadError(int result, bool restart) {
if (restart) {
DCHECK(!reading_);
DCHECK(!network_trans_.get());
- cache_->DoneWithEntry(entry_, this, false);
- entry_ = NULL;
+ ReleaseCacheEntry(EntryState::DOOM);
is_sparse_ = false;
partial_.reset();
next_state_ = STATE_GET_BACKEND;
@@ -2743,14 +2813,11 @@ void HttpCache::Transaction::OnAddToEntryTimeout(base::TimeTicks start_time) {
void HttpCache::Transaction::DoomPartialEntry(bool delete_object) {
DVLOG(2) << "DoomPartialEntry";
- int rv = cache_->DoomEntry(cache_key_, NULL);
- DCHECK_EQ(OK, rv);
- cache_->DoneWithEntry(entry_, this, false);
- entry_ = NULL;
+ ReleaseCacheEntry(EntryState::DOOM);
is_sparse_ = false;
truncated_ = false;
if (delete_object)
- partial_.reset(NULL);
+ partial_.reset();
}
int HttpCache::Transaction::DoPartialNetworkReadCompleted(int result) {
@@ -2782,8 +2849,8 @@ int HttpCache::Transaction::DoRestartPartialRequest() {
// WRITE + Doom + STATE_INIT_ENTRY == STATE_CREATE_ENTRY (without an attempt
// to Doom the entry again).
- mode_ = WRITE;
ResetPartialState(!range_requested_);
+ mode_ = WRITE;
next_state_ = STATE_CREATE_ENTRY;
return OK;
}
@@ -2859,14 +2926,14 @@ void HttpCache::Transaction::UpdateTransactionPattern(
}
void HttpCache::Transaction::RecordHistograms() {
- DCHECK_NE(PATTERN_UNDEFINED, transaction_pattern_);
- if (!cache_.get() || !cache_->GetCurrentBackend() ||
+ if (transaction_pattern_ == PATTERN_UNDEFINED || !cache_.get() ||
+ !cache_->GetCurrentBackend() ||
cache_->GetCurrentBackend()->GetCacheType() != DISK_CACHE ||
cache_->mode() != NORMAL || request_->method != "GET") {
return;
}
- UMA_HISTOGRAM_ENUMERATION(
- "HttpCache.Pattern", transaction_pattern_, PATTERN_MAX);
+ UMA_HISTOGRAM_ENUMERATION("HttpCache.Pattern", transaction_pattern_,
+ PATTERN_MAX);
if (transaction_pattern_ == PATTERN_NOT_COVERED)
return;
DCHECK(!range_requested_);
@@ -2940,4 +3007,58 @@ void HttpCache::Transaction::OnIOComplete(int result) {
DoLoop(result);
}
+int HttpCache::Transaction::AbandonCacheEntry(
+ const CompletionCallback& callback) {
+ DCHECK(abandon_cache_entry_callback_.is_null());
+ // Is the cache entry is sparse or if the entry is complete? Then the entry
rvargas (doing something else) 2015/09/21 22:06:00 needs some rewording :). I guess you were going fo
+ // doesn't need to be marked as truncated.
+ //
+ // * done_reading_: All pertinent response data has been written.
+ // * !(mode_ & WRITE): This transaction wasn't writing to the entry. Leave
+ // it be.
+ // * is_sparse_: Pre-existing sparse entry.
+ // * (partial_ && !truncated_): New sparse entry.
+ if (done_reading_ || !(mode_ & WRITE) || is_sparse_ ||
+ (partial_ && !truncated_)) {
+ ReleaseCacheEntry(EntryState::KEEP);
+ return OK;
+ }
+
+ // If the caller hasn't started reading (implies that no response data was
+ // written) or if the request can't be resumed, then another transaction is
+ // unlikely to be able to use a partial cache entry for this request.
+ if (!reading_ || !CanResume(true)) {
+ ReleaseCacheEntry(EntryState::DOOM);
+ return OK;
+ }
+
+ // If we get here, the cache entry only contains part of the response and can
+ // be resumed in the future. Mark it as truncated so it'll be handled
+ // correctly.
+ // TODO(asanka): Let's get rid of a persistent truncated flag and make it
+ // implicit based on what we find in the cache the next time the entry is
+ // opened.
+ truncated_ = true;
+ int result = WriteResponseInfoToEntry(
+ true, base::Bind(&HttpCache::Transaction::OnAbandonCacheEntryIOComplete,
+ weak_factory_.GetWeakPtr()));
+ if (result < 0 && result != ERR_IO_PENDING)
+ return result;
+
+ if (callback.is_null()) {
+ ReleaseCacheEntry(EntryState::KEEP);
+ return OK;
+ }
+
+ abandon_cache_entry_callback_ = callback;
+ return result;
+}
+
+void HttpCache::Transaction::OnAbandonCacheEntryIOComplete(int result) {
+ result = OnWriteResponseInfoToEntryComplete(result);
+ ReleaseCacheEntry(EntryState::KEEP);
+ if (!abandon_cache_entry_callback_.is_null())
+ base::ResetAndReturn(&abandon_cache_entry_callback_).Run(result);
+}
+
} // namespace net

Powered by Google App Engine
This is Rietveld 408576698