diff options
-rw-r--r-- | net/http/http_cache_transaction.cc | 18 | ||||
-rw-r--r-- | net/http/http_cache_unittest.cc | 32 |
2 files changed, 48 insertions, 2 deletions
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc index f11d695..856a291 100644 --- a/net/http/http_cache_transaction.cc +++ b/net/http/http_cache_transaction.cc @@ -1382,12 +1382,26 @@ int HttpCache::Transaction::DoAddToEntry() { if (bypass_lock_for_test_) { OnAddToEntryTimeout(entry_lock_waiting_since_); } else { - const int kTimeoutSeconds = 20; + int timeout_secs = 20; + if (partial_ && new_entry_->writer && + new_entry_->writer->range_requested_) { + // Immediately timeout and bypass the cache if we're a range request and + // we're blocked by the reader/writer lock. Doing so eliminates a long + // running issue, http://crbug.com/31014, where two of the same media + // resources could not be played back simultaneously due to one locking + // the cache entry until the entire video was downloaded. + // + // Bypassing the cache is not ideal, as we are now ignoring the cache + // entirely for all range requests to a resource beyond the first. This + // is however a much more succinct solution than the alternatives, which + // would require somewhat significant changes to the http caching logic. + timeout_secs = 0; + } base::MessageLoop::current()->PostDelayedTask( FROM_HERE, base::Bind(&HttpCache::Transaction::OnAddToEntryTimeout, weak_factory_.GetWeakPtr(), entry_lock_waiting_since_), - TimeDelta::FromSeconds(kTimeoutSeconds)); + TimeDelta::FromSeconds(timeout_secs)); } } return rv; diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc index 4987c37..8473f5c 100644 --- a/net/http/http_cache_unittest.cc +++ b/net/http/http_cache_unittest.cc @@ -6790,3 +6790,35 @@ TEST(HttpCache, ResourceFreshnessHeaderNotSent) { EXPECT_EQ(2, cache.network_layer()->transaction_count()); } + +// Tests that we allow multiple simultaneous, non-overlapping transactions to +// take place on a sparse entry. +TEST(HttpCache, RangeGET_MultipleRequests) { + MockHttpCache cache; + + // Create a transaction for bytes 0-9. + MockHttpRequest request(kRangeGET_TransactionOK); + MockTransaction transaction(kRangeGET_TransactionOK); + transaction.request_headers = "Range: bytes = 0-9\r\n" EXTRA_HEADER; + transaction.data = "rg: 00-09 "; + AddMockTransaction(&transaction); + + net::TestCompletionCallback callback; + scoped_ptr<net::HttpTransaction> trans; + int rv = cache.http_cache()->CreateTransaction(net::DEFAULT_PRIORITY, &trans); + EXPECT_EQ(net::OK, rv); + ASSERT_TRUE(trans.get()); + + // Start our transaction. + trans->Start(&request, callback.callback(), net::BoundNetLog()); + + // A second transaction on a different part of the file (the default + // kRangeGET_TransactionOK requests 40-49) should not be blocked by + // the already pending transaction. + RunTransactionTest(cache.http_cache(), kRangeGET_TransactionOK); + + // Let the first transaction complete. + callback.WaitForResult(); + + RemoveMockTransaction(&transaction); +} |