Chromium Code Reviews| 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..146bc23549de8d9b961e48f9904233ebf858186d 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; |
| @@ -1424,42 +1238,318 @@ int HttpCache::Transaction::DoAddToEntryComplete(int result) { |
| DCHECK(mode_ & READ_META); |
| next_state_ = STATE_CACHE_READ_RESPONSE; |
| } |
| - return OK; |
| -} |
| - |
| -// We may end up here multiple times for a given request. |
| -int HttpCache::Transaction::DoStartPartialCacheValidation() { |
| - if (mode_ == NONE) |
| - return OK; |
| + 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_); |
| +} |
| + |
| +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); |
| + } |
| - next_state_ = STATE_COMPLETE_PARTIAL_CACHE_VALIDATION; |
| - return partial_->ShouldValidateCache(entry_->disk_entry, io_callback_); |
| -} |
| + if (mode_ == WRITE && |
| + transaction_pattern_ != PATTERN_ENTRY_CANT_CONDITIONALIZE) { |
| + UpdateTransactionPattern(PATTERN_ENTRY_NOT_CACHED); |
| + } |
| -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; |
| + // 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_) |
| @@ -1613,7 +1741,6 @@ int HttpCache::Transaction::DoTruncateCachedMetadataComplete(int result) { |
| next_state_ = STATE_PARTIAL_HEADERS_RECEIVED; |
| return OK; |
| } |
| - |
|
rvargas (doing something else)
2015/07/13 19:18:56
need this line
hubbe
2015/07/13 19:29:15
Done.
|
| int HttpCache::Transaction::DoPartialHeadersReceived() { |
| new_response_ = NULL; |
| if (entry_ && !partial_.get() && |
| @@ -1637,142 +1764,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 +1786,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 +2610,6 @@ int HttpCache::Transaction::SetupEntryForRead() { |
| return OK; |
| } |
| - |
| int HttpCache::Transaction::ReadFromNetwork(IOBuffer* data, int data_len) { |
| read_buf_ = data; |
| io_buf_len_ = data_len; |