}
}
+enum ExternallyConditionalizedType {
+ EXTERNALLY_CONDITIONALIZED_CACHE_REQUIRES_VALIDATION,
+ EXTERNALLY_CONDITIONALIZED_CACHE_USABLE,
+ EXTERNALLY_CONDITIONALIZED_MISMATCHED_VALIDATORS,
+ EXTERNALLY_CONDITIONALIZED_MAX
+};
+
} // namespace
namespace net {
read_offset_(0),
effective_load_flags_(0),
write_len_(0),
- weak_factory_(this),
- io_callback_(base::Bind(&Transaction::OnIOComplete,
- weak_factory_.GetWeakPtr())),
transaction_pattern_(PATTERN_UNDEFINED),
total_received_bytes_(0),
- websocket_handshake_stream_base_create_helper_(NULL) {
+ websocket_handshake_stream_base_create_helper_(NULL),
+ weak_factory_(this) {
COMPILE_ASSERT(HttpCache::Transaction::kNumValidationHeaders ==
arraysize(kValidationHeaders),
Invalid_number_of_validation_headers);
+
+ io_callback_ = base::Bind(&Transaction::OnIOComplete,
+ weak_factory_.GetWeakPtr());
}
HttpCache::Transaction::~Transaction() {
if (cache_) {
if (entry_) {
- bool cancel_request = reading_ && response_.headers;
+ bool cancel_request = reading_ && response_.headers.get();
if (cancel_request) {
if (partial_) {
entry_->disk_entry->CancelSparseIO();
if (bypass_lock_for_test_) {
OnAddToEntryTimeout(entry_lock_waiting_since_);
} else {
- const int kTimeoutSeconds = 20;
+ int timeout_milliseconds = 20 * 1000;
+ if (partial_ && new_entry_->writer &&
+ new_entry_->writer->range_requested_) {
+ // Quickly 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.
+ //
+ // Allow some timeout slack for the entry addition to complete in case
+ // the writer lock is imminently released; we want to avoid skipping
+ // the cache if at all possible. See http://crbug.com/408765
+ timeout_milliseconds = 25;
+ }
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&HttpCache::Transaction::OnAddToEntryTimeout,
weak_factory_.GetWeakPtr(), entry_lock_waiting_since_),
- TimeDelta::FromSeconds(kTimeoutSeconds));
+ TimeDelta::FromMilliseconds(timeout_milliseconds));
}
}
return rv;
return OK;
}
- if (handling_206_ && !CanResume(false)) {
- // There is no point in storing this resource because it will never be used.
- DoneWritingToEntry(false);
- if (partial_.get())
- 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;
}
}
+ // TODO(ricea): This calculation is expensive to perform just to collect
+ // statistics. Either remove it or use the result, depending on the result of
+ // the experiment.
+ ExternallyConditionalizedType type =
+ EXTERNALLY_CONDITIONALIZED_CACHE_USABLE;
+ if (mode_ == NONE)
+ type = EXTERNALLY_CONDITIONALIZED_MISMATCHED_VALIDATORS;
+ else if (RequiresValidation())
+ type = EXTERNALLY_CONDITIONALIZED_CACHE_REQUIRES_VALIDATION;
+
+ // TODO(ricea): Add CACHE_USABLE_STALE once stale-while-revalidate CL landed.
+ // TODO(ricea): Either remove this histogram or make it permanent by M40.
+ UMA_HISTOGRAM_ENUMERATION("HttpCache.ExternallyConditionalized",
+ type,
+ EXTERNALLY_CONDITIONALIZED_MAX);
+
next_state_ = STATE_SEND_REQUEST;
return OK;
}
return false;
}
- // We should have handled this case before.
- DCHECK(response_.headers->response_code() != 206 ||
- response_.headers->HasStrongValidators());
+ if (response_.headers->response_code() == 206 &&
+ !response_.headers->HasStrongValidators()) {
+ return false;
+ }
// Just use the first available ETag and/or Last-Modified header value.
// TODO(darin): Or should we use the last?