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

Unified Diff: net/http/http_cache_transaction.cc

Issue 2721933002: HttpCache::Transaction layer allowing parallel validation (Closed)
Patch Set: DoneReadingFromEntry replaced with DoneWithEntry Created 3 years, 7 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 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_;

Powered by Google App Engine
This is Rietveld 408576698