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 77ea96c12ec3f44cd5c71a34df112c7ecc0cb1d4..89fe2ddbfc8f8e204b7d26abdcd357c2e5d12f39 100644 |
| --- a/net/http/http_cache_transaction.cc |
| +++ b/net/http/http_cache_transaction.cc |
| @@ -263,9 +263,10 @@ HttpCache::Transaction::Transaction(RequestPriority priority, HttpCache* cache) |
| range_requested_(false), |
| handling_206_(false), |
| cache_pending_(false), |
| - done_reading_(false), |
| + done_writing_(false), |
| vary_mismatch_(false), |
| couldnt_conditionalize_request_(false), |
| + stopped_caching_(false), |
| bypass_lock_for_test_(false), |
| fail_conditionalization_for_test_(false), |
| io_buf_len_(0), |
| @@ -300,7 +301,7 @@ HttpCache::Transaction::~Transaction() { |
| } |
| } |
| - cache_->DoneWithEntry(entry_, this, cancel_request); |
| + DoneWithEntry(cancel_request); |
| } else if (cache_pending_) { |
| cache_->RemovePendingTransaction(this); |
| } |
| @@ -334,7 +335,7 @@ bool HttpCache::Transaction::AddTruncatedFlag() { |
| return false; |
| // We may have received the whole resource already. |
| - if (done_reading_) |
| + if (done_writing_) |
| return true; |
| truncated_ = true; |
| @@ -366,7 +367,7 @@ int HttpCache::Transaction::Start(const HttpRequestInfo* request, |
| DCHECK(!reading_); |
| DCHECK(!network_trans_.get()); |
| DCHECK(!entry_); |
| - DCHECK_EQ(next_state_, STATE_NONE); |
| + DCHECK_EQ(STATE_NONE, next_state_); |
|
rvargas (doing something else)
2015/07/27 22:25:12
Don't invert the arguments. DCHECKs should read li
asanka
2015/08/18 22:46:59
Done.
|
| if (!cache_.get()) |
| return ERR_UNEXPECTED; |
| @@ -391,6 +392,7 @@ int HttpCache::Transaction::RestartIgnoringLastError( |
| // Ensure that we only have one asynchronous call at a time. |
| DCHECK(callback_.is_null()); |
| + DCHECK_EQ(STATE_NONE, next_state_); |
| if (!cache_.get()) |
| return ERR_UNEXPECTED; |
| @@ -410,6 +412,7 @@ int HttpCache::Transaction::RestartWithCertificate( |
| // Ensure that we only have one asynchronous call at a time. |
| DCHECK(callback_.is_null()); |
| + DCHECK_EQ(STATE_NONE, next_state_); |
| if (!cache_.get()) |
| return ERR_UNEXPECTED; |
| @@ -430,6 +433,7 @@ int HttpCache::Transaction::RestartWithAuth( |
| // Ensure that we only have one asynchronous call at a time. |
| DCHECK(callback_.is_null()); |
| + DCHECK_EQ(STATE_NONE, next_state_); |
| if (!cache_.get()) |
| return ERR_UNEXPECTED; |
| @@ -453,12 +457,13 @@ 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()); |
| + // Ensure that we only have one asynchronous call at a time. |
| DCHECK(callback_.is_null()); |
| + DCHECK_EQ(next_state_, STATE_NONE); |
| if (!cache_.get()) |
| return ERR_UNEXPECTED; |
| @@ -495,21 +500,8 @@ int HttpCache::Transaction::Read(IOBuffer* buf, int buf_len, |
| } |
| void HttpCache::Transaction::StopCaching() { |
| - // We really don't know where we are now. Hopefully there is no operation in |
| - // progress, but nothing really prevents this method to be called after we |
| - // returned ERR_IO_PENDING. We cannot attempt to truncate the entry at this |
| - // point because we need the state machine for that (and even if we are really |
| - // free, that would be an asynchronous operation). In other words, keep the |
| - // entry how it is (it will be marked as truncated at destruction), and let |
| - // the next piece of code that executes know that we are now reading directly |
| - // from the net. |
| - // TODO(mmenke): This doesn't release the lock on the cache entry, so a |
| - // future request for the resource will be blocked on this one. |
| - // Fix this. |
| - if (cache_.get() && entry_ && (mode_ & WRITE) && network_trans_.get() && |
| - !is_sparse_ && !range_requested_) { |
| - mode_ = NONE; |
| - } |
| + stopped_caching_ = true; |
| + UpdateTransactionPattern(PATTERN_NOT_COVERED); |
| } |
| bool HttpCache::Transaction::GetFullRequestHeaders( |
| @@ -529,18 +521,8 @@ int64 HttpCache::Transaction::GetTotalReceivedBytes() const { |
| } |
| void HttpCache::Transaction::DoneReading() { |
| - if (cache_.get() && entry_) { |
| - DCHECK_NE(mode_, UPDATE); |
| - if (mode_ & WRITE) { |
| - DoneWritingToEntry(true); |
| - } else if (mode_ & READ) { |
| - // It is necessary to check mode_ & READ because it is possible |
| - // for mode_ to be NONE and entry_ non-NULL with a write entry |
| - // if StopCaching was called. |
| - cache_->DoneReadingFromEntry(entry_, this); |
| - entry_ = NULL; |
| - } |
| - } |
| + DCHECK_NE(mode_, UPDATE); |
| + DoneWithRequest(); |
| } |
| const HttpResponseInfo* HttpCache::Transaction::GetResponseInfo() const { |
| @@ -1353,16 +1335,9 @@ int HttpCache::Transaction::DoStartPartialCacheValidation() { |
| } |
| 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; |
| - } |
| + // This is the end of the request. |
| + if (!result) |
| + return DoneWithRequest(); |
| if (result < 0) |
| return result; |
| @@ -1508,9 +1483,7 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() { |
| int ret = cache_->DoomEntry(cache_key_, NULL); |
| DCHECK_EQ(OK, ret); |
| } |
| - cache_->DoneWritingToEntry(entry_, true); |
| - entry_ = NULL; |
| - mode_ = NONE; |
| + DoneWritingToEntry(true); |
| } |
| // Invalidate any cached GET with a successful POST. |
| @@ -1645,7 +1618,6 @@ int HttpCache::Transaction::DoOverwriteCachedResponse() { |
| if (request_->method == "HEAD") { |
| // This response is replacing the cached one. |
| DoneWritingToEntry(false); |
| - mode_ = NONE; |
| new_response_ = NULL; |
| return OK; |
| } |
| @@ -1778,11 +1750,21 @@ int HttpCache::Transaction::DoNetworkReadComplete(int result) { |
| 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) |
| + if (result < 0) |
| return result; |
| + // Skip writing if StopCaching() has been called. |
| + // |
| + // For partial requests the transaction still needs to update its state. If |
| + // the network transaction being read was conditionalized, the cache |
| + // transaction may need to issue additional network or cache reads to fulfil |
| + // the original request. |
| + if (stopped_caching_ && partial_) |
| + return DoPartialNetworkReadCompleted(result); |
| + |
| + if (mode_ == NONE || stopped_caching_) |
| + return DoReadComplete(result); |
| + |
| next_state_ = STATE_CACHE_WRITE_DATA; |
| return result; |
| } |
| @@ -1851,12 +1833,9 @@ int HttpCache::Transaction::DoCacheWriteData(int num_bytes) { |
| } |
| int HttpCache::Transaction::DoCacheWriteDataComplete(int result) { |
| - if (entry_) { |
| - if (net_log_.IsCapturing()) { |
| - net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_DATA, |
| - result); |
| - } |
| - } |
| + if (entry_ && net_log_.IsCapturing()) |
|
rvargas (doing something else)
2015/07/27 22:25:12
needs {}
asanka
2015/08/18 22:46:59
Done.
|
| + net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_DATA, |
| + result); |
| if (!cache_.get()) |
| return ERR_UNEXPECTED; |
| @@ -1867,11 +1846,11 @@ 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_writing_ && entry_) { |
| 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; |
| + done_writing_ = true; |
|
rvargas (doing something else)
2015/07/27 22:25:12
We should probably keep the old name. So far, it s
asanka
2015/08/18 22:46:59
Changed to the old name.
|
| } |
| if (partial_) { |
| @@ -1885,10 +1864,9 @@ int HttpCache::Transaction::DoCacheWriteDataComplete(int 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_ || |
| - response_.headers->GetContentLength() <= 0) { |
| + if (done_writing_ || !entry_ || partial_ || |
| + response_.headers->GetContentLength() <= 0) |
|
rvargas (doing something else)
2015/07/27 22:25:12
needs {}
asanka
2015/08/18 22:46:59
Done.
|
| DoneWritingToEntry(true); |
| - } |
| } |
| return result; |
| @@ -2673,6 +2651,31 @@ int HttpCache::Transaction::OnWriteResponseInfoToEntryComplete(int result) { |
| return OK; |
| } |
| +int HttpCache::Transaction::DoneWithRequest() { |
| + DCHECK_EQ(STATE_NONE, next_state_); |
| + |
| + if (!cache_ || !entry_) |
| + return OK; |
| + |
| + if (!(mode_ & WRITE)) { |
| + cache_->DoneReadingFromEntry(entry_, this); |
| + entry_ = nullptr; |
| + return OK; |
| + } |
| + |
| + if (stopped_caching_ && !is_sparse_ && !done_writing_ && !entry_->doomed) { |
| + if (CanResume(true)) { |
| + truncated_ = true; |
| + return DoCacheWriteTruncatedResponse(); |
|
rvargas (doing something else)
2015/07/27 22:25:12
This may return pending and that is not expected b
asanka
2015/08/18 22:46:59
This code was removed in the latest patch set.
|
| + } |
| + int ret = cache_->DoomEntry(cache_key_, nullptr); |
| + DCHECK_EQ(OK, ret); |
| + } |
| + |
| + DoneWritingToEntry(true); |
| + return OK; |
| +} |
| + |
| void HttpCache::Transaction::DoneWritingToEntry(bool success) { |
| if (!entry_) |
| return; |
| @@ -2684,6 +2687,13 @@ void HttpCache::Transaction::DoneWritingToEntry(bool success) { |
| mode_ = NONE; // switch to 'pass through' mode |
| } |
| +void HttpCache::Transaction::DoneWithEntry(bool cancel) { |
| + cache_->DoneWithEntry(entry_, this, cancel); |
| + entry_ = nullptr; |
| + is_sparse_ = false; |
| + truncated_ = false; |
| +} |
| + |
| int HttpCache::Transaction::OnCacheReadError(int result, bool restart) { |
| DLOG(ERROR) << "ReadData failed: " << result; |
| const int result_for_histogram = std::max(0, -result); |
| @@ -2702,9 +2712,7 @@ int HttpCache::Transaction::OnCacheReadError(int result, bool restart) { |
| if (restart) { |
| DCHECK(!reading_); |
| DCHECK(!network_trans_.get()); |
| - cache_->DoneWithEntry(entry_, this, false); |
| - entry_ = NULL; |
| - is_sparse_ = false; |
| + DoneWithEntry(false); |
| partial_.reset(); |
| next_state_ = STATE_GET_BACKEND; |
| return OK; |
| @@ -2730,12 +2738,9 @@ void HttpCache::Transaction::DoomPartialEntry(bool delete_object) { |
| DVLOG(2) << "DoomPartialEntry"; |
| int rv = cache_->DoomEntry(cache_key_, NULL); |
| DCHECK_EQ(OK, rv); |
| - cache_->DoneWithEntry(entry_, this, false); |
| - entry_ = NULL; |
| - is_sparse_ = false; |
| - truncated_ = false; |
| + DoneWithEntry(false); |
| if (delete_object) |
| - partial_.reset(NULL); |
| + partial_.reset(); |
| } |
| int HttpCache::Transaction::DoPartialNetworkReadCompleted(int result) { |
| @@ -2745,8 +2750,9 @@ int HttpCache::Transaction::DoPartialNetworkReadCompleted(int result) { |
| // We need to move on to the next range. |
| ResetNetworkTransaction(); |
| next_state_ = STATE_START_PARTIAL_CACHE_VALIDATION; |
| + return OK; |
| } |
| - return result; |
| + return DoReadComplete(result); |
| } |
| int HttpCache::Transaction::DoPartialCacheReadCompleted(int result) { |
| @@ -2773,6 +2779,47 @@ int HttpCache::Transaction::DoRestartPartialRequest() { |
| return OK; |
| } |
| +int HttpCache::Transaction::DoReadComplete(int result) { |
| + DCHECK(mode_ & WRITE || mode_ == NONE); |
| + DCHECK(cache_); |
| + DCHECK_LE(0, result); |
| + DCHECK(reading_); |
| + |
| + // If there is no partial data, or if this is the last range of, then all the |
| + // remaining bytes of the response are going to be coming from the network. |
| + // Hence we can release the cache entry and switch to passthrough mode. |
| + if ((mode_ & WRITE) && stopped_caching_ && |
| + (!partial_ || partial_->IsLastRange())) |
|
rvargas (doing something else)
2015/07/27 22:25:12
needs {}
asanka
2015/08/18 22:46:59
Done.
|
| + return BeginCacheEntryRelease(result); |
| + return result; |
| +} |
| + |
| +int HttpCache::Transaction::BeginCacheEntryRelease(int result_to_forward) { |
| + DCHECK_EQ(STATE_NONE, next_state_); |
| + DCHECK(stopped_caching_); |
| + |
| + // Any errors from the cache truncation operation is going to be ignored. |
| + // There's not much the caller can do about it. |
| + callback_ = base::Bind(&Transaction::OnCacheReleaseComplete, |
|
rvargas (doing something else)
2015/07/27 22:25:12
This is surprising. So far callback_ is always a c
asanka
2015/08/18 22:46:59
Yeah. This was removed.
|
| + weak_factory_.GetWeakPtr(), |
| + base::Bind(callback_, result_to_forward)); |
| + return DoneWithRequest(); |
| +} |
| + |
| +void HttpCache::Transaction::OnCacheReleaseComplete( |
|
rvargas (doing something else)
2015/07/27 22:25:12
Why is this not part of the state machine?
asanka
2015/08/18 22:46:59
Point taken, but this code was removed.
|
| + const base::Closure& closure, |
| + int result) { |
| + // TODO(asanka): Clean this up. |
| + if (entry_) { |
| + DCHECK(mode_ & WRITE); |
| + DoneWritingToEntry(true); |
| + } |
| + mode_ = NONE; |
| + stopped_caching_ = false; |
| + if (!closure.is_null()) |
| + closure.Run(); |
| +} |
| + |
| void HttpCache::Transaction::ResetPartialState(bool delete_object) { |
| partial_->RestoreHeaders(&custom_request_->extra_headers); |
| DoomPartialEntry(delete_object); |