diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/http/http_cache_transaction.cc | 37 | ||||
-rw-r--r-- | net/http/http_cache_transaction.h | 7 | ||||
-rw-r--r-- | net/http/http_cache_unittest.cc | 31 | ||||
-rw-r--r-- | net/http/partial_data.cc | 46 | ||||
-rw-r--r-- | net/http/partial_data.h | 4 |
5 files changed, 98 insertions, 27 deletions
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc index a6ef5e0..96b1fff 100644 --- a/net/http/http_cache_transaction.cc +++ b/net/http/http_cache_transaction.cc @@ -672,7 +672,8 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() { return OK; } - if (!ValidatePartialResponse(new_response->headers, &server_responded_206_) && + new_response_ = new_response; + if (!ValidatePartialResponse(&server_responded_206_) && !auth_response_.headers) { // Something went wrong with this request and we have to restart it. // If we have an authentication response, we are exposed to weird things @@ -680,6 +681,7 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() { // the new response. response_ = HttpResponseInfo(); network_trans_.reset(); + new_response_ = NULL; next_state_ = STATE_SEND_REQUEST; return OK; } @@ -690,9 +692,14 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() { DoneWritingToEntry(false); } + if (enable_range_support_ && new_response_->headers->response_code() == 416) { + DCHECK_EQ(NONE, mode_); + response_ = *new_response_; + return OK; + } + HistogramHeaders(new_response->headers); - new_response_ = new_response; // Are we expecting a response to a conditional query? if (mode_ == READ_WRITE || mode_ == UPDATE) { if (new_response->headers->response_code() == 304 || @@ -1044,7 +1051,7 @@ int HttpCache::Transaction::DoPartialHeadersReceived() { } else if (mode_ != NONE) { // We are about to return the headers for a byte-range request to the user, // so let's fix them. - partial_->FixResponseHeaders(response_.headers); + partial_->FixResponseHeaders(response_.headers, true); } return OK; } @@ -1396,7 +1403,7 @@ int HttpCache::Transaction::BeginCacheValidation() { bool skip_validation = effective_load_flags_ & LOAD_PREFERRING_CACHE || !RequiresValidation(); - if (partial_.get() && !partial_->IsCurrentRangeCached()) + if (partial_.get() && !partial_->IsCurrentRangeCached() || invalid_range_) skip_validation = false; if (skip_validation) { @@ -1597,8 +1604,11 @@ bool HttpCache::Transaction::ConditionalizeRequest() { } DCHECK(custom_request_.get()); + bool use_if_range = partial_.get() && !partial_->IsCurrentRangeCached() && + !invalid_range_; + if (!etag_value.empty()) { - if (partial_.get() && !partial_->IsCurrentRangeCached()) { + if (use_if_range) { // We don't want to switch to WRITE mode if we don't have this block of a // byte-range request because we may have other parts cached. custom_request_->extra_headers.SetHeader( @@ -1614,7 +1624,7 @@ bool HttpCache::Transaction::ConditionalizeRequest() { } if (!last_modified_value.empty()) { - if (partial_.get() && !partial_->IsCurrentRangeCached()) { + if (use_if_range) { custom_request_->extra_headers.SetHeader( HttpRequestHeaders::kIfRange, last_modified_value); } else { @@ -1644,8 +1654,8 @@ bool HttpCache::Transaction::ConditionalizeRequest() { // WARNING: Whenever this code returns false, it has to make sure that the next // time it is called it will return true so that we don't keep retrying the // request. -bool HttpCache::Transaction::ValidatePartialResponse( - const HttpResponseHeaders* headers, bool* partial_content) { +bool HttpCache::Transaction::ValidatePartialResponse(bool* partial_content) { + const HttpResponseHeaders* headers = new_response_->headers; int response_code = headers->response_code(); bool partial_response = enable_range_support_ ? response_code == 206 : false; *partial_content = false; @@ -1657,10 +1667,13 @@ bool HttpCache::Transaction::ValidatePartialResponse( // We gave up trying to match this request with the stored data. If the // server is ok with the request, delete the entry, otherwise just ignore // this request - if (partial_response || response_code == 200 || response_code == 304) { + DCHECK(!reading_); + if (partial_response || response_code == 200) { DoomPartialEntry(true); mode_ = NONE; } else { + if (response_code == 304) + FailRangeRequest(); IgnoreRangeRequest(); } return true; @@ -1734,6 +1747,11 @@ void HttpCache::Transaction::IgnoreRangeRequest() { mode_ = NONE; } +void HttpCache::Transaction::FailRangeRequest() { + response_ = *new_response_; + partial_->FixResponseHeaders(response_.headers, false); +} + int HttpCache::Transaction::ReadFromNetwork(IOBuffer* data, int data_len) { read_buf_ = data; io_buf_len_ = data_len; @@ -1829,6 +1847,7 @@ void HttpCache::Transaction::DoneWritingToEntry(bool success) { } 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); diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h index 2883282..4d3673c 100644 --- a/net/http/http_cache_transaction.h +++ b/net/http/http_cache_transaction.h @@ -267,12 +267,15 @@ class HttpCache::Transaction : public HttpTransaction { // Makes sure that a 206 response is expected. Returns true on success. // On success, |partial_content| will be set to true if we are processing a // partial entry. - bool ValidatePartialResponse(const HttpResponseHeaders* headers, - bool* partial_content); + bool ValidatePartialResponse(bool* partial_content); // Handles a response validation error by bypassing the cache. void IgnoreRangeRequest(); + // Changes the response code of a range request to be 416 (Requested range not + // satisfiable). + void FailRangeRequest(); + // Reads data from the network. int ReadFromNetwork(IOBuffer* data, int data_len); diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc index 2c8e16d..eec8098 100644 --- a/net/http/http_cache_unittest.cc +++ b/net/http/http_cache_unittest.cc @@ -863,6 +863,7 @@ void RangeTransactionServer::RangeHandler(const net::HttpRequestInfo* request, std::string* response_data) { if (request->extra_headers.IsEmpty()) { response_status->assign("HTTP/1.1 416 Requested Range Not Satisfiable"); + response_data->clear(); return; } @@ -871,6 +872,7 @@ void RangeTransactionServer::RangeHandler(const net::HttpRequestInfo* request, if (not_modified_) { response_status->assign("HTTP/1.1 304 Not Modified"); + response_data->clear(); return; } @@ -885,6 +887,7 @@ void RangeTransactionServer::RangeHandler(const net::HttpRequestInfo* request, net::HttpByteRange byte_range = ranges[0]; if (byte_range.first_byte_position() > 79) { response_status->assign("HTTP/1.1 416 Requested Range Not Satisfiable"); + response_data->clear(); return; } @@ -3164,7 +3167,7 @@ TEST(HttpCache, UnknownRangeGET_304) { // Ask for the end of the file, without knowing the length. transaction.request_headers = "Range: bytes = 70-\r\n" EXTRA_HEADER; - transaction.data = "rg: 70-79 "; + transaction.data = ""; RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); // We just bypass the cache. @@ -3409,13 +3412,34 @@ TEST(HttpCache, RangeGET_Previous200) { // The last transaction has finished so make sure the entry is deactivated. MessageLoop::current()->RunAllPending(); + // Make a request for an invalid range. + MockTransaction transaction3(kRangeGET_TransactionOK); + transaction3.request_headers = "Range: bytes = 80-90\r\n" EXTRA_HEADER; + transaction3.data = ""; + transaction3.load_flags = net::LOAD_PREFERRING_CACHE; + RunTransactionTestWithResponse(cache.http_cache(), transaction3, &headers); + EXPECT_EQ(2, cache.disk_cache()->open_count()); + EXPECT_EQ(0U, headers.find("HTTP/1.1 416 ")); + EXPECT_NE(std::string::npos, headers.find("Content-Range: bytes 0-0/80")); + EXPECT_NE(std::string::npos, headers.find("Content-Length: 0")); + + // Make sure the entry is deactivated. + MessageLoop::current()->RunAllPending(); + + // Even though the request was invalid, we should have the entry. + RunTransactionTest(cache.http_cache(), transaction2); + EXPECT_EQ(3, cache.disk_cache()->open_count()); + + // Make sure the entry is deactivated. + MessageLoop::current()->RunAllPending(); + // Now we should receive a range from the server and drop the stored entry. handler.set_not_modified(false); transaction2.request_headers = kRangeGET_TransactionOK.request_headers; RunTransactionTestWithResponse(cache.http_cache(), transaction2, &headers); Verify206Response(headers, 40, 49); - EXPECT_EQ(3, cache.network_layer()->transaction_count()); - EXPECT_EQ(2, cache.disk_cache()->open_count()); + EXPECT_EQ(5, cache.network_layer()->transaction_count()); + EXPECT_EQ(4, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); RunTransactionTest(cache.http_cache(), transaction2); @@ -3484,6 +3508,7 @@ TEST(HttpCache, RangeGET_MoreThanCurrentSize) { // A weird request should not delete this entry. Ask for bytes 120-. MockTransaction transaction(kRangeGET_TransactionOK); transaction.request_headers = "Range: bytes = 120-\r\n" EXTRA_HEADER; + transaction.data = ""; RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); EXPECT_EQ(0U, headers.find("HTTP/1.1 416 ")); diff --git a/net/http/partial_data.cc b/net/http/partial_data.cc index 54900b3..799c3fa 100644 --- a/net/http/partial_data.cc +++ b/net/http/partial_data.cc @@ -127,6 +127,9 @@ bool PartialData::Init(const HttpRequestHeaders& headers) { resource_size_ = 0; current_range_start_ = byte_range_.first_byte_position(); + + DVLOG(1) << "Range start: " << current_range_start_ << " end: " << + byte_range_.last_byte_position(); return true; } @@ -154,6 +157,8 @@ int PartialData::ShouldValidateCache(disk_cache::Entry* entry, if (!len) return 0; + DVLOG(3) << "ShouldValidateCache len: " << len; + if (sparse_entry_) { DCHECK(!callback_); Core* core = Core::CreateCore(this); @@ -171,6 +176,12 @@ int PartialData::ShouldValidateCache(disk_cache::Entry* entry, cached_start_ = 0; } } else { + if (byte_range_.HasFirstBytePosition() && + byte_range_.first_byte_position() >= resource_size_) { + // The caller should take care of this condition because we should have + // failed IsRequestedRangeOK(), but it's better to be consistent here. + len = 0; + } cached_min_len_ = len; cached_start_ = current_range_start_; } @@ -250,6 +261,7 @@ bool PartialData::UpdateFromStoredHeaders(const HttpResponseHeaders* headers, DCHECK(byte_range_.IsValid()); sparse_entry_ = false; resource_size_ = entry->GetDataSize(kDataStream); + DVLOG(2) << "UpdateFromStoredHeaders size: " << resource_size_; return true; } @@ -335,28 +347,36 @@ bool PartialData::ResponseHeadersOK(const HttpResponseHeaders* headers) { // We are making multiple requests to complete the range requested by the user. // Just assume that everything is fine and say that we are returning what was // requested. -void PartialData::FixResponseHeaders(HttpResponseHeaders* headers) { +void PartialData::FixResponseHeaders(HttpResponseHeaders* headers, + bool success) { if (truncated_) return; headers->RemoveHeader(kLengthHeader); headers->RemoveHeader(kRangeHeader); - int64 range_len; + int64 range_len, start, end; if (byte_range_.IsValid()) { - if (!sparse_entry_) - headers->ReplaceStatusLine("HTTP/1.1 206 Partial Content"); + if (success) { + if (!sparse_entry_) + headers->ReplaceStatusLine("HTTP/1.1 206 Partial Content"); + + DCHECK(byte_range_.HasFirstBytePosition()); + DCHECK(byte_range_.HasLastBytePosition()); + start = byte_range_.first_byte_position(); + end = byte_range_.last_byte_position(); + range_len = end - start + 1; + } else { + headers->ReplaceStatusLine( + "HTTP/1.1 416 Requested Range Not Satisfiable"); + start = 0; + end = 0; + range_len = 0; + } - DCHECK(byte_range_.HasFirstBytePosition()); - DCHECK(byte_range_.HasLastBytePosition()); headers->AddHeader( base::StringPrintf("%s: bytes %" PRId64 "-%" PRId64 "/%" PRId64, - kRangeHeader, - byte_range_.first_byte_position(), - byte_range_.last_byte_position(), - resource_size_)); - range_len = byte_range_.last_byte_position() - - byte_range_.first_byte_position() + 1; + kRangeHeader, start, end, resource_size_)); } else { // TODO(rvargas): Is it safe to change the protocol version? headers->ReplaceStatusLine("HTTP/1.1 200 OK"); @@ -396,6 +416,7 @@ int PartialData::CacheRead(disk_cache::Entry* entry, IOBuffer* data, int PartialData::CacheWrite(disk_cache::Entry* entry, IOBuffer* data, int data_len, CompletionCallback* callback) { + DVLOG(3) << "To write: " << data_len; if (sparse_entry_) { return entry->WriteSparseData(current_range_start_, data, data_len, callback); @@ -409,6 +430,7 @@ int PartialData::CacheWrite(disk_cache::Entry* entry, IOBuffer* data, } void PartialData::OnCacheReadCompleted(int result) { + DVLOG(3) << "Read: " << result; if (result > 0) { current_range_start_ += result; cached_min_len_ -= result; diff --git a/net/http/partial_data.h b/net/http/partial_data.h index 22e0c8b..45bef31 100644 --- a/net/http/partial_data.h +++ b/net/http/partial_data.h @@ -84,7 +84,9 @@ class PartialData { bool ResponseHeadersOK(const HttpResponseHeaders* headers); // Fixes the response headers to include the right content length and range. - void FixResponseHeaders(HttpResponseHeaders* headers); + // |success| is the result of the whole request so if it's false, we'll change + // the result code to be 416. + void FixResponseHeaders(HttpResponseHeaders* headers, bool success); // Fixes the content length that we want to store in the cache. void FixContentLength(HttpResponseHeaders* headers); |