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 |