Index: net/http/http_cache_transaction.cc |
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc |
index 518944650747e6a3dc7f39c58b4b4d7cb1610758..e44e165ea69fdc37e1d478fcaabbe292ae8ce7ac 100644 |
--- a/net/http/http_cache_transaction.cc |
+++ b/net/http/http_cache_transaction.cc |
@@ -196,16 +196,7 @@ HttpCache::Transaction::~Transaction() { |
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); |
- } |
- } |
- |
- cache_->DoneWithEntry(entry_, this, cancel_request); |
+ cache_->DoneWithEntry(entry_, this, true, partial_ != nullptr); |
jkarlin
2017/05/30 14:42:38
Yay for this cleanup!
|
} else if (cache_pending_) { |
cache_->RemovePendingTransaction(this); |
} |
@@ -451,7 +442,7 @@ void HttpCache::Transaction::DoneReading() { |
// 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); |
+ cache_->DoneWithEntry(entry_, this, false, partial_ != nullptr); |
entry_ = NULL; |
} |
} |
@@ -565,6 +556,12 @@ void HttpCache::Transaction::GetConnectionAttempts( |
old_connection_attempts_.end()); |
} |
+void HttpCache::Transaction::SetValidatingCannotProceed() { |
+ DCHECK(!reading_); |
+ next_state_ = STATE_HEADERS_PHASE_CANNOT_PROCEED; |
+ entry_ = nullptr; |
+} |
+ |
size_t HttpCache::Transaction::EstimateMemoryUsage() const { |
// TODO(xunjieli): Consider improving the coverage. crbug.com/669108. |
return 0; |
@@ -579,7 +576,7 @@ size_t HttpCache::Transaction::EstimateMemoryUsage() const { |
// GetBackend* -> InitEntry -> OpenEntry* -> CreateEntry* -> AddToEntry* -> |
// SendRequest* -> SuccessfulSendRequest -> OverwriteCachedResponse -> |
// CacheWriteResponse* -> TruncateCachedData* -> TruncateCachedMetadata* -> |
-// PartialHeadersReceived |
+// PartialHeadersReceived -> FinishHeaders* |
// |
// Read(): |
// NetworkRead* -> CacheWriteData* |
@@ -588,7 +585,7 @@ size_t HttpCache::Transaction::EstimateMemoryUsage() const { |
// Start(): |
// GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse* |
// -> CacheDispatchValidation -> BeginPartialCacheValidation() -> |
-// BeginCacheValidation() -> SetupEntryForRead() |
+// BeginCacheValidation() -> SetupEntryForRead() -> FinishHeaders* |
// |
// Read(): |
// CacheReadData* |
@@ -600,7 +597,7 @@ size_t HttpCache::Transaction::EstimateMemoryUsage() const { |
// BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest -> |
// UpdateCachedResponse -> CacheWriteUpdatedResponse* -> |
// UpdateCachedResponseComplete -> OverwriteCachedResponse -> |
-// PartialHeadersReceived |
+// PartialHeadersReceived -> FinishHeaders* |
// |
// Read(): |
// CacheReadData* |
@@ -611,7 +608,7 @@ size_t HttpCache::Transaction::EstimateMemoryUsage() const { |
// -> CacheDispatchValidation -> BeginPartialCacheValidation() -> |
// BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest -> |
// OverwriteCachedResponse -> CacheWriteResponse* -> DoTruncateCachedData* -> |
-// TruncateCachedMetadata* -> PartialHeadersReceived |
+// TruncateCachedMetadata* -> PartialHeadersReceived -> FinishHeaders* |
// |
// Read(): |
// NetworkRead* -> CacheWriteData* |
@@ -625,7 +622,7 @@ size_t HttpCache::Transaction::EstimateMemoryUsage() const { |
// BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest -> |
// UpdateCachedResponse -> CacheWriteUpdatedResponse* -> |
// UpdateCachedResponseComplete -> OverwriteCachedResponse -> |
-// PartialHeadersReceived |
+// PartialHeadersReceived -> FinishHeaders* |
// |
// Read() 1: |
// NetworkRead* -> CacheWriteData* |
@@ -666,7 +663,7 @@ size_t HttpCache::Transaction::EstimateMemoryUsage() const { |
// GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse* |
// -> CacheDispatchValidation -> BeginPartialCacheValidation() -> |
// BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest -> |
-// OverwriteCachedResponse |
+// OverwriteCachedResponse -> FinishHeaders* |
// |
// 10. HEAD. Sparse entry, partially cached: |
// Serve the request from the cache, as long as it doesn't require |
@@ -691,7 +688,7 @@ size_t HttpCache::Transaction::EstimateMemoryUsage() const { |
// GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse* |
// -> CacheToggleUnusedSincePrefetch* -> CacheDispatchValidation -> |
// BeginPartialCacheValidation() -> BeginCacheValidation() -> |
-// SetupEntryForRead() |
+// SetupEntryForRead() -> FinishHeaders* |
// |
// Read(): |
// CacheReadData* |
@@ -705,8 +702,9 @@ int HttpCache::Transaction::DoLoop(int result) { |
DCHECK(!in_do_loop_); |
int rv = result; |
+ State state = next_state_; |
do { |
- State state = next_state_; |
+ state = next_state_; |
next_state_ = STATE_UNSET; |
base::AutoReset<bool> scoped_in_do_loop(&in_do_loop_, true); |
@@ -843,6 +841,15 @@ int HttpCache::Transaction::DoLoop(int result) { |
case STATE_CACHE_READ_METADATA_COMPLETE: |
rv = DoCacheReadMetadataComplete(rv); |
break; |
+ case STATE_HEADERS_PHASE_CANNOT_PROCEED: |
+ rv = DoHeadersPhaseCannotProceed(); |
+ break; |
+ case STATE_FINISH_HEADERS: |
+ rv = DoFinishHeaders(rv); |
+ break; |
+ case STATE_FINISH_HEADERS_COMPLETE: |
+ rv = DoFinishHeadersComplete(rv); |
+ break; |
case STATE_NETWORK_READ: |
DCHECK_EQ(OK, rv); |
rv = DoNetworkRead(); |
@@ -879,8 +886,13 @@ int HttpCache::Transaction::DoLoop(int result) { |
} while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); |
+ // Assert Start() state machine's allowed last state in successful cases when |
+ // caching is happening. |
+ DCHECK(reading_ || rv != OK || !entry_ || |
+ state == STATE_FINISH_HEADERS_COMPLETE); |
+ |
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. |
base::ResetAndReturn(&callback_).Run(rv); |
} |
@@ -907,7 +919,7 @@ int HttpCache::Transaction::DoGetBackendComplete(int result) { |
if (effective_load_flags_ & LOAD_ONLY_FROM_CACHE) { |
if (effective_load_flags_ & LOAD_BYPASS_CACHE) { |
// The client has asked for nonsense. |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return ERR_CACHE_MISS; |
} |
mode_ = READ; |
@@ -930,8 +942,8 @@ int HttpCache::Transaction::DoGetBackendComplete(int result) { |
} |
// Use PUT and DELETE only to invalidate existing stored entries. |
- if ((request_->method == "PUT" || request_->method == "DELETE") && |
- mode_ != READ_WRITE && mode_ != WRITE) { |
+ if ((method_ == "PUT" || method_ == "DELETE") && mode_ != READ_WRITE && |
+ mode_ != WRITE) { |
mode_ = NONE; |
} |
@@ -940,13 +952,13 @@ int HttpCache::Transaction::DoGetBackendComplete(int result) { |
// was not modified, the entry is updated and a response is not returned from |
// the cache. If we receive 200, it doesn't matter if there was a validation |
// header or not. |
- if (request_->method == "HEAD" && mode_ == WRITE) |
+ if (method_ == "HEAD" && mode_ == WRITE) |
mode_ = NONE; |
// If must use cache, then we must fail. This can happen for back/forward |
// navigations to a page generated via a form post. |
if (!(mode_ & READ) && effective_load_flags_ & LOAD_ONLY_FROM_CACHE) { |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return ERR_CACHE_MISS; |
} |
@@ -963,6 +975,9 @@ int HttpCache::Transaction::DoGetBackendComplete(int result) { |
// This is only set if we have something to do with the response. |
range_requested_ = (partial_.get() != NULL); |
+ // mode_ may change later, save the initial mode in case we need to restart |
+ // this request. |
+ restart_info_.mode = mode_; |
return OK; |
} |
@@ -971,7 +986,7 @@ int HttpCache::Transaction::DoInitEntry() { |
DCHECK(!new_entry_); |
if (!cache_.get()) { |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return ERR_UNEXPECTED; |
} |
@@ -1008,13 +1023,13 @@ int HttpCache::Transaction::DoOpenEntryComplete(int result) { |
} |
if (result == ERR_CACHE_RACE) { |
- TransitionToState(STATE_INIT_ENTRY); |
+ TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED); |
return OK; |
} |
- if (request_->method == "PUT" || request_->method == "DELETE" || |
- (request_->method == "HEAD" && mode_ == READ_WRITE)) { |
- DCHECK(mode_ == READ_WRITE || mode_ == WRITE || request_->method == "HEAD"); |
+ if (method_ == "PUT" || method_ == "DELETE" || |
+ (method_ == "HEAD" && mode_ == READ_WRITE)) { |
+ DCHECK(mode_ == READ_WRITE || mode_ == WRITE || method_ == "HEAD"); |
mode_ = NONE; |
TransitionToState(STATE_SEND_REQUEST); |
return OK; |
@@ -1034,7 +1049,7 @@ int HttpCache::Transaction::DoOpenEntryComplete(int result) { |
// The entry does not exist, and we are not permitted to create a new entry, |
// so we must fail. |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return ERR_CACHE_MISS; |
} |
@@ -1053,8 +1068,9 @@ int HttpCache::Transaction::DoDoomEntryComplete(int result) { |
net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_DOOM_ENTRY, |
result); |
cache_pending_ = false; |
- TransitionToState(result == ERR_CACHE_RACE ? STATE_INIT_ENTRY |
- : STATE_CREATE_ENTRY); |
+ TransitionToState(result == ERR_CACHE_RACE |
+ ? STATE_HEADERS_PHASE_CANNOT_PROCEED |
+ : STATE_CREATE_ENTRY); |
return OK; |
} |
@@ -1081,7 +1097,7 @@ int HttpCache::Transaction::DoCreateEntryComplete(int result) { |
break; |
case ERR_CACHE_RACE: |
- TransitionToState(STATE_INIT_ENTRY); |
+ TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED); |
break; |
default: |
@@ -1162,13 +1178,13 @@ int HttpCache::Transaction::DoAddToEntryComplete(int result) { |
new_entry_ = NULL; |
if (result == ERR_CACHE_RACE) { |
- TransitionToState(STATE_INIT_ENTRY); |
+ TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED); |
return OK; |
} |
if (result == ERR_CACHE_LOCK_TIMEOUT) { |
if (mode_ == READ) { |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return ERR_CACHE_MISS; |
} |
@@ -1182,12 +1198,16 @@ int HttpCache::Transaction::DoAddToEntryComplete(int result) { |
return OK; |
} |
- open_entry_last_used_ = entry_->disk_entry->GetLastUsed(); |
+ // TODO(crbug.com/713354) Access timestamp for histograms only if entry is |
+ // already written, to avoid data race since cache thread can also access |
+ // this. |
+ if (!cache_->IsWritingInProgress(entry_)) |
+ open_entry_last_used_ = entry_->disk_entry->GetLastUsed(); |
// TODO(jkarlin): We should either handle the case or DCHECK. |
if (result != OK) { |
NOTREACHED(); |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return result; |
} |
@@ -1226,29 +1246,37 @@ int HttpCache::Transaction::DoCacheReadResponseComplete(int result) { |
return OnCacheReadError(result, true); |
} |
- int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex); |
- int64_t full_response_length = response_.headers->GetContentLength(); |
- |
- // Some resources may have slipped in as truncated when they're not. |
- if (full_response_length == current_size) |
- truncated_ = false; |
- |
- // The state machine's handling of StopCaching unfortunately doesn't deal well |
- // with resources that are larger than 2GB when there is a truncated or sparse |
- // cache entry. While the state machine is reworked to resolve this, the |
- // following logic is put in place to defer such requests to the network. The |
- // cache should not be storing multi gigabyte resources. See |
- // http://crbug.com/89567. |
- if ((truncated_ || response_.headers->response_code() == 206) && |
- !range_requested_ && |
- full_response_length > std::numeric_limits<int32_t>::max()) { |
- // Does not release the cache entry. If another transaction wants to use |
- // this cache entry while this transaction is active, the second transaction |
- // will fall back to the network after the timeout. |
- DCHECK(!partial_); |
- mode_ = NONE; |
- TransitionToState(STATE_SEND_REQUEST); |
- return OK; |
+ // TODO(crbug.com/713354) Only get data size if there is no other transaction |
+ // currently writing the response body due to the data race mentioned in the |
+ // associated bug. |
+ if (!cache_->IsWritingInProgress(entry_)) { |
+ int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex); |
+ int64_t full_response_length = response_.headers->GetContentLength(); |
+ |
+ // Some resources may have slipped in as truncated when they're not. |
+ if (full_response_length == current_size) |
+ truncated_ = false; |
+ |
+ // The state machine's handling of StopCaching unfortunately doesn't deal |
+ // well with resources that are larger than 2GB when there is a truncated or |
+ // sparse cache entry. While the state machine is reworked to resolve this, |
+ // the following logic is put in place to defer such requests to the |
+ // network. The cache should not be storing multi gigabyte resources. See |
+ // http://crbug.com/89567. |
+ if ((truncated_ || response_.headers->response_code() == 206) && |
+ !range_requested_ && |
+ full_response_length > std::numeric_limits<int32_t>::max()) { |
+ DCHECK(!partial_); |
+ |
+ // Doom the entry so that no other transaction gets added to this entry |
+ // and avoid a race of not being able to check this condition because |
+ // writing is in progress. |
+ cache_->DoneWritingToEntry(entry_, false, this); |
+ entry_ = nullptr; |
+ mode_ = NONE; |
+ TransitionToState(STATE_SEND_REQUEST); |
+ return OK; |
+ } |
} |
if (response_.unused_since_prefetch != |
@@ -1330,7 +1358,7 @@ int HttpCache::Transaction::DoCacheQueryData() { |
int HttpCache::Transaction::DoCacheQueryDataComplete(int result) { |
DCHECK_EQ(OK, result); |
if (!cache_.get()) { |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return ERR_UNEXPECTED; |
} |
@@ -1340,7 +1368,7 @@ int HttpCache::Transaction::DoCacheQueryDataComplete(int result) { |
// We may end up here multiple times for a given request. |
int HttpCache::Transaction::DoStartPartialCacheValidation() { |
if (mode_ == NONE) { |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return OK; |
} |
@@ -1354,15 +1382,15 @@ int HttpCache::Transaction::DoCompletePartialCacheValidation(int result) { |
if (mode_ & WRITE) { |
DoneWritingToEntry(true); |
} else { |
- cache_->DoneReadingFromEntry(entry_, this); |
+ cache_->DoneWithEntry(entry_, this, false, partial_ != nullptr); |
entry_ = NULL; |
} |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return result; |
} |
if (result < 0) { |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return result; |
} |
@@ -1388,7 +1416,7 @@ int HttpCache::Transaction::DoSendRequest() { |
int rv = |
cache_->network_layer_->CreateTransaction(priority_, &network_trans_); |
if (rv != OK) { |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return rv; |
} |
network_trans_->SetBeforeNetworkStartCallback(before_network_start_callback_); |
@@ -1410,7 +1438,7 @@ int HttpCache::Transaction::DoSendRequest() { |
int HttpCache::Transaction::DoSendRequestComplete(int result) { |
TRACE_EVENT0("io", "HttpCacheTransaction::DoSendRequestComplete"); |
if (!cache_.get()) { |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return ERR_UNEXPECTED; |
} |
@@ -1441,7 +1469,7 @@ int HttpCache::Transaction::DoSendRequestComplete(int result) { |
DoneWritingToEntry(true); |
} |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return result; |
} |
@@ -1455,7 +1483,7 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() { |
new_response->headers->response_code() == 407) { |
SetAuthResponse(*new_response); |
if (!reading_) { |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return OK; |
} |
@@ -1480,7 +1508,7 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() { |
mode_ = NONE; |
partial_.reset(); |
ResetNetworkTransaction(); |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return ERR_CACHE_AUTH_FAILURE_AFTER_READ; |
} |
@@ -1512,20 +1540,18 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() { |
} |
// Invalidate any cached GET with a successful PUT or DELETE. |
- if (mode_ == WRITE && |
- (request_->method == "PUT" || request_->method == "DELETE")) { |
+ if (mode_ == WRITE && (method_ == "PUT" || method_ == "DELETE")) { |
if (NonErrorResponse(new_response->headers->response_code())) { |
int ret = cache_->DoomEntry(cache_key_, NULL); |
DCHECK_EQ(OK, ret); |
} |
- cache_->DoneWritingToEntry(entry_, true); |
+ cache_->DoneWritingToEntry(entry_, true, this); |
entry_ = NULL; |
mode_ = NONE; |
} |
// Invalidate any cached GET with a successful POST. |
- if (!(effective_load_flags_ & LOAD_DISABLE_CACHE) && |
- request_->method == "POST" && |
+ if (!(effective_load_flags_ & LOAD_DISABLE_CACHE) && method_ == "POST" && |
NonErrorResponse(new_response->headers->response_code())) { |
cache_->DoomMainEntryForUrl(request_->url); |
} |
@@ -1533,10 +1559,10 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() { |
RecordNoStoreHeaderHistogram(request_->load_flags, new_response); |
if (new_response_->headers->response_code() == 416 && |
- (request_->method == "GET" || request_->method == "POST")) { |
+ (method_ == "GET" || method_ == "POST")) { |
// If there is an active entry it may be destroyed with this transaction. |
SetResponse(*new_response_); |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return OK; |
} |
@@ -1624,7 +1650,6 @@ int HttpCache::Transaction::DoUpdateCachedResponseComplete(int result) { |
} else if (entry_ && !handling_206_) { |
DCHECK_EQ(READ_WRITE, mode_); |
if (!partial_ || partial_->IsLastRange()) { |
- cache_->ConvertWriterToReader(entry_); |
mode_ = READ; |
} |
// We no longer need the network transaction, so destroy it. |
@@ -1657,12 +1682,12 @@ int HttpCache::Transaction::DoOverwriteCachedResponse() { |
SetResponse(*new_response_); |
- if (request_->method == "HEAD") { |
+ if (method_ == "HEAD") { |
// This response is replacing the cached one. |
DoneWritingToEntry(false); |
mode_ = NONE; |
new_response_ = NULL; |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return OK; |
} |
@@ -1683,6 +1708,19 @@ int HttpCache::Transaction::DoOverwriteCachedResponse() { |
int HttpCache::Transaction::DoCacheWriteResponse() { |
TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheWriteResponse"); |
TransitionToState(STATE_CACHE_WRITE_RESPONSE_COMPLETE); |
+ |
+ // Invalidate any current entry with a successful response if this transaction |
+ // cannot write to this entry. This transaction then continues to read from |
+ // the network without writing to the backend. |
+ bool is_match = response_.headers->response_code() == 304; |
+ if (entry_ && response_.headers && |
+ !cache_->CanTransactionWriteResponseHeaders(entry_, this, is_match)) { |
+ cache_->DoneWritingToEntry(entry_, false, this); |
+ entry_ = nullptr; |
+ mode_ = NONE; |
+ return OK; |
+ } |
+ |
return WriteResponseInfoToEntry(truncated_); |
} |
@@ -1744,10 +1782,12 @@ int HttpCache::Transaction::DoPartialHeadersReceived() { |
new_response_ = NULL; |
if (!partial_) { |
- if (entry_ && entry_->disk_entry->GetDataSize(kMetadataIndex)) |
+ if (entry_ && entry_->disk_entry->GetDataSize(kMetadataIndex)) { |
TransitionToState(STATE_CACHE_READ_METADATA); |
- else |
- TransitionToState(STATE_NONE); |
+ } else { |
+ DCHECK(!reading_); |
+ TransitionToState(STATE_FINISH_HEADERS); |
+ } |
return OK; |
} |
@@ -1761,13 +1801,59 @@ int HttpCache::Transaction::DoPartialHeadersReceived() { |
// We are about to return the headers for a byte-range request to the user, |
// so let's fix them. |
partial_->FixResponseHeaders(response_.headers.get(), true); |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
} else { |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
} |
return OK; |
} |
+int HttpCache::Transaction::DoHeadersPhaseCannotProceed() { |
+ // If its the Start state machine and it cannot proceed due to a cache |
+ // failure, restart this transaction. |
+ DCHECK(!reading_); |
+ TransitionToState(STATE_INIT_ENTRY); |
+ cache_entry_status_ = restart_info_.cache_entry_status; |
+ entry_ = nullptr; |
+ mode_ = restart_info_.mode; |
+ if (network_trans_) |
+ network_trans_.reset(); |
+ |
+ return OK; |
+} |
+ |
+int HttpCache::Transaction::DoFinishHeaders(int result) { |
+ if (!entry_ || result != OK) { |
+ TransitionToState(STATE_NONE); |
+ return result; |
+ } |
+ |
+ TransitionToState(STATE_FINISH_HEADERS_COMPLETE); |
+ |
+ // If it was an auth failure or 416, this transaction should continue to be |
+ // headers_transaction till consumer takes an action, so no need to do |
+ // anything now. |
+ if (auth_response_.headers.get() || |
+ (new_response_ && new_response_->headers && |
+ new_response_->headers->response_code() == 416)) |
+ return OK; |
+ |
+ // If the transaction needs to wait because another transaction is still |
+ // writing the response body, it will return ERR_IO_PENDING now and the |
+ // io_callback_ will be invoked when the wait is done. |
+ return cache_->DoneWithResponseHeaders(entry_, this, partial_ != nullptr); |
+} |
+ |
+int HttpCache::Transaction::DoFinishHeadersComplete(int rv) { |
+ if (rv == ERR_CACHE_RACE) { |
+ TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED); |
+ return OK; |
+ } |
+ |
+ TransitionToState(STATE_NONE); |
+ return rv; |
+} |
+ |
int HttpCache::Transaction::DoCacheReadMetadata() { |
TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheReadMetadata"); |
DCHECK(entry_); |
@@ -1790,7 +1876,8 @@ int HttpCache::Transaction::DoCacheReadMetadataComplete(int result) { |
result); |
if (result != response_.metadata->size()) |
return OnCacheReadError(result, false); |
- TransitionToState(STATE_NONE); |
+ |
+ TransitionToState(STATE_FINISH_HEADERS); |
return OK; |
} |
@@ -1823,7 +1910,7 @@ int HttpCache::Transaction::DoNetworkReadComplete(int result) { |
int HttpCache::Transaction::DoCacheReadData() { |
TRACE_EVENT0("io", "HttpCacheTransaction::DoCacheReadData"); |
- if (request_->method == "HEAD") { |
+ if (method_ == "HEAD") { |
TransitionToState(STATE_NONE); |
return 0; |
} |
@@ -1961,6 +2048,7 @@ void HttpCache::Transaction::SetRequest(const NetLogWithSource& net_log, |
net_log_ = net_log; |
request_ = request; |
effective_load_flags_ = request_->load_flags; |
+ method_ = request_->method; |
if (cache_->mode() == DISABLE) |
effective_load_flags_ |= LOAD_DISABLE_CACHE; |
@@ -2040,7 +2128,7 @@ void HttpCache::Transaction::SetRequest(const NetLogWithSource& net_log, |
if (range_found && !(effective_load_flags_ & LOAD_DISABLE_CACHE)) { |
UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER); |
partial_.reset(new PartialData); |
- if (request_->method == "GET" && partial_->Init(request_->extra_headers)) { |
+ if (method_ == "GET" && partial_->Init(request_->extra_headers)) { |
// We will be modifying the actual range requested to the server, so |
// let's remove the header here. |
custom_request_.reset(new HttpRequestInfo(*request_)); |
@@ -2054,6 +2142,7 @@ void HttpCache::Transaction::SetRequest(const NetLogWithSource& net_log, |
partial_.reset(NULL); |
} |
} |
+ restart_info_.cache_entry_status = cache_entry_status_; |
} |
bool HttpCache::Transaction::ShouldPassThrough() { |
@@ -2065,18 +2154,18 @@ bool HttpCache::Transaction::ShouldPassThrough() { |
if (effective_load_flags_ & LOAD_DISABLE_CACHE) |
return true; |
- if (request_->method == "GET" || request_->method == "HEAD") |
+ if (method_ == "GET" || method_ == "HEAD") |
return false; |
- if (request_->method == "POST" && request_->upload_data_stream && |
+ if (method_ == "POST" && request_->upload_data_stream && |
request_->upload_data_stream->identifier()) { |
return false; |
} |
- if (request_->method == "PUT" && request_->upload_data_stream) |
+ if (method_ == "PUT" && request_->upload_data_stream) |
return false; |
- if (request_->method == "DELETE") |
+ if (method_ == "DELETE") |
return false; |
return true; |
@@ -2087,28 +2176,28 @@ int HttpCache::Transaction::BeginCacheRead() { |
// TODO(jkarlin): Either handle this case or DCHECK. |
if (response_.headers->response_code() == 206 || partial_) { |
NOTREACHED(); |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return ERR_CACHE_MISS; |
} |
// We don't have the whole resource. |
if (truncated_) { |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return ERR_CACHE_MISS; |
} |
if (RequiresValidation()) { |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return ERR_CACHE_MISS; |
} |
- if (request_->method == "HEAD") |
+ if (method_ == "HEAD") |
FixHeadersForHead(); |
if (entry_->disk_entry->GetDataSize(kMetadataIndex)) |
TransitionToState(STATE_CACHE_READ_METADATA); |
else |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return OK; |
} |
@@ -2118,7 +2207,7 @@ int HttpCache::Transaction::BeginCacheValidation() { |
bool skip_validation = !RequiresValidation(); |
- if (request_->method == "HEAD" && |
+ if (method_ == "HEAD" && |
(truncated_ || response_.headers->response_code() == 206)) { |
DCHECK(!partial_); |
if (skip_validation) |
@@ -2176,7 +2265,7 @@ int HttpCache::Transaction::BeginPartialCacheValidation() { |
// Partial requests should not be recorded in histograms. |
UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER); |
- if (request_->method == "HEAD") |
+ if (method_ == "HEAD") |
return BeginCacheValidation(); |
if (!range_requested_) { |
@@ -2314,7 +2403,7 @@ bool HttpCache::Transaction::RequiresValidation() { |
return true; |
} |
- if (request_->method == "PUT" || request_->method == "DELETE") |
+ if (method_ == "PUT" || method_ == "DELETE") |
return true; |
bool validation_required_by_headers = response_.headers->RequiresValidation( |
@@ -2340,7 +2429,7 @@ bool HttpCache::Transaction::RequiresValidation() { |
bool HttpCache::Transaction::ConditionalizeRequest() { |
DCHECK(response_.headers.get()); |
- if (request_->method == "PUT" || request_->method == "DELETE") |
+ if (method_ == "PUT" || method_ == "DELETE") |
return false; |
// This only makes sense for cached 200 or 206 responses. |
@@ -2434,7 +2523,7 @@ bool HttpCache::Transaction::ValidatePartialResponse() { |
bool partial_response = (response_code == 206); |
handling_206_ = false; |
- if (!entry_ || request_->method != "GET") |
+ if (!entry_ || method_ != "GET") |
return true; |
if (invalid_range_) { |
@@ -2541,7 +2630,7 @@ void HttpCache::Transaction::IgnoreRangeRequest() { |
if (mode_ & WRITE) |
DoneWritingToEntry(mode_ != WRITE); |
else if (mode_ & READ && entry_) |
- cache_->DoneReadingFromEntry(entry_, this); |
+ cache_->DoneWithEntry(entry_, this, false, partial_ != nullptr); |
partial_.reset(NULL); |
entry_ = NULL; |
@@ -2568,16 +2657,16 @@ int HttpCache::Transaction::SetupEntryForRead() { |
partial_.reset(); |
} |
} |
- cache_->ConvertWriterToReader(entry_); |
+ |
mode_ = READ; |
- if (request_->method == "HEAD") |
+ if (method_ == "HEAD") |
FixHeadersForHead(); |
if (entry_->disk_entry->GetDataSize(kMetadataIndex)) |
TransitionToState(STATE_CACHE_READ_METADATA); |
else |
- TransitionToState(STATE_NONE); |
+ TransitionToState(STATE_FINISH_HEADERS); |
return OK; |
} |
@@ -2656,7 +2745,7 @@ void HttpCache::Transaction::DoneWritingToEntry(bool success) { |
RecordHistograms(); |
- cache_->DoneWritingToEntry(entry_, success); |
+ cache_->DoneWritingToEntry(entry_, success, this); |
entry_ = NULL; |
mode_ = NONE; // switch to 'pass through' mode |
} |
@@ -2679,7 +2768,7 @@ int HttpCache::Transaction::OnCacheReadError(int result, bool restart) { |
if (restart) { |
DCHECK(!reading_); |
DCHECK(!network_trans_.get()); |
- cache_->DoneWithEntry(entry_, this, false); |
+ cache_->DoneWithEntry(entry_, this, false, partial_ != nullptr); |
entry_ = NULL; |
is_sparse_ = false; |
partial_.reset(); |
@@ -2708,7 +2797,7 @@ 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); |
+ cache_->DoneWithEntry(entry_, this, false, partial_ != nullptr); |
entry_ = NULL; |
is_sparse_ = false; |
truncated_ = false; |
@@ -2804,7 +2893,7 @@ bool HttpCache::Transaction::CanResume(bool has_data) { |
if (has_data && !entry_->disk_entry->GetDataSize(kResponseContentIndex)) |
return false; |
- if (request_->method != "GET") |
+ if (method_ != "GET") |
return false; |
// Note that if this is a 206, content-length was already fixed after calling |
@@ -2853,7 +2942,7 @@ void HttpCache::Transaction::RecordHistograms() { |
DCHECK_NE(CacheEntryStatus::ENTRY_UNDEFINED, cache_entry_status_); |
if (!cache_.get() || !cache_->GetCurrentBackend() || |
cache_->GetCurrentBackend()->GetCacheType() != DISK_CACHE || |
- cache_->mode() != NORMAL || request_->method != "GET") { |
+ cache_->mode() != NORMAL || method_ != "GET") { |
return; |
} |
@@ -2867,10 +2956,14 @@ void HttpCache::Transaction::RecordHistograms() { |
cache_entry_status_ == CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE); |
int64_t freshness_periods_since_last_used = 0; |
- if (stale_request) { |
+ if (stale_request && !open_entry_last_used_.is_null()) { |
+ // Note that we are not able to capture those transactions' histograms which |
+ // when added to entry, the response was being written by another |
+ // transaction because getting the last used timestamp might lead to a data |
+ // race in that case. TODO(crbug.com/713354). |
+ |
// For stale entries, record how many freshness periods have elapsed since |
// the entry was last used. |
- DCHECK(!open_entry_last_used_.is_null()); |
DCHECK(!stale_entry_freshness_.is_zero()); |
base::TimeDelta time_since_use = base::Time::Now() - open_entry_last_used_; |
freshness_periods_since_last_used = |
@@ -2903,7 +2996,7 @@ void HttpCache::Transaction::RecordHistograms() { |
// response header mime type, which could be incorrect, so this is just an |
// estimate. |
if (mime_type == "text/html" && |
- (request_->load_flags & LOAD_MAIN_FRAME_DEPRECATED)) { |
+ (effective_load_flags_ & LOAD_MAIN_FRAME_DEPRECATED)) { |
CACHE_STATUS_HISTOGRAMS(".MainFrameHTML"); |
} else if (mime_type == "text/html") { |
CACHE_STATUS_HISTOGRAMS(".NonMainFrameHTML"); |
@@ -2943,7 +3036,8 @@ void HttpCache::Transaction::RecordHistograms() { |
if (cache_entry_status_ == CacheEntryStatus::ENTRY_OTHER) |
return; |
- DCHECK(!range_requested_); |
+ |
+ DCHECK(!range_requested_) << "Cache entry status " << cache_entry_status_; |
DCHECK(!first_cache_access_since_.is_null()); |
TimeDelta total_time = base::TimeTicks::Now() - first_cache_access_since_; |