Index: net/http/http_cache.cc |
=================================================================== |
--- net/http/http_cache.cc (revision 22968) |
+++ net/http/http_cache.cc (working copy) |
@@ -309,6 +309,9 @@ |
// copy is valid). Returns true if able to make the request conditional. |
bool ConditionalizeRequest(); |
+ // Makes sure that a 206 response is expected. Returns a network error code. |
+ bool ValidatePartialResponse(const HttpResponseHeaders* headers); |
+ |
// Reads data from the network. |
int ReadFromNetwork(IOBuffer* data, int data_len); |
@@ -335,6 +338,10 @@ |
// Called when we are done writing to the cache entry. |
void DoneWritingToEntry(bool success); |
+ // Deletes the current partial cache entry (sparse), and optionally removes |
+ // the control object (partial_). |
+ void DoomPartialEntry(bool delete_object); |
+ |
// Performs the needed work after receiving data from the network. |
int DoNetworkReadCompleted(int result); |
@@ -798,6 +805,7 @@ |
} else { |
// The range is invalid or we cannot handle it properly. |
effective_load_flags_ |= LOAD_DISABLE_CACHE; |
+ partial_.reset(NULL); |
} |
} |
@@ -883,15 +891,23 @@ |
return BeginCacheValidation(); |
#endif |
- if (!partial_.get()) { |
+ bool byte_range_requested = partial_.get() != NULL; |
+ if (!byte_range_requested) { |
// The request is not for a range, but we have stored just ranges. |
- // TODO(rvargas): Add support for this case. |
- NOTREACHED(); |
+ partial_.reset(new PartialData()); |
+ if (!custom_request_.get()) { |
+ custom_request_.reset(new HttpRequestInfo(*request_)); |
+ request_ = custom_request_.get(); |
+ DCHECK(custom_request_->extra_headers.empty()); |
+ } |
} |
- if (!partial_->UpdateFromStoredHeaders(response_.headers)) { |
- // TODO(rvargas): Handle this error. |
- NOTREACHED(); |
+ if (!partial_->UpdateFromStoredHeaders(response_.headers, |
+ entry_->disk_entry)) { |
+ // The stored data cannot be used. Get rid of it and restart this request. |
+ DoomPartialEntry(!byte_range_requested); |
+ mode_ = WRITE; |
+ return AddToEntry(); |
} |
return ContinuePartialCacheValidation(); |
@@ -899,8 +915,6 @@ |
int HttpCache::Transaction::ContinuePartialCacheValidation() { |
DCHECK(mode_ == READ_WRITE); |
- // TODO(rvargas): Avoid re-validation of each cached piece. |
- |
int rv = partial_->PrepareCacheValidation(entry_->disk_entry, |
&custom_request_->extra_headers); |
@@ -914,6 +928,15 @@ |
return HandleResult(rv); |
} |
+ if (reading_ && partial_->IsCurrentRangeCached()) { |
+ rv = ReadFromEntry(read_buf_, read_buf_len_); |
+ |
+ // We are supposed to hanlde errors here. |
+ if (rv < 0 && rv != ERR_IO_PENDING) |
+ HandleResult(rv); |
+ return rv; |
+ } |
+ |
return BeginCacheValidation(); |
} |
@@ -1080,6 +1103,50 @@ |
return true; |
} |
+bool HttpCache::Transaction::ValidatePartialResponse( |
+ const HttpResponseHeaders* headers) { |
+#ifdef ENABLE_RANGE_SUPPORT |
+ bool partial_content = headers->response_code() == 206; |
+#else |
+ bool partial_content = false; |
+#endif |
+ |
+ bool failure = false; |
+ if (!partial_content) { |
+ if (!partial_.get()) |
+ return false; |
+ |
+ // TODO(rvargas): Do we need to consider other results here?. |
+ if (headers->response_code() == 200 || headers->response_code() == 416) |
+ failure = true; |
+ |
+ if (!reading_ && failure) { |
+ // We are expecting 206 or 304 because we asked for a range. Given that |
+ // the server is refusing the request we'll remove the sparse entry. |
+ DoomPartialEntry(true); |
+ mode_ = NONE; |
+ return false; |
+ } |
+ } |
+ |
+ if (!failure && partial_.get() && partial_->ResponseHeadersOK(headers)) |
+ return true; |
+ |
+ // We have a problem. We may or may not be reading already (in which case we |
+ // returned the headers), but we'll just pretend that this request is not |
+ // using the cache and see what happens. Most likely this is the first |
+ // response from the server (it's not changing its mind midway, right?). |
+ if (mode_ & WRITE) { |
+ DoneWritingToEntry(mode_ != WRITE); |
+ } else if (mode_ & READ && entry_) { |
+ cache_->DoneReadingFromEntry(entry_, this); |
+ } |
+ |
+ entry_ = NULL; |
+ mode_ = NONE; |
+ return false; |
+} |
+ |
int HttpCache::Transaction::ReadFromNetwork(IOBuffer* data, int data_len) { |
int rv = network_trans_->Read(data, data_len, &network_read_callback_); |
read_buf_ = data; |
@@ -1197,6 +1264,14 @@ |
mode_ = NONE; // switch to 'pass through' mode |
} |
+void HttpCache::Transaction::DoomPartialEntry(bool delete_object) { |
+ cache_->DoneWithEntry(entry_, this); |
+ cache_->DoomEntry(cache_key_); |
+ entry_ = NULL; |
+ if (delete_object) |
+ partial_.reset(NULL); |
+} |
+ |
void HttpCache::Transaction::OnNetworkInfoAvailable(int result) { |
DCHECK(result != ERR_IO_PENDING); |
@@ -1211,19 +1286,8 @@ |
new_response->headers->response_code() == 407) { |
auth_response_ = *new_response; |
} else { |
-#ifdef ENABLE_RANGE_SUPPORT |
- bool partial_content = new_response->headers->response_code() == 206; |
-#else |
- bool partial_content = false; |
-#endif |
- // TODO(rvargas): Validate partial_content vs partial_ and mode_ |
- if (partial_content) { |
- DCHECK(partial_.get()); |
- if (!partial_->ResponseHeadersOK(new_response->headers)) { |
- // TODO(rvargas): Handle this error. |
- NOTREACHED(); |
- } |
- } |
+ bool partial_content = ValidatePartialResponse(new_response->headers); |
+ |
// Are we expecting a response to a conditional query? |
if (mode_ == READ_WRITE || mode_ == UPDATE) { |
if (new_response->headers->response_code() == 304 || partial_content) { |