Index: net/http/http_cache_transaction.cc |
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc |
index f2fcf4cb7c47a5dd60ff53bcb0478b7e47c4238f..eed5d48148fd641b76e71be9e9a98ba5349c5901 100644 |
--- a/net/http/http_cache_transaction.cc |
+++ b/net/http/http_cache_transaction.cc |
@@ -804,24 +804,6 @@ int HttpCache::Transaction::DoLoop(int result) { |
case STATE_GET_BACKEND_COMPLETE: |
rv = DoGetBackendComplete(rv); |
break; |
- case STATE_SEND_REQUEST: |
- DCHECK_EQ(OK, rv); |
- rv = DoSendRequest(); |
- break; |
- case STATE_SEND_REQUEST_COMPLETE: |
- rv = DoSendRequestComplete(rv); |
- break; |
- case STATE_SUCCESSFUL_SEND_REQUEST: |
- DCHECK_EQ(OK, rv); |
- rv = DoSuccessfulSendRequest(); |
- break; |
- case STATE_NETWORK_READ: |
- DCHECK_EQ(OK, rv); |
- rv = DoNetworkRead(); |
- break; |
- case STATE_NETWORK_READ_COMPLETE: |
- rv = DoNetworkReadComplete(rv); |
- break; |
case STATE_INIT_ENTRY: |
DCHECK_EQ(OK, rv); |
rv = DoInitEntry(); |
@@ -833,13 +815,6 @@ int HttpCache::Transaction::DoLoop(int result) { |
case STATE_OPEN_ENTRY_COMPLETE: |
rv = DoOpenEntryComplete(rv); |
break; |
- case STATE_CREATE_ENTRY: |
- DCHECK_EQ(OK, rv); |
- rv = DoCreateEntry(); |
- break; |
- case STATE_CREATE_ENTRY_COMPLETE: |
- rv = DoCreateEntryComplete(rv); |
- break; |
case STATE_DOOM_ENTRY: |
DCHECK_EQ(OK, rv); |
rv = DoDoomEntry(); |
@@ -847,6 +822,13 @@ int HttpCache::Transaction::DoLoop(int result) { |
case STATE_DOOM_ENTRY_COMPLETE: |
rv = DoDoomEntryComplete(rv); |
break; |
+ case STATE_CREATE_ENTRY: |
+ DCHECK_EQ(OK, rv); |
+ rv = DoCreateEntry(); |
+ break; |
+ case STATE_CREATE_ENTRY_COMPLETE: |
+ rv = DoCreateEntryComplete(rv); |
+ break; |
case STATE_ADD_TO_ENTRY: |
DCHECK_EQ(OK, rv); |
rv = DoAddToEntry(); |
@@ -854,6 +836,31 @@ int HttpCache::Transaction::DoLoop(int result) { |
case STATE_ADD_TO_ENTRY_COMPLETE: |
rv = DoAddToEntryComplete(rv); |
break; |
+ case STATE_CACHE_READ_RESPONSE: |
+ DCHECK_EQ(OK, rv); |
+ rv = DoCacheReadResponse(); |
+ break; |
+ case STATE_CACHE_READ_RESPONSE_COMPLETE: |
+ rv = DoCacheReadResponseComplete(rv); |
+ break; |
+ case STATE_TOGGLE_UNUSED_SINCE_PREFETCH: |
+ DCHECK_EQ(OK, rv); |
+ rv = DoCacheToggleUnusedSincePrefetch(); |
+ break; |
+ case STATE_TOGGLE_UNUSED_SINCE_PREFETCH_COMPLETE: |
+ rv = DoCacheToggleUnusedSincePrefetchComplete(rv); |
+ break; |
+ case STATE_CACHE_DISPATCH_VALIDATION: |
+ DCHECK_EQ(OK, rv); |
+ rv = DoCacheDispatchValidation(); |
+ break; |
+ case STATE_CACHE_QUERY_DATA: |
+ DCHECK_EQ(OK, rv); |
+ rv = DoCacheQueryData(); |
+ break; |
+ case STATE_CACHE_QUERY_DATA_COMPLETE: |
+ rv = DoCacheQueryDataComplete(rv); |
+ break; |
case STATE_START_PARTIAL_CACHE_VALIDATION: |
DCHECK_EQ(OK, rv); |
rv = DoStartPartialCacheValidation(); |
@@ -861,6 +868,17 @@ int HttpCache::Transaction::DoLoop(int result) { |
case STATE_COMPLETE_PARTIAL_CACHE_VALIDATION: |
rv = DoCompletePartialCacheValidation(rv); |
break; |
+ case STATE_SEND_REQUEST: |
+ DCHECK_EQ(OK, rv); |
+ rv = DoSendRequest(); |
+ break; |
+ case STATE_SEND_REQUEST_COMPLETE: |
+ rv = DoSendRequestComplete(rv); |
+ break; |
+ case STATE_SUCCESSFUL_SEND_REQUEST: |
+ DCHECK_EQ(OK, rv); |
+ rv = DoSuccessfulSendRequest(); |
+ break; |
case STATE_UPDATE_CACHED_RESPONSE: |
DCHECK_EQ(OK, rv); |
rv = DoUpdateCachedResponse(); |
@@ -872,6 +890,17 @@ int HttpCache::Transaction::DoLoop(int result) { |
DCHECK_EQ(OK, rv); |
rv = DoOverwriteCachedResponse(); |
break; |
+ case STATE_CACHE_WRITE_RESPONSE: |
+ DCHECK_EQ(OK, rv); |
+ rv = DoCacheWriteResponse(); |
+ break; |
+ case STATE_CACHE_WRITE_TRUNCATED_RESPONSE: |
+ DCHECK_EQ(OK, rv); |
+ rv = DoCacheWriteTruncatedResponse(); |
+ break; |
+ case STATE_CACHE_WRITE_RESPONSE_COMPLETE: |
+ rv = DoCacheWriteResponseComplete(rv); |
+ break; |
case STATE_TRUNCATE_CACHED_DATA: |
DCHECK_EQ(OK, rv); |
rv = DoTruncateCachedData(); |
@@ -890,35 +919,6 @@ int HttpCache::Transaction::DoLoop(int result) { |
DCHECK_EQ(OK, rv); |
rv = DoPartialHeadersReceived(); |
break; |
- case STATE_CACHE_READ_RESPONSE: |
- DCHECK_EQ(OK, rv); |
- rv = DoCacheReadResponse(); |
- break; |
- case STATE_CACHE_READ_RESPONSE_COMPLETE: |
- rv = DoCacheReadResponseComplete(rv); |
- break; |
- case STATE_CACHE_DISPATCH_VALIDATION: |
- DCHECK_EQ(OK, rv); |
- rv = DoCacheDispatchValidation(); |
- break; |
- case STATE_TOGGLE_UNUSED_SINCE_PREFETCH: |
- DCHECK_EQ(OK, rv); |
- rv = DoCacheToggleUnusedSincePrefetch(); |
- break; |
- case STATE_TOGGLE_UNUSED_SINCE_PREFETCH_COMPLETE: |
- rv = DoCacheToggleUnusedSincePrefetchComplete(rv); |
- break; |
- case STATE_CACHE_WRITE_RESPONSE: |
- DCHECK_EQ(OK, rv); |
- rv = DoCacheWriteResponse(); |
- break; |
- case STATE_CACHE_WRITE_TRUNCATED_RESPONSE: |
- DCHECK_EQ(OK, rv); |
- rv = DoCacheWriteTruncatedResponse(); |
- break; |
- case STATE_CACHE_WRITE_RESPONSE_COMPLETE: |
- rv = DoCacheWriteResponseComplete(rv); |
- break; |
case STATE_CACHE_READ_METADATA: |
DCHECK_EQ(OK, rv); |
rv = DoCacheReadMetadata(); |
@@ -926,12 +926,12 @@ int HttpCache::Transaction::DoLoop(int result) { |
case STATE_CACHE_READ_METADATA_COMPLETE: |
rv = DoCacheReadMetadataComplete(rv); |
break; |
- case STATE_CACHE_QUERY_DATA: |
+ case STATE_NETWORK_READ: |
DCHECK_EQ(OK, rv); |
- rv = DoCacheQueryData(); |
+ rv = DoNetworkRead(); |
break; |
- case STATE_CACHE_QUERY_DATA_COMPLETE: |
- rv = DoCacheQueryDataComplete(rv); |
+ case STATE_NETWORK_READ_COMPLETE: |
+ rv = DoNetworkReadComplete(rv); |
break; |
case STATE_CACHE_READ_DATA: |
DCHECK_EQ(OK, rv); |
@@ -1031,255 +1031,87 @@ int HttpCache::Transaction::DoGetBackendComplete(int result) { |
return OK; |
} |
-int HttpCache::Transaction::DoSendRequest() { |
- DCHECK(mode_ & WRITE || mode_ == NONE); |
- DCHECK(!network_trans_.get()); |
- |
- send_request_since_ = TimeTicks::Now(); |
- |
- // Create a network transaction. |
- int rv = cache_->network_layer_->CreateTransaction(priority_, |
- &network_trans_); |
- if (rv != OK) |
- return rv; |
- network_trans_->SetBeforeNetworkStartCallback(before_network_start_callback_); |
- network_trans_->SetBeforeProxyHeadersSentCallback( |
- before_proxy_headers_sent_callback_); |
- |
- // Old load timing information, if any, is now obsolete. |
- old_network_trans_load_timing_.reset(); |
- |
- if (websocket_handshake_stream_base_create_helper_) |
- network_trans_->SetWebSocketHandshakeStreamCreateHelper( |
- websocket_handshake_stream_base_create_helper_); |
- |
- next_state_ = STATE_SEND_REQUEST_COMPLETE; |
- rv = network_trans_->Start(request_, io_callback_, net_log_); |
- return rv; |
-} |
+int HttpCache::Transaction::DoInitEntry() { |
+ DCHECK(!new_entry_); |
-int HttpCache::Transaction::DoSendRequestComplete(int result) { |
if (!cache_.get()) |
return ERR_UNEXPECTED; |
- // If we tried to conditionalize the request and failed, we know |
- // we won't be reading from the cache after this point. |
- if (couldnt_conditionalize_request_) |
- mode_ = WRITE; |
- |
- if (result == OK) { |
- next_state_ = STATE_SUCCESSFUL_SEND_REQUEST; |
+ if (mode_ == WRITE) { |
+ next_state_ = STATE_DOOM_ENTRY; |
return OK; |
} |
- const HttpResponseInfo* response = network_trans_->GetResponseInfo(); |
- response_.network_accessed = response->network_accessed; |
- |
- // Do not record requests that have network errors or restarts. |
- UpdateTransactionPattern(PATTERN_NOT_COVERED); |
- if (IsCertificateError(result)) { |
- // If we get a certificate error, then there is a certificate in ssl_info, |
- // so GetResponseInfo() should never return NULL here. |
- DCHECK(response); |
- response_.ssl_info = response->ssl_info; |
- } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) { |
- DCHECK(response); |
- response_.cert_request_info = response->cert_request_info; |
- } else if (response_.was_cached) { |
- DoneWritingToEntry(true); |
- } |
- |
- return result; |
+ next_state_ = STATE_OPEN_ENTRY; |
+ return OK; |
} |
-// We received the response headers and there is no error. |
-int HttpCache::Transaction::DoSuccessfulSendRequest() { |
- DCHECK(!new_response_); |
- const HttpResponseInfo* new_response = network_trans_->GetResponseInfo(); |
- |
- if (new_response->headers->response_code() == 401 || |
- new_response->headers->response_code() == 407) { |
- auth_response_ = *new_response; |
- if (!reading_) |
- return OK; |
+int HttpCache::Transaction::DoOpenEntry() { |
+ DCHECK(!new_entry_); |
+ next_state_ = STATE_OPEN_ENTRY_COMPLETE; |
+ cache_pending_ = true; |
+ net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY); |
+ first_cache_access_since_ = TimeTicks::Now(); |
+ return cache_->OpenEntry(cache_key_, &new_entry_, this); |
+} |
- // We initiated a second request the caller doesn't know about. We should be |
- // able to authenticate this request because we should have authenticated |
- // this URL moments ago. |
- if (IsReadyToRestartForAuth()) { |
- DCHECK(!response_.auth_challenge.get()); |
- next_state_ = STATE_SEND_REQUEST_COMPLETE; |
- // In theory we should check to see if there are new cookies, but there |
- // is no way to do that from here. |
- return network_trans_->RestartWithAuth(AuthCredentials(), io_callback_); |
- } |
+int HttpCache::Transaction::DoOpenEntryComplete(int result) { |
+ // It is important that we go to STATE_ADD_TO_ENTRY whenever the result is |
+ // OK, otherwise the cache will end up with an active entry without any |
+ // transaction attached. |
+ net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY, result); |
+ cache_pending_ = false; |
+ if (result == OK) { |
+ next_state_ = STATE_ADD_TO_ENTRY; |
+ return OK; |
+ } |
- // We have to perform cleanup at this point so that at least the next |
- // request can succeed. We do not retry at this point, because data |
- // has been read and we have no way to gather credentials. We would |
- // fail again, and potentially loop. This can happen if the credentials |
- // expire while chrome is suspended. |
- if (entry_) |
- DoomPartialEntry(false); |
- mode_ = NONE; |
- partial_.reset(); |
- ResetNetworkTransaction(); |
- return ERR_CACHE_AUTH_FAILURE_AFTER_READ; |
+ if (result == ERR_CACHE_RACE) { |
+ next_state_ = STATE_INIT_ENTRY; |
+ return OK; |
} |
- new_response_ = new_response; |
- if (!ValidatePartialResponse() && !auth_response_.headers.get()) { |
- // Something went wrong with this request and we have to restart it. |
- // If we have an authentication response, we are exposed to weird things |
- // hapenning if the user cancels the authentication before we receive |
- // the new response. |
- net_log_.AddEvent(NetLog::TYPE_HTTP_CACHE_RE_SEND_PARTIAL_REQUEST); |
- UpdateTransactionPattern(PATTERN_NOT_COVERED); |
- response_ = HttpResponseInfo(); |
- ResetNetworkTransaction(); |
- new_response_ = NULL; |
+ if (request_->method == "PUT" || request_->method == "DELETE" || |
+ (request_->method == "HEAD" && mode_ == READ_WRITE)) { |
+ DCHECK(mode_ == READ_WRITE || mode_ == WRITE || request_->method == "HEAD"); |
+ mode_ = NONE; |
next_state_ = STATE_SEND_REQUEST; |
return OK; |
} |
- 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); |
+ if (mode_ == READ_WRITE) { |
+ mode_ = WRITE; |
+ next_state_ = STATE_CREATE_ENTRY; |
+ return OK; |
+ } |
+ if (mode_ == UPDATE) { |
+ // There is no cache entry to update; proceed without caching. |
+ mode_ = NONE; |
+ next_state_ = STATE_SEND_REQUEST; |
+ return OK; |
} |
- if (mode_ == WRITE && |
- transaction_pattern_ != PATTERN_ENTRY_CANT_CONDITIONALIZE) { |
- UpdateTransactionPattern(PATTERN_ENTRY_NOT_CACHED); |
- } |
- |
- // Invalidate any cached GET with a successful PUT or DELETE. |
- if (mode_ == WRITE && |
- (request_->method == "PUT" || request_->method == "DELETE")) { |
- if (NonErrorResponse(new_response->headers->response_code())) { |
- int ret = cache_->DoomEntry(cache_key_, NULL); |
- DCHECK_EQ(OK, ret); |
- } |
- cache_->DoneWritingToEntry(entry_, true); |
- entry_ = NULL; |
- mode_ = NONE; |
- } |
- |
- // Invalidate any cached GET with a successful POST. |
- if (!(effective_load_flags_ & LOAD_DISABLE_CACHE) && |
- request_->method == "POST" && |
- NonErrorResponse(new_response->headers->response_code())) { |
- cache_->DoomMainEntryForUrl(request_->url); |
- } |
- |
- RecordNoStoreHeaderHistogram(request_->load_flags, new_response); |
- |
- if (new_response_->headers->response_code() == 416 && |
- (request_->method == "GET" || request_->method == "POST")) { |
- // If there is an active entry it may be destroyed with this transaction. |
- response_ = *new_response_; |
- return OK; |
- } |
- |
- // Are we expecting a response to a conditional query? |
- if (mode_ == READ_WRITE || mode_ == UPDATE) { |
- if (new_response->headers->response_code() == 304 || handling_206_) { |
- UpdateTransactionPattern(PATTERN_ENTRY_VALIDATED); |
- next_state_ = STATE_UPDATE_CACHED_RESPONSE; |
- return OK; |
- } |
- UpdateTransactionPattern(PATTERN_ENTRY_UPDATED); |
- mode_ = WRITE; |
- } |
- |
- next_state_ = STATE_OVERWRITE_CACHED_RESPONSE; |
- return OK; |
-} |
- |
-int HttpCache::Transaction::DoNetworkRead() { |
- next_state_ = STATE_NETWORK_READ_COMPLETE; |
- return network_trans_->Read(read_buf_.get(), io_buf_len_, io_callback_); |
-} |
- |
-int HttpCache::Transaction::DoNetworkReadComplete(int result) { |
- DCHECK(mode_ & WRITE || mode_ == NONE); |
- |
- if (!cache_.get()) |
- return ERR_UNEXPECTED; |
- |
- // If there is an error or we aren't saving the data, we are done; just wait |
- // until the destructor runs to see if we can keep the data. |
- if (mode_ == NONE || result < 0) |
- return result; |
- |
- next_state_ = STATE_CACHE_WRITE_DATA; |
- return result; |
-} |
- |
-int HttpCache::Transaction::DoInitEntry() { |
- DCHECK(!new_entry_); |
- |
- if (!cache_.get()) |
- return ERR_UNEXPECTED; |
- |
- if (mode_ == WRITE) { |
- next_state_ = STATE_DOOM_ENTRY; |
- return OK; |
- } |
- |
- next_state_ = STATE_OPEN_ENTRY; |
- return OK; |
+ // The entry does not exist, and we are not permitted to create a new entry, |
+ // so we must fail. |
+ return ERR_CACHE_MISS; |
} |
-int HttpCache::Transaction::DoOpenEntry() { |
- DCHECK(!new_entry_); |
- next_state_ = STATE_OPEN_ENTRY_COMPLETE; |
+int HttpCache::Transaction::DoDoomEntry() { |
+ next_state_ = STATE_DOOM_ENTRY_COMPLETE; |
cache_pending_ = true; |
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY); |
- first_cache_access_since_ = TimeTicks::Now(); |
- return cache_->OpenEntry(cache_key_, &new_entry_, this); |
+ if (first_cache_access_since_.is_null()) |
+ first_cache_access_since_ = TimeTicks::Now(); |
+ net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY); |
+ return cache_->DoomEntry(cache_key_, this); |
} |
-int HttpCache::Transaction::DoOpenEntryComplete(int result) { |
- // It is important that we go to STATE_ADD_TO_ENTRY whenever the result is |
- // OK, otherwise the cache will end up with an active entry without any |
- // transaction attached. |
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY, result); |
+int HttpCache::Transaction::DoDoomEntryComplete(int result) { |
+ net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY, result); |
+ next_state_ = STATE_CREATE_ENTRY; |
cache_pending_ = false; |
- if (result == OK) { |
- next_state_ = STATE_ADD_TO_ENTRY; |
- return OK; |
- } |
- |
- if (result == ERR_CACHE_RACE) { |
+ if (result == ERR_CACHE_RACE) |
next_state_ = STATE_INIT_ENTRY; |
- return OK; |
- } |
- |
- if (request_->method == "PUT" || request_->method == "DELETE" || |
- (request_->method == "HEAD" && mode_ == READ_WRITE)) { |
- DCHECK(mode_ == READ_WRITE || mode_ == WRITE || request_->method == "HEAD"); |
- mode_ = NONE; |
- next_state_ = STATE_SEND_REQUEST; |
- return OK; |
- } |
- |
- if (mode_ == READ_WRITE) { |
- mode_ = WRITE; |
- next_state_ = STATE_CREATE_ENTRY; |
- return OK; |
- } |
- if (mode_ == UPDATE) { |
- // There is no cache entry to update; proceed without caching. |
- mode_ = NONE; |
- next_state_ = STATE_SEND_REQUEST; |
- return OK; |
- } |
- |
- // The entry does not exist, and we are not permitted to create a new entry, |
- // so we must fail. |
- return ERR_CACHE_MISS; |
+ return OK; |
} |
int HttpCache::Transaction::DoCreateEntry() { |
@@ -1318,24 +1150,6 @@ int HttpCache::Transaction::DoCreateEntryComplete(int result) { |
return OK; |
} |
-int HttpCache::Transaction::DoDoomEntry() { |
- next_state_ = STATE_DOOM_ENTRY_COMPLETE; |
- cache_pending_ = true; |
- if (first_cache_access_since_.is_null()) |
- first_cache_access_since_ = TimeTicks::Now(); |
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY); |
- return cache_->DoomEntry(cache_key_, this); |
-} |
- |
-int HttpCache::Transaction::DoDoomEntryComplete(int result) { |
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY, result); |
- next_state_ = STATE_CREATE_ENTRY; |
- cache_pending_ = false; |
- if (result == ERR_CACHE_RACE) |
- next_state_ = STATE_INIT_ENTRY; |
- return OK; |
-} |
- |
int HttpCache::Transaction::DoAddToEntry() { |
DCHECK(new_entry_); |
cache_pending_ = true; |
@@ -1427,39 +1241,315 @@ int HttpCache::Transaction::DoAddToEntryComplete(int result) { |
return OK; |
} |
+int HttpCache::Transaction::DoCacheReadResponse() { |
+ DCHECK(entry_); |
+ next_state_ = STATE_CACHE_READ_RESPONSE_COMPLETE; |
+ |
+ io_buf_len_ = entry_->disk_entry->GetDataSize(kResponseInfoIndex); |
+ read_buf_ = new IOBuffer(io_buf_len_); |
+ |
+ net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_INFO); |
+ return entry_->disk_entry->ReadData(kResponseInfoIndex, 0, read_buf_.get(), |
+ io_buf_len_, io_callback_); |
+} |
+ |
+int HttpCache::Transaction::DoCacheReadResponseComplete(int result) { |
+ net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result); |
+ if (result != io_buf_len_ || |
+ !HttpCache::ParseResponseInfo(read_buf_->data(), io_buf_len_, &response_, |
+ &truncated_)) { |
+ return OnCacheReadError(result, true); |
+ } |
+ |
+ // cert_cache() will be null if the CertCacheTrial field trial is disabled. |
+ if (cache_->cert_cache() && response_.ssl_info.is_valid()) |
+ ReadCertChain(); |
+ |
+ // Some resources may have slipped in as truncated when they're not. |
+ int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex); |
+ if (response_.headers->GetContentLength() == current_size) |
+ truncated_ = false; |
+ |
+ if ((response_.unused_since_prefetch && |
+ !(request_->load_flags & LOAD_PREFETCH)) || |
+ (!response_.unused_since_prefetch && |
+ (request_->load_flags & LOAD_PREFETCH))) { |
+ // Either this is the first use of an entry since it was prefetched or |
+ // this is a prefetch. The value of response.unused_since_prefetch is valid |
+ // for this transaction but the bit needs to be flipped in storage. |
+ next_state_ = STATE_TOGGLE_UNUSED_SINCE_PREFETCH; |
+ return OK; |
+ } |
+ |
+ next_state_ = STATE_CACHE_DISPATCH_VALIDATION; |
+ return OK; |
+} |
+ |
+int HttpCache::Transaction::DoCacheToggleUnusedSincePrefetch() { |
+ // Write back the toggled value for the next use of this entry. |
+ response_.unused_since_prefetch = !response_.unused_since_prefetch; |
+ |
+ // TODO(jkarlin): If DoUpdateCachedResponse is also called for this |
+ // transaction then metadata will be written to cache twice. If prefetching |
+ // becomes more common, consider combining the writes. |
+ target_state_ = STATE_TOGGLE_UNUSED_SINCE_PREFETCH_COMPLETE; |
+ next_state_ = STATE_CACHE_WRITE_RESPONSE; |
+ return OK; |
+} |
+ |
+int HttpCache::Transaction::DoCacheToggleUnusedSincePrefetchComplete( |
+ int result) { |
+ // Restore the original value for this transaction. |
+ response_.unused_since_prefetch = !response_.unused_since_prefetch; |
+ next_state_ = STATE_CACHE_DISPATCH_VALIDATION; |
+ return OK; |
+} |
+ |
+int HttpCache::Transaction::DoCacheDispatchValidation() { |
+ // We now have access to the cache entry. |
+ // |
+ // o if we are a reader for the transaction, then we can start reading the |
+ // cache entry. |
+ // |
+ // o if we can read or write, then we should check if the cache entry needs |
+ // to be validated and then issue a network request if needed or just read |
+ // from the cache if the cache entry is already valid. |
+ // |
+ // o if we are set to UPDATE, then we are handling an externally |
+ // conditionalized request (if-modified-since / if-none-match). We check |
+ // if the request headers define a validation request. |
+ // |
+ int result = ERR_FAILED; |
+ switch (mode_) { |
+ case READ: |
+ UpdateTransactionPattern(PATTERN_ENTRY_USED); |
+ result = BeginCacheRead(); |
+ break; |
+ case READ_WRITE: |
+ result = BeginPartialCacheValidation(); |
+ break; |
+ case UPDATE: |
+ result = BeginExternallyConditionalizedRequest(); |
+ break; |
+ case WRITE: |
+ default: |
+ NOTREACHED(); |
+ } |
+ return result; |
+} |
+ |
+int HttpCache::Transaction::DoCacheQueryData() { |
+ next_state_ = STATE_CACHE_QUERY_DATA_COMPLETE; |
+ return entry_->disk_entry->ReadyForSparseIO(io_callback_); |
+} |
+ |
+int HttpCache::Transaction::DoCacheQueryDataComplete(int result) { |
+ DCHECK_EQ(OK, result); |
+ if (!cache_.get()) |
+ return ERR_UNEXPECTED; |
+ |
+ return ValidateEntryHeadersAndContinue(); |
+} |
+ |
// We may end up here multiple times for a given request. |
int HttpCache::Transaction::DoStartPartialCacheValidation() { |
if (mode_ == NONE) |
return OK; |
- next_state_ = STATE_COMPLETE_PARTIAL_CACHE_VALIDATION; |
- return partial_->ShouldValidateCache(entry_->disk_entry, io_callback_); |
-} |
+ next_state_ = STATE_COMPLETE_PARTIAL_CACHE_VALIDATION; |
+ return partial_->ShouldValidateCache(entry_->disk_entry, io_callback_); |
+} |
+ |
+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; |
+ } |
+ |
+ if (result < 0) |
+ return result; |
+ |
+ partial_->PrepareCacheValidation(entry_->disk_entry, |
+ &custom_request_->extra_headers); |
+ |
+ if (reading_ && partial_->IsCurrentRangeCached()) { |
+ next_state_ = STATE_CACHE_READ_DATA; |
+ return OK; |
+ } |
+ |
+ return BeginCacheValidation(); |
+} |
+ |
+int HttpCache::Transaction::DoSendRequest() { |
+ DCHECK(mode_ & WRITE || mode_ == NONE); |
+ DCHECK(!network_trans_.get()); |
+ |
+ send_request_since_ = TimeTicks::Now(); |
+ |
+ // Create a network transaction. |
+ int rv = |
+ cache_->network_layer_->CreateTransaction(priority_, &network_trans_); |
+ if (rv != OK) |
+ return rv; |
+ network_trans_->SetBeforeNetworkStartCallback(before_network_start_callback_); |
+ network_trans_->SetBeforeProxyHeadersSentCallback( |
+ before_proxy_headers_sent_callback_); |
+ |
+ // Old load timing information, if any, is now obsolete. |
+ old_network_trans_load_timing_.reset(); |
+ |
+ if (websocket_handshake_stream_base_create_helper_) |
+ network_trans_->SetWebSocketHandshakeStreamCreateHelper( |
+ websocket_handshake_stream_base_create_helper_); |
+ |
+ next_state_ = STATE_SEND_REQUEST_COMPLETE; |
+ rv = network_trans_->Start(request_, io_callback_, net_log_); |
+ return rv; |
+} |
+ |
+int HttpCache::Transaction::DoSendRequestComplete(int result) { |
+ if (!cache_.get()) |
+ return ERR_UNEXPECTED; |
+ |
+ // If we tried to conditionalize the request and failed, we know |
+ // we won't be reading from the cache after this point. |
+ if (couldnt_conditionalize_request_) |
+ mode_ = WRITE; |
+ |
+ if (result == OK) { |
+ next_state_ = STATE_SUCCESSFUL_SEND_REQUEST; |
+ return OK; |
+ } |
+ |
+ const HttpResponseInfo* response = network_trans_->GetResponseInfo(); |
+ response_.network_accessed = response->network_accessed; |
+ |
+ // Do not record requests that have network errors or restarts. |
+ UpdateTransactionPattern(PATTERN_NOT_COVERED); |
+ if (IsCertificateError(result)) { |
+ // If we get a certificate error, then there is a certificate in ssl_info, |
+ // so GetResponseInfo() should never return NULL here. |
+ DCHECK(response); |
+ response_.ssl_info = response->ssl_info; |
+ } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) { |
+ DCHECK(response); |
+ response_.cert_request_info = response->cert_request_info; |
+ } else if (response_.was_cached) { |
+ DoneWritingToEntry(true); |
+ } |
+ |
+ return result; |
+} |
+ |
+// We received the response headers and there is no error. |
+int HttpCache::Transaction::DoSuccessfulSendRequest() { |
+ DCHECK(!new_response_); |
+ const HttpResponseInfo* new_response = network_trans_->GetResponseInfo(); |
+ |
+ if (new_response->headers->response_code() == 401 || |
+ new_response->headers->response_code() == 407) { |
+ auth_response_ = *new_response; |
+ if (!reading_) |
+ return OK; |
+ |
+ // We initiated a second request the caller doesn't know about. We should be |
+ // able to authenticate this request because we should have authenticated |
+ // this URL moments ago. |
+ if (IsReadyToRestartForAuth()) { |
+ DCHECK(!response_.auth_challenge.get()); |
+ next_state_ = STATE_SEND_REQUEST_COMPLETE; |
+ // In theory we should check to see if there are new cookies, but there |
+ // is no way to do that from here. |
+ return network_trans_->RestartWithAuth(AuthCredentials(), io_callback_); |
+ } |
+ |
+ // We have to perform cleanup at this point so that at least the next |
+ // request can succeed. We do not retry at this point, because data |
+ // has been read and we have no way to gather credentials. We would |
+ // fail again, and potentially loop. This can happen if the credentials |
+ // expire while chrome is suspended. |
+ if (entry_) |
+ DoomPartialEntry(false); |
+ mode_ = NONE; |
+ partial_.reset(); |
+ ResetNetworkTransaction(); |
+ return ERR_CACHE_AUTH_FAILURE_AFTER_READ; |
+ } |
+ |
+ new_response_ = new_response; |
+ if (!ValidatePartialResponse() && !auth_response_.headers.get()) { |
+ // Something went wrong with this request and we have to restart it. |
+ // If we have an authentication response, we are exposed to weird things |
+ // hapenning if the user cancels the authentication before we receive |
+ // the new response. |
+ net_log_.AddEvent(NetLog::TYPE_HTTP_CACHE_RE_SEND_PARTIAL_REQUEST); |
+ UpdateTransactionPattern(PATTERN_NOT_COVERED); |
+ response_ = HttpResponseInfo(); |
+ ResetNetworkTransaction(); |
+ new_response_ = NULL; |
+ next_state_ = STATE_SEND_REQUEST; |
+ return OK; |
+ } |
+ |
+ 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); |
+ } |
-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; |
+ if (mode_ == WRITE && |
+ transaction_pattern_ != PATTERN_ENTRY_CANT_CONDITIONALIZE) { |
+ UpdateTransactionPattern(PATTERN_ENTRY_NOT_CACHED); |
+ } |
+ |
+ // Invalidate any cached GET with a successful PUT or DELETE. |
+ if (mode_ == WRITE && |
+ (request_->method == "PUT" || request_->method == "DELETE")) { |
+ if (NonErrorResponse(new_response->headers->response_code())) { |
+ int ret = cache_->DoomEntry(cache_key_, NULL); |
+ DCHECK_EQ(OK, ret); |
} |
- return result; |
+ cache_->DoneWritingToEntry(entry_, true); |
+ entry_ = NULL; |
+ mode_ = NONE; |
} |
- if (result < 0) |
- return result; |
+ // Invalidate any cached GET with a successful POST. |
+ if (!(effective_load_flags_ & LOAD_DISABLE_CACHE) && |
+ request_->method == "POST" && |
+ NonErrorResponse(new_response->headers->response_code())) { |
+ cache_->DoomMainEntryForUrl(request_->url); |
+ } |
- partial_->PrepareCacheValidation(entry_->disk_entry, |
- &custom_request_->extra_headers); |
+ RecordNoStoreHeaderHistogram(request_->load_flags, new_response); |
- if (reading_ && partial_->IsCurrentRangeCached()) { |
- next_state_ = STATE_CACHE_READ_DATA; |
+ if (new_response_->headers->response_code() == 416 && |
+ (request_->method == "GET" || request_->method == "POST")) { |
+ // If there is an active entry it may be destroyed with this transaction. |
+ response_ = *new_response_; |
return OK; |
} |
- return BeginCacheValidation(); |
+ // Are we expecting a response to a conditional query? |
+ if (mode_ == READ_WRITE || mode_ == UPDATE) { |
+ if (new_response->headers->response_code() == 304 || handling_206_) { |
+ UpdateTransactionPattern(PATTERN_ENTRY_VALIDATED); |
+ next_state_ = STATE_UPDATE_CACHED_RESPONSE; |
+ return OK; |
+ } |
+ UpdateTransactionPattern(PATTERN_ENTRY_UPDATED); |
+ mode_ = WRITE; |
+ } |
+ |
+ next_state_ = STATE_OVERWRITE_CACHED_RESPONSE; |
+ return OK; |
} |
// We received 304 or 206 and we want to update the cached response headers. |
@@ -1570,6 +1660,44 @@ int HttpCache::Transaction::DoOverwriteCachedResponse() { |
return OK; |
} |
+int HttpCache::Transaction::DoCacheWriteResponse() { |
+ // TODO(rtenneti): Remove ScopedTracker below once crbug.com/422516 is fixed. |
+ tracked_objects::ScopedTracker tracking_profile( |
+ FROM_HERE_WITH_EXPLICIT_FUNCTION( |
+ "422516 HttpCache::Transaction::DoCacheWriteResponse")); |
+ |
+ if (entry_) { |
+ if (net_log_.IsCapturing()) |
+ net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO); |
+ } |
+ return WriteResponseInfoToEntry(false); |
+} |
+ |
+int HttpCache::Transaction::DoCacheWriteTruncatedResponse() { |
+ if (entry_) { |
+ if (net_log_.IsCapturing()) |
+ net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO); |
+ } |
+ return WriteResponseInfoToEntry(true); |
+} |
+ |
+int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) { |
+ next_state_ = target_state_; |
+ target_state_ = STATE_NONE; |
+ if (!entry_) |
+ return OK; |
+ if (net_log_.IsCapturing()) { |
+ net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_INFO, |
+ result); |
+ } |
+ |
+ // Balance the AddRef from WriteResponseInfoToEntry. |
+ if (result != io_buf_len_) { |
+ DLOG(ERROR) << "failed to write response info to cache"; |
+ DoneWritingToEntry(false); |
+ } |
+ return OK; |
+} |
int HttpCache::Transaction::DoTruncateCachedData() { |
next_state_ = STATE_TRUNCATE_CACHED_DATA_COMPLETE; |
if (!entry_) |
@@ -1637,142 +1765,6 @@ int HttpCache::Transaction::DoPartialHeadersReceived() { |
return OK; |
} |
-int HttpCache::Transaction::DoCacheReadResponse() { |
- DCHECK(entry_); |
- next_state_ = STATE_CACHE_READ_RESPONSE_COMPLETE; |
- |
- io_buf_len_ = entry_->disk_entry->GetDataSize(kResponseInfoIndex); |
- read_buf_ = new IOBuffer(io_buf_len_); |
- |
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_INFO); |
- return entry_->disk_entry->ReadData(kResponseInfoIndex, 0, read_buf_.get(), |
- io_buf_len_, io_callback_); |
-} |
- |
-int HttpCache::Transaction::DoCacheReadResponseComplete(int result) { |
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result); |
- if (result != io_buf_len_ || |
- !HttpCache::ParseResponseInfo(read_buf_->data(), io_buf_len_, |
- &response_, &truncated_)) { |
- return OnCacheReadError(result, true); |
- } |
- |
- // cert_cache() will be null if the CertCacheTrial field trial is disabled. |
- if (cache_->cert_cache() && response_.ssl_info.is_valid()) |
- ReadCertChain(); |
- |
- // Some resources may have slipped in as truncated when they're not. |
- int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex); |
- if (response_.headers->GetContentLength() == current_size) |
- truncated_ = false; |
- |
- if ((response_.unused_since_prefetch && |
- !(request_->load_flags & LOAD_PREFETCH)) || |
- (!response_.unused_since_prefetch && |
- (request_->load_flags & LOAD_PREFETCH))) { |
- // Either this is the first use of an entry since it was prefetched or |
- // this is a prefetch. The value of response.unused_since_prefetch is valid |
- // for this transaction but the bit needs to be flipped in storage. |
- next_state_ = STATE_TOGGLE_UNUSED_SINCE_PREFETCH; |
- return OK; |
- } |
- |
- next_state_ = STATE_CACHE_DISPATCH_VALIDATION; |
- return OK; |
-} |
- |
-int HttpCache::Transaction::DoCacheDispatchValidation() { |
- // We now have access to the cache entry. |
- // |
- // o if we are a reader for the transaction, then we can start reading the |
- // cache entry. |
- // |
- // o if we can read or write, then we should check if the cache entry needs |
- // to be validated and then issue a network request if needed or just read |
- // from the cache if the cache entry is already valid. |
- // |
- // o if we are set to UPDATE, then we are handling an externally |
- // conditionalized request (if-modified-since / if-none-match). We check |
- // if the request headers define a validation request. |
- // |
- int result = ERR_FAILED; |
- switch (mode_) { |
- case READ: |
- UpdateTransactionPattern(PATTERN_ENTRY_USED); |
- result = BeginCacheRead(); |
- break; |
- case READ_WRITE: |
- result = BeginPartialCacheValidation(); |
- break; |
- case UPDATE: |
- result = BeginExternallyConditionalizedRequest(); |
- break; |
- case WRITE: |
- default: |
- NOTREACHED(); |
- } |
- return result; |
-} |
- |
-int HttpCache::Transaction::DoCacheToggleUnusedSincePrefetch() { |
- // Write back the toggled value for the next use of this entry. |
- response_.unused_since_prefetch = !response_.unused_since_prefetch; |
- |
- // TODO(jkarlin): If DoUpdateCachedResponse is also called for this |
- // transaction then metadata will be written to cache twice. If prefetching |
- // becomes more common, consider combining the writes. |
- target_state_ = STATE_TOGGLE_UNUSED_SINCE_PREFETCH_COMPLETE; |
- next_state_ = STATE_CACHE_WRITE_RESPONSE; |
- return OK; |
-} |
- |
-int HttpCache::Transaction::DoCacheToggleUnusedSincePrefetchComplete( |
- int result) { |
- // Restore the original value for this transaction. |
- response_.unused_since_prefetch = !response_.unused_since_prefetch; |
- next_state_ = STATE_CACHE_DISPATCH_VALIDATION; |
- return OK; |
-} |
- |
-int HttpCache::Transaction::DoCacheWriteResponse() { |
- // TODO(rtenneti): Remove ScopedTracker below once crbug.com/422516 is fixed. |
- tracked_objects::ScopedTracker tracking_profile( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "422516 HttpCache::Transaction::DoCacheWriteResponse")); |
- |
- if (entry_) { |
- if (net_log_.IsCapturing()) |
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO); |
- } |
- return WriteResponseInfoToEntry(false); |
-} |
- |
-int HttpCache::Transaction::DoCacheWriteTruncatedResponse() { |
- if (entry_) { |
- if (net_log_.IsCapturing()) |
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO); |
- } |
- return WriteResponseInfoToEntry(true); |
-} |
- |
-int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) { |
- next_state_ = target_state_; |
- target_state_ = STATE_NONE; |
- if (!entry_) |
- return OK; |
- if (net_log_.IsCapturing()) { |
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_INFO, |
- result); |
- } |
- |
- // Balance the AddRef from WriteResponseInfoToEntry. |
- if (result != io_buf_len_) { |
- DLOG(ERROR) << "failed to write response info to cache"; |
- DoneWritingToEntry(false); |
- } |
- return OK; |
-} |
- |
int HttpCache::Transaction::DoCacheReadMetadata() { |
DCHECK(entry_); |
DCHECK(!response_.metadata.get()); |
@@ -1795,17 +1787,24 @@ int HttpCache::Transaction::DoCacheReadMetadataComplete(int result) { |
return OK; |
} |
-int HttpCache::Transaction::DoCacheQueryData() { |
- next_state_ = STATE_CACHE_QUERY_DATA_COMPLETE; |
- return entry_->disk_entry->ReadyForSparseIO(io_callback_); |
+int HttpCache::Transaction::DoNetworkRead() { |
+ next_state_ = STATE_NETWORK_READ_COMPLETE; |
+ return network_trans_->Read(read_buf_.get(), io_buf_len_, io_callback_); |
} |
-int HttpCache::Transaction::DoCacheQueryDataComplete(int result) { |
- DCHECK_EQ(OK, result); |
+int HttpCache::Transaction::DoNetworkReadComplete(int result) { |
+ DCHECK(mode_ & WRITE || mode_ == NONE); |
+ |
if (!cache_.get()) |
return ERR_UNEXPECTED; |
- return ValidateEntryHeadersAndContinue(); |
+ // If there is an error or we aren't saving the data, we are done; just wait |
+ // until the destructor runs to see if we can keep the data. |
+ if (mode_ == NONE || result < 0) |
+ return result; |
+ |
+ next_state_ = STATE_CACHE_WRITE_DATA; |
+ return result; |
} |
int HttpCache::Transaction::DoCacheReadData() { |
@@ -2612,7 +2611,6 @@ int HttpCache::Transaction::SetupEntryForRead() { |
return OK; |
} |
- |
int HttpCache::Transaction::ReadFromNetwork(IOBuffer* data, int data_len) { |
read_buf_ = data; |
io_buf_len_ = data_len; |