diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-10-13 13:24:50 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-10-14 10:57:25 +0000 |
commit | af3d4809763ef308f08ced947a73b624729ac7ea (patch) | |
tree | 4402b911e30383f6c6dace1e8cf3b8e85355db3a /chromium/net/http/http_cache_transaction.cc | |
parent | 0e8ff63a407fe323e215bb1a2c423c09a4747c8a (diff) | |
download | qtwebengine-chromium-af3d4809763ef308f08ced947a73b624729ac7ea.tar.gz |
BASELINE: Update Chromium to 47.0.2526.14
Also adding in sources needed for spellchecking.
Change-Id: Idd44170fa1616f26315188970a8d5ba7d472b18a
Reviewed-by: Michael BrĂ¼ning <michael.bruning@theqtcompany.com>
Diffstat (limited to 'chromium/net/http/http_cache_transaction.cc')
-rw-r--r-- | chromium/net/http/http_cache_transaction.cc | 1106 |
1 files changed, 562 insertions, 544 deletions
diff --git a/chromium/net/http/http_cache_transaction.cc b/chromium/net/http/http_cache_transaction.cc index f2fcf4cb7c4..9dd8458e2e2 100644 --- a/chromium/net/http/http_cache_transaction.cc +++ b/chromium/net/http/http_cache_transaction.cc @@ -14,6 +14,7 @@ #include <string> #include "base/bind.h" +#include "base/callback_helpers.h" #include "base/compiler_specific.h" #include "base/format_macros.h" #include "base/location.h" @@ -236,8 +237,8 @@ static bool HeaderMatches(const HttpRequestHeaders& headers, HttpUtil::ValuesIterator v(header_value.begin(), header_value.end(), ','); while (v.GetNext()) { - if (base::LowerCaseEqualsASCII(v.value_begin(), v.value_end(), - search->value)) + if (base::LowerCaseEqualsASCII( + base::StringPiece(v.value_begin(), v.value_end()), search->value)) return true; } } @@ -255,7 +256,6 @@ HttpCache::Transaction::Transaction(RequestPriority priority, HttpCache* cache) new_entry_(NULL), new_response_(NULL), mode_(NONE), - target_state_(STATE_NONE), reading_(false), invalid_range_(false), truncated_(false), @@ -274,6 +274,7 @@ HttpCache::Transaction::Transaction(RequestPriority priority, HttpCache* cache) write_len_(0), transaction_pattern_(PATTERN_UNDEFINED), total_received_bytes_(0), + total_sent_bytes_(0), websocket_handshake_stream_base_create_helper_(NULL), weak_factory_(this) { static_assert(HttpCache::Transaction::kNumValidationHeaders == @@ -327,7 +328,7 @@ bool HttpCache::Transaction::AddTruncatedFlag() { DCHECK(mode_ & WRITE || mode_ == NONE); // Don't set the flag for sparse entries. - if (partial_.get() && !truncated_) + if (partial_ && !truncated_) return true; if (!CanResume(true)) @@ -338,7 +339,6 @@ bool HttpCache::Transaction::AddTruncatedFlag() { return true; truncated_ = true; - target_state_ = STATE_NONE; next_state_ = STATE_CACHE_WRITE_TRUNCATED_RESPONSE; DoLoop(OK); return true; @@ -367,6 +367,7 @@ int HttpCache::Transaction::Start(const HttpRequestInfo* request, DCHECK(!reading_); DCHECK(!network_trans_.get()); DCHECK(!entry_); + DCHECK_EQ(next_state_, STATE_NONE); if (!cache_.get()) return ERR_UNEXPECTED; @@ -453,6 +454,7 @@ bool HttpCache::Transaction::IsReadyToRestartForAuth() { int HttpCache::Transaction::Read(IOBuffer* buf, int buf_len, const CompletionCallback& callback) { + DCHECK_EQ(next_state_, STATE_NONE); DCHECK(buf); DCHECK_GT(buf_len, 0); DCHECK(!callback.is_null()); @@ -473,29 +475,19 @@ int HttpCache::Transaction::Read(IOBuffer* buf, int buf_len, } reading_ = true; - int rv; - - switch (mode_) { - case READ_WRITE: - DCHECK(partial_.get()); - if (!network_trans_.get()) { - // We are just reading from the cache, but we may be writing later. - rv = ReadFromEntry(buf, buf_len); - break; - } - case NONE: - case WRITE: - DCHECK(network_trans_.get()); - rv = ReadFromNetwork(buf, buf_len); - break; - case READ: - rv = ReadFromEntry(buf, buf_len); - break; - default: - NOTREACHED(); - rv = ERR_FAILED; + read_buf_ = buf; + io_buf_len_ = buf_len; + if (network_trans_) { + DCHECK(mode_ == WRITE || mode_ == NONE || + (mode_ == READ_WRITE && partial_)); + next_state_ = STATE_NETWORK_READ; + } else { + DCHECK(mode_ == READ || (mode_ == READ_WRITE && partial_)); + next_state_ = STATE_CACHE_READ_DATA; } + int rv = DoLoop(OK); + if (rv == ERR_IO_PENDING) { DCHECK(callback_.is_null()); callback_ = callback; @@ -530,13 +522,20 @@ bool HttpCache::Transaction::GetFullRequestHeaders( return false; } -int64 HttpCache::Transaction::GetTotalReceivedBytes() const { - int64 total_received_bytes = total_received_bytes_; +int64_t HttpCache::Transaction::GetTotalReceivedBytes() const { + int64_t total_received_bytes = total_received_bytes_; if (network_trans_) total_received_bytes += network_trans_->GetTotalReceivedBytes(); return total_received_bytes; } +int64_t HttpCache::Transaction::GetTotalSentBytes() const { + int64_t total_sent_bytes = total_sent_bytes_; + if (network_trans_) + total_sent_bytes += network_trans_->GetTotalSentBytes(); + return total_sent_bytes; +} + void HttpCache::Transaction::DoneReading() { if (cache_.get() && entry_) { DCHECK_NE(mode_, UPDATE); @@ -600,6 +599,18 @@ bool HttpCache::Transaction::GetLoadTimingInfo( return true; } +bool HttpCache::Transaction::GetRemoteEndpoint(IPEndPoint* endpoint) const { + if (network_trans_) + return network_trans_->GetRemoteEndpoint(endpoint); + + if (!old_remote_endpoint_.address().empty()) { + *endpoint = old_remote_endpoint_; + return true; + } + + return false; +} + void HttpCache::Transaction::SetPriority(RequestPriority priority) { priority_ = priority; if (network_trans_) @@ -644,26 +655,6 @@ void HttpCache::Transaction::GetConnectionAttempts( //----------------------------------------------------------------------------- -void HttpCache::Transaction::DoCallback(int rv) { - DCHECK(rv != ERR_IO_PENDING); - DCHECK(!callback_.is_null()); - - read_buf_ = NULL; // Release the buffer before invoking the callback. - - // Since Run may result in Read being called, clear callback_ up front. - CompletionCallback c = callback_; - callback_.Reset(); - c.Run(rv); -} - -int HttpCache::Transaction::HandleResult(int rv) { - DCHECK(rv != ERR_IO_PENDING); - if (!callback_.is_null()) - DoCallback(rv); - - return rv; -} - // A few common patterns: (Foo* means Foo -> FooComplete) // // 1. Not-cached entry: @@ -690,8 +681,9 @@ int HttpCache::Transaction::HandleResult(int rv) { // GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse* // -> CacheDispatchValidation -> BeginPartialCacheValidation() -> // BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest -> -// UpdateCachedResponse -> CacheWriteResponse* -> UpdateCachedResponseComplete -// -> OverwriteCachedResponse -> PartialHeadersReceived +// UpdateCachedResponse -> CacheWriteUpdatedResponse* -> +// UpdateCachedResponseComplete -> OverwriteCachedResponse -> +// PartialHeadersReceived // // Read(): // CacheReadData* @@ -714,8 +706,9 @@ int HttpCache::Transaction::HandleResult(int rv) { // CacheQueryData* -> ValidateEntryHeadersAndContinue() -> // StartPartialCacheValidation -> CompletePartialCacheValidation -> // BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest -> -// UpdateCachedResponse -> CacheWriteResponse* -> UpdateCachedResponseComplete -// -> OverwriteCachedResponse -> PartialHeadersReceived +// UpdateCachedResponse -> CacheWriteUpdatedResponse* -> +// UpdateCachedResponseComplete -> OverwriteCachedResponse -> +// PartialHeadersReceived // // Read() 1: // NetworkRead* -> CacheWriteData* @@ -804,24 +797,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 +808,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 +815,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 +829,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,10 +861,28 @@ 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(); break; + case STATE_CACHE_WRITE_UPDATED_RESPONSE: + DCHECK_EQ(OK, rv); + rv = DoCacheWriteUpdatedResponse(); + break; + case STATE_CACHE_WRITE_UPDATED_RESPONSE_COMPLETE: + rv = DoCacheWriteUpdatedResponseComplete(rv); + break; case STATE_UPDATE_CACHED_RESPONSE_COMPLETE: rv = DoUpdateCachedResponseComplete(rv); break; @@ -872,6 +890,13 @@ 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_RESPONSE_COMPLETE: + rv = DoCacheWriteResponseComplete(rv); + break; case STATE_TRUNCATE_CACHED_DATA: DCHECK_EQ(OK, rv); rv = DoTruncateCachedData(); @@ -890,35 +915,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 +922,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); @@ -946,6 +942,13 @@ int HttpCache::Transaction::DoLoop(int result) { case STATE_CACHE_WRITE_DATA_COMPLETE: rv = DoCacheWriteDataComplete(rv); break; + case STATE_CACHE_WRITE_TRUNCATED_RESPONSE: + DCHECK_EQ(OK, rv); + rv = DoCacheWriteTruncatedResponse(); + break; + case STATE_CACHE_WRITE_TRUNCATED_RESPONSE_COMPLETE: + rv = DoCacheWriteTruncatedResponseComplete(rv); + break; default: NOTREACHED() << "bad state"; rv = ERR_FAILED; @@ -953,8 +956,10 @@ int HttpCache::Transaction::DoLoop(int result) { } } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); - if (rv != ERR_IO_PENDING) - HandleResult(rv); + if (rv != ERR_IO_PENDING && !callback_.is_null()) { + read_buf_ = NULL; // Release the buffer before invoking the callback. + base::ResetAndReturn(&callback_).Run(rv); + } return rv; } @@ -1016,7 +1021,7 @@ int HttpCache::Transaction::DoGetBackendComplete(int result) { return ERR_CACHE_MISS; if (mode_ == NONE) { - if (partial_.get()) { + if (partial_) { partial_->RestoreHeaders(&custom_request_->extra_headers); partial_.reset(); } @@ -1031,192 +1036,6 @@ 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::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); - } - - 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_); @@ -1282,6 +1101,24 @@ int HttpCache::Transaction::DoOpenEntryComplete(int result) { return ERR_CACHE_MISS; } +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::DoCreateEntry() { DCHECK(!new_entry_); next_state_ = STATE_CREATE_ENTRY_COMPLETE; @@ -1297,45 +1134,29 @@ int HttpCache::Transaction::DoCreateEntryComplete(int result) { net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY, result); cache_pending_ = false; - next_state_ = STATE_ADD_TO_ENTRY; + switch (result) { + case OK: + next_state_ = STATE_ADD_TO_ENTRY; + break; - if (result == ERR_CACHE_RACE) { - next_state_ = STATE_INIT_ENTRY; - return OK; - } + case ERR_CACHE_RACE: + next_state_ = STATE_INIT_ENTRY; + break; - if (result != OK) { - // We have a race here: Maybe we failed to open the entry and decided to - // create one, but by the time we called create, another transaction already - // created the entry. If we want to eliminate this issue, we need an atomic - // OpenOrCreate() method exposed by the disk cache. - DLOG(WARNING) << "Unable to create cache entry"; - mode_ = NONE; - if (partial_.get()) - partial_->RestoreHeaders(&custom_request_->extra_headers); - next_state_ = STATE_SEND_REQUEST; + default: + // We have a race here: Maybe we failed to open the entry and decided to + // create one, but by the time we called create, another transaction + // already created the entry. If we want to eliminate this issue, we + // need an atomic OpenOrCreate() method exposed by the disk cache. + DLOG(WARNING) << "Unable to create cache entry"; + mode_ = NONE; + if (partial_) + partial_->RestoreHeaders(&custom_request_->extra_headers); + next_state_ = STATE_SEND_REQUEST; } 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; @@ -1416,7 +1237,7 @@ int HttpCache::Transaction::DoAddToEntryComplete(int result) { } if (mode_ == WRITE) { - if (partial_.get()) + if (partial_) partial_->RestoreHeaders(&custom_request_->extra_headers); next_state_ = STATE_SEND_REQUEST; } else { @@ -1427,6 +1248,121 @@ 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. + + // TODO(rtenneti): Remove ScopedTracker below once crbug.com/422516 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "422516 HttpCache::Transaction::DoCacheToggleUnusedSincePrefetch")); + + next_state_ = STATE_TOGGLE_UNUSED_SINCE_PREFETCH_COMPLETE; + return WriteResponseInfoToEntry(false); +} + +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 OnWriteResponseInfoToEntryComplete(result); +} + +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) @@ -1462,6 +1398,173 @@ int HttpCache::Transaction::DoCompletePartialCacheValidation(int result) { 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(); + old_remote_endpoint_ = IPEndPoint(); + + 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); + } + + 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; +} + // We received 304 or 206 and we want to update the cached response headers. int HttpCache::Transaction::DoUpdateCachedResponse() { next_state_ = STATE_UPDATE_CACHED_RESPONSE_COMPLETE; @@ -1493,14 +1596,28 @@ int HttpCache::Transaction::DoUpdateCachedResponse() { // If we are already reading, we already updated the headers for this // request; doing it again will change Content-Length. if (!reading_) { - target_state_ = STATE_UPDATE_CACHED_RESPONSE_COMPLETE; - next_state_ = STATE_CACHE_WRITE_RESPONSE; + next_state_ = STATE_CACHE_WRITE_UPDATED_RESPONSE; rv = OK; } } return rv; } +int HttpCache::Transaction::DoCacheWriteUpdatedResponse() { + // TODO(rtenneti): Remove ScopedTracker below once crbug.com/422516 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "422516 HttpCache::Transaction::DoCacheWriteUpdatedResponse")); + + next_state_ = STATE_CACHE_WRITE_UPDATED_RESPONSE_COMPLETE; + return WriteResponseInfoToEntry(false); +} + +int HttpCache::Transaction::DoCacheWriteUpdatedResponseComplete(int result) { + next_state_ = STATE_UPDATE_CACHED_RESPONSE_COMPLETE; + return OnWriteResponseInfoToEntryComplete(result); +} + int HttpCache::Transaction::DoUpdateCachedResponseComplete(int result) { if (mode_ == UPDATE) { DCHECK(!handling_206_); @@ -1512,7 +1629,7 @@ int HttpCache::Transaction::DoUpdateCachedResponseComplete(int result) { DoneWritingToEntry(true); } else if (entry_ && !handling_206_) { DCHECK_EQ(READ_WRITE, mode_); - if (!partial_.get() || partial_->IsLastRange()) { + if (!partial_ || partial_->IsLastRange()) { cache_->ConvertWriterToReader(entry_); mode_ = READ; } @@ -1541,7 +1658,7 @@ int HttpCache::Transaction::DoOverwriteCachedResponse() { } // We change the value of Content-Length for partial content. - if (handling_206_ && partial_.get()) + if (handling_206_ && partial_) partial_->FixContentLength(new_response_->headers.get()); response_ = *new_response_; @@ -1558,18 +1675,31 @@ int HttpCache::Transaction::DoOverwriteCachedResponse() { // There is no point in storing this resource because it will never be used. // This may change if we support LOAD_ONLY_FROM_CACHE with sparse entries. DoneWritingToEntry(false); - if (partial_.get()) + if (partial_) partial_->FixResponseHeaders(response_.headers.get(), true); next_state_ = STATE_PARTIAL_HEADERS_RECEIVED; return OK; } - target_state_ = STATE_TRUNCATE_CACHED_DATA; - next_state_ = truncated_ ? STATE_CACHE_WRITE_TRUNCATED_RESPONSE : - STATE_CACHE_WRITE_RESPONSE; + next_state_ = STATE_CACHE_WRITE_RESPONSE; 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")); + + next_state_ = STATE_CACHE_WRITE_RESPONSE_COMPLETE; + return WriteResponseInfoToEntry(truncated_); +} + +int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) { + next_state_ = STATE_TRUNCATE_CACHED_DATA; + return OnWriteResponseInfoToEntryComplete(result); +} + int HttpCache::Transaction::DoTruncateCachedData() { next_state_ = STATE_TRUNCATE_CACHED_DATA_COMPLETE; if (!entry_) @@ -1616,11 +1746,10 @@ int HttpCache::Transaction::DoTruncateCachedMetadataComplete(int result) { int HttpCache::Transaction::DoPartialHeadersReceived() { new_response_ = NULL; - if (entry_ && !partial_.get() && - entry_->disk_entry->GetDataSize(kMetadataIndex)) + if (entry_ && !partial_ && entry_->disk_entry->GetDataSize(kMetadataIndex)) next_state_ = STATE_CACHE_READ_METADATA; - if (!partial_.get()) + if (!partial_) return OK; if (reading_) { @@ -1637,142 +1766,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,26 +1788,36 @@ 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() { + if (request_->method == "HEAD") + return 0; + DCHECK(entry_); next_state_ = STATE_CACHE_READ_DATA_COMPLETE; if (net_log_.IsCapturing()) net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_DATA); - if (partial_.get()) { + if (partial_) { return partial_->CacheRead(entry_->disk_entry, read_buf_.get(), io_buf_len_, io_callback_); } @@ -1833,7 +1836,7 @@ int HttpCache::Transaction::DoCacheReadDataComplete(int result) { if (!cache_.get()) return ERR_UNEXPECTED; - if (partial_.get()) { + if (partial_) { // Partial requests are confusing to report in histograms because they may // have multiple underlying requests. UpdateTransactionPattern(PATTERN_NOT_COVERED); @@ -1875,7 +1878,6 @@ int HttpCache::Transaction::DoCacheWriteDataComplete(int result) { result); } } - // Balance the AddRef from DoCacheWriteData. if (!cache_.get()) return ERR_UNEXPECTED; @@ -1886,31 +1888,42 @@ int HttpCache::Transaction::DoCacheWriteDataComplete(int result) { // We want to ignore errors writing to disk and just keep reading from // the network. result = write_len_; - } else if (!done_reading_ && entry_) { + } else if (!done_reading_ && entry_ && (!partial_ || truncated_)) { int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex); int64 body_size = response_.headers->GetContentLength(); if (body_size >= 0 && body_size <= current_size) done_reading_ = true; } - if (partial_.get()) { + if (partial_) { // This may be the last request. - if (!(result == 0 && !truncated_ && - (partial_->IsLastRange() || mode_ == WRITE))) + if (result != 0 || truncated_ || + !(partial_->IsLastRange() || mode_ == WRITE)) { return DoPartialNetworkReadCompleted(result); + } } if (result == 0) { // End of file. This may be the result of a connection problem so see if we // have to keep the entry around to be flagged as truncated later on. - if (done_reading_ || !entry_ || partial_.get() || - response_.headers->GetContentLength() <= 0) + if (done_reading_ || !entry_ || partial_ || + response_.headers->GetContentLength() <= 0) { DoneWritingToEntry(true); + } } return result; } +int HttpCache::Transaction::DoCacheWriteTruncatedResponse() { + next_state_ = STATE_CACHE_WRITE_TRUNCATED_RESPONSE_COMPLETE; + return WriteResponseInfoToEntry(true); +} + +int HttpCache::Transaction::DoCacheWriteTruncatedResponseComplete(int result) { + return OnWriteResponseInfoToEntryComplete(result); +} + //----------------------------------------------------------------------------- void HttpCache::Transaction::ReadCertChain() { @@ -2098,7 +2111,7 @@ bool HttpCache::Transaction::ShouldPassThrough() { int HttpCache::Transaction::BeginCacheRead() { // We don't support any combination of LOAD_ONLY_FROM_CACHE and byte ranges. - if (response_.headers->response_code() == 206 || partial_.get()) { + if (response_.headers->response_code() == 206 || partial_) { NOTREACHED(); return ERR_CACHE_MISS; } @@ -2117,12 +2130,19 @@ int HttpCache::Transaction::BeginCacheRead() { } int HttpCache::Transaction::BeginCacheValidation() { - DCHECK(mode_ == READ_WRITE); + DCHECK_EQ(mode_, READ_WRITE); ValidationType required_validation = RequiresValidation(); bool skip_validation = (required_validation == VALIDATION_NONE); + if ((effective_load_flags_ & LOAD_SUPPORT_ASYNC_REVALIDATION) && + required_validation == VALIDATION_ASYNCHRONOUS) { + DCHECK_EQ(request_->method, "GET"); + skip_validation = true; + response_.async_revalidation_required = true; + } + if (request_->method == "HEAD" && (truncated_ || response_.headers->response_code() == 206)) { DCHECK(!partial_); @@ -2142,7 +2162,7 @@ int HttpCache::Transaction::BeginCacheValidation() { skip_validation = !partial_->initial_validation(); } - if (partial_.get() && (is_sparse_ || truncated_) && + if (partial_ && (is_sparse_ || truncated_) && (!partial_->IsCurrentRangeCached() || invalid_range_)) { // Force revalidation for sparse or truncated entries. Note that we don't // want to ignore the regular validation logic just because a byte range was @@ -2163,7 +2183,7 @@ int HttpCache::Transaction::BeginCacheValidation() { if (!ConditionalizeRequest()) { couldnt_conditionalize_request_ = true; UpdateTransactionPattern(PATTERN_ENTRY_CANT_CONDITIONALIZE); - if (partial_.get()) + if (partial_) return DoRestartPartialRequest(); DCHECK_NE(206, response_.headers->response_code()); @@ -2174,38 +2194,34 @@ int HttpCache::Transaction::BeginCacheValidation() { } int HttpCache::Transaction::BeginPartialCacheValidation() { - DCHECK(mode_ == READ_WRITE); + DCHECK_EQ(mode_, READ_WRITE); - if (response_.headers->response_code() != 206 && !partial_.get() && - !truncated_) { + if (response_.headers->response_code() != 206 && !partial_ && !truncated_) return BeginCacheValidation(); - } // Partial requests should not be recorded in histograms. UpdateTransactionPattern(PATTERN_NOT_COVERED); - if (range_requested_) { - next_state_ = STATE_CACHE_QUERY_DATA; - return OK; - } - - // The request is not for a range, but we have stored just ranges. - if (request_->method == "HEAD") return BeginCacheValidation(); - partial_.reset(new PartialData()); - partial_->SetHeaders(request_->extra_headers); - if (!custom_request_.get()) { - custom_request_.reset(new HttpRequestInfo(*request_)); - request_ = custom_request_.get(); + if (!range_requested_) { + // The request is not for a range, but we have stored just ranges. + + partial_.reset(new PartialData()); + partial_->SetHeaders(request_->extra_headers); + if (!custom_request_.get()) { + custom_request_.reset(new HttpRequestInfo(*request_)); + request_ = custom_request_.get(); + } } - return ValidateEntryHeadersAndContinue(); + next_state_ = STATE_CACHE_QUERY_DATA; + return OK; } // This should only be called once per request. int HttpCache::Transaction::ValidateEntryHeadersAndContinue() { - DCHECK(mode_ == READ_WRITE); + DCHECK_EQ(mode_, READ_WRITE); if (!partial_->UpdateFromStoredHeaders( response_.headers.get(), entry_->disk_entry, truncated_)) { @@ -2254,7 +2270,7 @@ int HttpCache::Transaction::BeginExternallyConditionalizedRequest() { EXTERNALLY_CONDITIONALIZED_CACHE_USABLE; if (mode_ == NONE) type = EXTERNALLY_CONDITIONALIZED_MISMATCHED_VALIDATORS; - else if (RequiresValidation()) + else if (RequiresValidation() != VALIDATION_NONE) type = EXTERNALLY_CONDITIONALIZED_CACHE_REQUIRES_VALIDATION; // TODO(ricea): Add CACHE_USABLE_STALE once stale-while-revalidate CL landed. @@ -2384,15 +2400,15 @@ bool HttpCache::Transaction::ConditionalizeRequest() { if (etag_value.empty() && last_modified_value.empty()) return false; - if (!partial_.get()) { + if (!partial_) { // Need to customize the request, so this forces us to allocate :( custom_request_.reset(new HttpRequestInfo(*request_)); request_ = custom_request_.get(); } DCHECK(custom_request_.get()); - bool use_if_range = partial_.get() && !partial_->IsCurrentRangeCached() && - !invalid_range_; + bool use_if_range = + partial_ && !partial_->IsCurrentRangeCached() && !invalid_range_; if (!use_if_range) { // stale-while-revalidate is not useful when we only have a partial response @@ -2426,7 +2442,7 @@ bool HttpCache::Transaction::ConditionalizeRequest() { } // For byte-range requests, make sure that we use only one way to validate // the request. - if (partial_.get() && !partial_->IsCurrentRangeCached()) + if (partial_ && !partial_->IsCurrentRangeCached()) return true; } @@ -2490,7 +2506,7 @@ bool HttpCache::Transaction::ValidatePartialResponse() { return true; } - if (!partial_.get()) { + if (!partial_) { // We are not expecting 206 but we may have one. if (partial_response) IgnoreRangeRequest(); @@ -2591,7 +2607,7 @@ void HttpCache::Transaction::FixHeadersForHead() { int HttpCache::Transaction::SetupEntryForRead() { if (network_trans_) ResetNetworkTransaction(); - if (partial_.get()) { + if (partial_) { if (truncated_ || is_sparse_ || !invalid_range_) { // We are going to return the saved response headers to the caller, so // we may need to adjust them first. @@ -2612,24 +2628,6 @@ int HttpCache::Transaction::SetupEntryForRead() { return OK; } - -int HttpCache::Transaction::ReadFromNetwork(IOBuffer* data, int data_len) { - read_buf_ = data; - io_buf_len_ = data_len; - next_state_ = STATE_NETWORK_READ; - return DoLoop(OK); -} - -int HttpCache::Transaction::ReadFromEntry(IOBuffer* data, int data_len) { - if (request_->method == "HEAD") - return 0; - - read_buf_ = data; - io_buf_len_ = data_len; - next_state_ = STATE_CACHE_READ_DATA; - return DoLoop(OK); -} - int HttpCache::Transaction::WriteToEntry(int index, int offset, IOBuffer* data, int data_len, const CompletionCallback& callback) { @@ -2637,7 +2635,7 @@ int HttpCache::Transaction::WriteToEntry(int index, int offset, return data_len; int rv = 0; - if (!partial_.get() || !data_len) { + if (!partial_ || !data_len) { rv = entry_->disk_entry->WriteData(index, offset, data, data_len, callback, true); } else { @@ -2647,10 +2645,12 @@ int HttpCache::Transaction::WriteToEntry(int index, int offset, } int HttpCache::Transaction::WriteResponseInfoToEntry(bool truncated) { - next_state_ = STATE_CACHE_WRITE_RESPONSE_COMPLETE; if (!entry_) return OK; + if (net_log_.IsCapturing()) + net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO); + // Do not cache no-store content. Do not cache content with cert errors // either. This is to prevent not reporting net errors when loading a // resource from the cache. When we load a page over HTTPS with a cert error @@ -2686,6 +2686,21 @@ int HttpCache::Transaction::WriteResponseInfoToEntry(bool truncated) { io_buf_len_, io_callback_, true); } +int HttpCache::Transaction::OnWriteResponseInfoToEntryComplete(int result) { + if (!entry_) + return OK; + if (net_log_.IsCapturing()) { + net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_INFO, + result); + } + + if (result != io_buf_len_) { + DLOG(ERROR) << "failed to write response info to cache"; + DoneWritingToEntry(false); + } + return OK; +} + void HttpCache::Transaction::DoneWritingToEntry(bool success) { if (!entry_) return; @@ -2807,10 +2822,13 @@ void HttpCache::Transaction::ResetNetworkTransaction() { if (network_trans_->GetLoadTimingInfo(&load_timing)) old_network_trans_load_timing_.reset(new LoadTimingInfo(load_timing)); total_received_bytes_ += network_trans_->GetTotalReceivedBytes(); + total_sent_bytes_ += network_trans_->GetTotalSentBytes(); ConnectionAttempts attempts; network_trans_->GetConnectionAttempts(&attempts); for (const auto& attempt : attempts) old_connection_attempts_.push_back(attempt); + old_remote_endpoint_ = IPEndPoint(); + network_trans_->GetRemoteEndpoint(&old_remote_endpoint_); network_trans_.reset(); } |