| Index: net/http/http_cache_transaction.cc
|
| ===================================================================
|
| --- net/http/http_cache_transaction.cc (revision 33833)
|
| +++ net/http/http_cache_transaction.cc (working copy)
|
| @@ -101,6 +101,7 @@
|
| request_(NULL),
|
| cache_(cache->AsWeakPtr()),
|
| entry_(NULL),
|
| + new_entry_(NULL),
|
| network_trans_(NULL),
|
| callback_(NULL),
|
| mode_(NONE),
|
| @@ -156,6 +157,9 @@
|
|
|
| // Ensure that we only have one asynchronous call at a time.
|
| DCHECK(!callback_);
|
| + DCHECK(!reading_);
|
| + DCHECK(!network_trans_.get());
|
| + DCHECK(!entry_);
|
|
|
| if (!cache_)
|
| return ERR_UNEXPECTED;
|
| @@ -167,7 +171,7 @@
|
| if (!ShouldPassThrough()) {
|
| cache_key_ = cache_->GenerateCacheKey(request);
|
|
|
| - // requested cache access mode
|
| + // Requested cache access mode.
|
| if (effective_load_flags_ & LOAD_ONLY_FROM_CACHE) {
|
| mode_ = READ;
|
| } else if (effective_load_flags_ & LOAD_BYPASS_CACHE) {
|
| @@ -188,7 +192,7 @@
|
| }
|
| }
|
|
|
| - // if must use cache, then we must fail. this can happen for back/forward
|
| + // If must use cache, then we must fail. This can happen for back/forward
|
| // navigations to a page generated via a form post.
|
| if (!(mode_ & READ) && effective_load_flags_ & LOAD_ONLY_FROM_CACHE)
|
| return ERR_CACHE_MISS;
|
| @@ -201,7 +205,7 @@
|
| rv = AddToEntry();
|
| }
|
|
|
| - // setting this here allows us to check for the existance of a callback_ to
|
| + // Setting this here allows us to check for the existance of a callback_ to
|
| // determine if we are still inside Start.
|
| if (rv == ERR_IO_PENDING)
|
| callback_ = callback;
|
| @@ -213,7 +217,7 @@
|
| CompletionCallback* callback) {
|
| DCHECK(callback);
|
|
|
| - // ensure that we only have one asynchronous call at a time.
|
| + // Ensure that we only have one asynchronous call at a time.
|
| DCHECK(!callback_);
|
|
|
| if (!cache_)
|
| @@ -232,7 +236,7 @@
|
| CompletionCallback* callback) {
|
| DCHECK(callback);
|
|
|
| - // ensure that we only have one asynchronous call at a time.
|
| + // Ensure that we only have one asynchronous call at a time.
|
| DCHECK(!callback_);
|
|
|
| if (!cache_)
|
| @@ -350,60 +354,128 @@
|
| }
|
|
|
| int HttpCache::Transaction::AddToEntry() {
|
| - ActiveEntry* entry = NULL;
|
| + next_state_ = STATE_INIT_ENTRY;
|
| + return DoLoop(OK);
|
| +}
|
|
|
| +int HttpCache::Transaction::DoInitEntry() {
|
| + DCHECK(!new_entry_);
|
| +
|
| if (!cache_)
|
| return ERR_UNEXPECTED;
|
|
|
| if (mode_ == WRITE) {
|
| - cache_->DoomEntry(cache_key_);
|
| - } else {
|
| - entry = cache_->FindActiveEntry(cache_key_);
|
| - if (!entry) {
|
| - LoadLog::BeginEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_OPEN_ENTRY);
|
| - entry = cache_->OpenEntry(cache_key_);
|
| - LoadLog::EndEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_OPEN_ENTRY);
|
| - if (!entry) {
|
| - if (mode_ == READ_WRITE) {
|
| - mode_ = WRITE;
|
| - } else if (mode_ == UPDATE) {
|
| - // There is no cache entry to update; proceed without caching.
|
| - mode_ = NONE;
|
| - return BeginNetworkRequest();
|
| - } else {
|
| - if (cache_->mode() == PLAYBACK)
|
| - DLOG(INFO) << "Playback Cache Miss: " << request_->url;
|
| + next_state_ = STATE_DOOM_ENTRY;
|
| + return OK;
|
| + }
|
|
|
| - // entry does not exist, and not permitted to create a new entry, so
|
| - // we must fail.
|
| - return HandleResult(ERR_CACHE_MISS);
|
| - }
|
| - }
|
| - }
|
| + new_entry_ = cache_->FindActiveEntry(cache_key_);
|
| + if (!new_entry_) {
|
| + next_state_ = STATE_OPEN_ENTRY;
|
| + return OK;
|
| }
|
|
|
| if (mode_ == WRITE) {
|
| - DCHECK(!entry);
|
| - LoadLog::BeginEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_CREATE_ENTRY);
|
| - entry = cache_->CreateEntry(cache_key_);
|
| - LoadLog::EndEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_CREATE_ENTRY);
|
| - if (!entry) {
|
| - DLOG(WARNING) << "unable to create cache entry";
|
| - mode_ = NONE;
|
| - if (partial_.get())
|
| - partial_->RestoreHeaders(&custom_request_->extra_headers);
|
| - return BeginNetworkRequest();
|
| - }
|
| + next_state_ = STATE_CREATE_ENTRY;
|
| + return OK;
|
| }
|
|
|
| + next_state_ = STATE_ADD_TO_ENTRY;
|
| + return OK;
|
| +}
|
|
|
| +int HttpCache::Transaction::DoDoomEntry() {
|
| + next_state_ = STATE_DOOM_ENTRY_COMPLETE;
|
| + cache_->DoomEntry(cache_key_);
|
| + return OK;
|
| +}
|
| +
|
| +int HttpCache::Transaction::DoDoomEntryComplete() {
|
| + next_state_ = STATE_CREATE_ENTRY;
|
| + return OK;
|
| +}
|
| +
|
| +int HttpCache::Transaction::DoOpenEntry() {
|
| + DCHECK(!new_entry_);
|
| + next_state_ = STATE_OPEN_ENTRY_COMPLETE;
|
| + LoadLog::BeginEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_OPEN_ENTRY);
|
| + new_entry_ = cache_->OpenEntry(cache_key_);
|
| + return OK;
|
| +}
|
| +
|
| +int HttpCache::Transaction::DoOpenEntryComplete() {
|
| + LoadLog::EndEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_OPEN_ENTRY);
|
| + if (new_entry_) {
|
| + next_state_ = STATE_ADD_TO_ENTRY;
|
| + return OK;
|
| + }
|
| +
|
| + if (mode_ == READ_WRITE) {
|
| + mode_ = WRITE;
|
| + next_state_ = STATE_CREATE_ENTRY;
|
| + return OK;
|
| + }
|
| + if (mode_ == UPDATE) {
|
| + // There is no cache entry to update; proceed without caching.
|
| + mode_ = NONE;
|
| + next_state_ = STATE_SEND_REQUEST;
|
| + return OK;
|
| + }
|
| + if (cache_->mode() == PLAYBACK)
|
| + DLOG(INFO) << "Playback Cache Miss: " << request_->url;
|
| +
|
| + // The entry does not exist, and we are not permitted to create a new entry,
|
| + // so we must fail.
|
| + return ERR_CACHE_MISS;
|
| +}
|
| +
|
| +int HttpCache::Transaction::DoCreateEntry() {
|
| + DCHECK(!new_entry_);
|
| + next_state_ = STATE_CREATE_ENTRY_COMPLETE;
|
| + LoadLog::BeginEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_CREATE_ENTRY);
|
| + new_entry_ = cache_->CreateEntry(cache_key_);
|
| + return OK;
|
| +}
|
| +
|
| +int HttpCache::Transaction::DoCreateEntryComplete() {
|
| + LoadLog::EndEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_CREATE_ENTRY);
|
| + next_state_ = STATE_ADD_TO_ENTRY;
|
| + if (!new_entry_) {
|
| + // We have a race here: Maybe we failed to open the entry and decided to
|
| + // create one, but by the time we called create, another transaction already
|
| + // created the entry. If we want to eliminate this issue, we need an atomic
|
| + // OpenOrCreate() method exposed by the disk cache.
|
| + DLOG(WARNING) << "Unable to create cache entry";
|
| + mode_ = NONE;
|
| + if (partial_.get())
|
| + partial_->RestoreHeaders(&custom_request_->extra_headers);
|
| + next_state_ = STATE_SEND_REQUEST;
|
| + }
|
| + return OK;
|
| +}
|
| +
|
| +int HttpCache::Transaction::DoAddToEntry() {
|
| + DCHECK(new_entry_);
|
| LoadLog::BeginEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_WAITING);
|
| - return cache_->AddTransactionToEntry(entry, this);
|
| + int rv = cache_->AddTransactionToEntry(new_entry_, this);
|
| + new_entry_ = NULL;
|
| + return rv;
|
| }
|
|
|
| int HttpCache::Transaction::EntryAvailable(ActiveEntry* entry) {
|
| LoadLog::EndEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_WAITING);
|
| + entry_ = entry;
|
|
|
| + next_state_ = STATE_ENTRY_AVAILABLE;
|
| + if (new_entry_) {
|
| + // We are inside AddTransactionToEntry() so avoid reentering DoLoop().
|
| + DCHECK_EQ(new_entry_, entry);
|
| + return OK;
|
| + }
|
| + return DoLoop(OK);
|
| +}
|
| +
|
| +int HttpCache::Transaction::DoEntryAvailable() {
|
| // We now have access to the cache entry.
|
| //
|
| // o if we are the writer for the transaction, then we can start the network
|
| @@ -421,8 +493,8 @@
|
| // the cache entry, and check if the request headers define a validation
|
| // request.
|
| //
|
| + DCHECK(!new_entry_);
|
| int rv;
|
| - entry_ = entry;
|
| switch (mode_) {
|
| case READ:
|
| rv = BeginCacheRead();
|
| @@ -430,7 +502,8 @@
|
| case WRITE:
|
| if (partial_.get())
|
| partial_->RestoreHeaders(&custom_request_->extra_headers);
|
| - rv = BeginNetworkRequest();
|
| + next_state_ = STATE_SEND_REQUEST;
|
| + rv = OK;
|
| break;
|
| case READ_WRITE:
|
| rv = BeginPartialCacheValidation();
|
| @@ -500,6 +573,46 @@
|
| case STATE_NETWORK_READ_COMPLETE:
|
| rv = DoNetworkReadComplete(rv);
|
| break;
|
| + case STATE_INIT_ENTRY:
|
| + DCHECK_EQ(OK, rv);
|
| + rv = DoInitEntry();
|
| + break;
|
| + case STATE_OPEN_ENTRY:
|
| + DCHECK_EQ(OK, rv);
|
| + rv = DoOpenEntry();
|
| + break;
|
| + case STATE_OPEN_ENTRY_COMPLETE:
|
| + DCHECK_EQ(OK, rv);
|
| + rv = DoOpenEntryComplete();
|
| + break;
|
| + case STATE_CREATE_ENTRY:
|
| + DCHECK_EQ(OK, rv);
|
| + rv = DoCreateEntry();
|
| + break;
|
| + case STATE_CREATE_ENTRY_COMPLETE:
|
| + DCHECK_EQ(OK, rv);
|
| + rv = DoCreateEntryComplete();
|
| + break;
|
| + case STATE_DOOM_ENTRY:
|
| + DCHECK_EQ(OK, rv);
|
| + rv = DoDoomEntry();
|
| + break;
|
| + case STATE_DOOM_ENTRY_COMPLETE:
|
| + DCHECK_EQ(OK, rv);
|
| + rv = DoDoomEntryComplete();
|
| + break;
|
| + case STATE_ADD_TO_ENTRY:
|
| + DCHECK_EQ(OK, rv);
|
| + rv = DoAddToEntry();
|
| + break;
|
| + case STATE_ENTRY_AVAILABLE:
|
| + DCHECK_EQ(OK, rv);
|
| + rv = DoEntryAvailable();
|
| + break;
|
| + case STATE_PARTIAL_CACHE_VALIDATION:
|
| + DCHECK_EQ(OK, rv);
|
| + rv = DoPartialCacheValidation();
|
| + break;
|
| case STATE_CACHE_QUERY_DATA:
|
| DCHECK_EQ(OK, rv);
|
| rv = DoCacheQueryData();
|
| @@ -681,19 +794,19 @@
|
| // Read response headers.
|
| int rv = ReadResponseInfoFromEntry();
|
| if (rv != OK)
|
| - return HandleResult(rv);
|
| + return rv;
|
|
|
| // We don't support any combination of LOAD_ONLY_FROM_CACHE and byte ranges.
|
| if (response_.headers->response_code() == 206 || partial_.get()) {
|
| NOTREACHED();
|
| - return HandleResult(ERR_CACHE_MISS);
|
| + return ERR_CACHE_MISS;
|
| }
|
|
|
| // We don't have the whole resource.
|
| if (truncated_)
|
| - return HandleResult(ERR_CACHE_MISS);
|
| + return ERR_CACHE_MISS;
|
|
|
| - return HandleResult(rv);
|
| + return rv;
|
| }
|
|
|
| int HttpCache::Transaction::BeginCacheValidation() {
|
| @@ -710,9 +823,9 @@
|
| // either READ or WRITE mode once we hear back from the server.
|
| if (!ConditionalizeRequest())
|
| mode_ = WRITE;
|
| - return BeginNetworkRequest();
|
| + next_state_ = STATE_SEND_REQUEST;
|
| }
|
| - return HandleResult(OK);
|
| + return OK;
|
| }
|
|
|
| int HttpCache::Transaction::BeginPartialCacheValidation() {
|
| @@ -721,7 +834,7 @@
|
| int rv = ReadResponseInfoFromEntry();
|
| if (rv != OK) {
|
| DCHECK(rv != ERR_IO_PENDING);
|
| - return HandleResult(rv);
|
| + return rv;
|
| }
|
|
|
| if (response_.headers->response_code() != 206 && !partial_.get() &&
|
| @@ -734,7 +847,7 @@
|
| bool byte_range_requested = partial_.get() != NULL;
|
| if (byte_range_requested) {
|
| next_state_ = STATE_CACHE_QUERY_DATA;
|
| - return DoLoop(OK);
|
| + return OK;
|
| }
|
| // The request is not for a range, but we have stored just ranges.
|
| partial_.reset(new PartialData());
|
| @@ -776,7 +889,8 @@
|
| DoomPartialEntry(!byte_range_requested);
|
| mode_ = WRITE;
|
| truncated_ = false;
|
| - return AddToEntry();
|
| + next_state_ = STATE_INIT_ENTRY;
|
| + return OK;
|
| }
|
|
|
| if (!partial_->IsRequestedRangeOK()) {
|
| @@ -784,31 +898,36 @@
|
| invalid_range_ = true;
|
| }
|
|
|
| - return ContinuePartialCacheValidation();
|
| + next_state_ = STATE_PARTIAL_CACHE_VALIDATION;
|
| + return OK;
|
| }
|
|
|
| -int HttpCache::Transaction::ContinuePartialCacheValidation() {
|
| - DCHECK(mode_ == READ_WRITE);
|
| +int HttpCache::Transaction::DoPartialCacheValidation() {
|
| + if (mode_ == NONE)
|
| + return OK;
|
| +
|
| int rv = partial_->PrepareCacheValidation(entry_->disk_entry,
|
| &custom_request_->extra_headers);
|
|
|
| if (!rv) {
|
| - // Don't invoke the callback before telling the cache we're done.
|
| + // This is the end of the request.
|
| + if (mode_ & WRITE) {
|
| + DoneWritingToEntry(true);
|
| + } else {
|
| + cache_->DoneReadingFromEntry(entry_, this);
|
| + entry_ = NULL;
|
| + }
|
| return rv;
|
| }
|
|
|
| if (rv < 0) {
|
| DCHECK(rv != ERR_IO_PENDING);
|
| - return HandleResult(rv);
|
| + return 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;
|
| + next_state_ = STATE_CACHE_READ_DATA;
|
| + return OK;
|
| }
|
|
|
| return BeginCacheValidation();
|
| @@ -822,7 +941,7 @@
|
| int rv = ReadResponseInfoFromEntry();
|
| if (rv != OK) {
|
| DCHECK(rv != ERR_IO_PENDING);
|
| - return HandleResult(rv);
|
| + return rv;
|
| }
|
|
|
| for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kValidationHeaders); i++) {
|
| @@ -843,7 +962,8 @@
|
| }
|
| }
|
|
|
| - return BeginNetworkRequest();
|
| + next_state_ = STATE_SEND_REQUEST;
|
| + return OK;
|
| }
|
|
|
| int HttpCache::Transaction::BeginNetworkRequest() {
|
| @@ -1261,16 +1381,10 @@
|
| int HttpCache::Transaction::DoPartialNetworkReadCompleted(int result) {
|
| partial_->OnNetworkReadCompleted(result);
|
|
|
| - if (result == 0) { // End of file.
|
| - if (mode_ == READ_WRITE) {
|
| - // We need to move on to the next range.
|
| - network_trans_.reset();
|
| - result = ContinuePartialCacheValidation();
|
| - if (result != OK)
|
| - // Any error was already handled.
|
| - return result;
|
| - }
|
| - DoneWritingToEntry(true);
|
| + if (result == 0) {
|
| + // We need to move on to the next range.
|
| + network_trans_.reset();
|
| + next_state_ = STATE_PARTIAL_CACHE_VALIDATION;
|
| }
|
| return result;
|
| }
|
| @@ -1296,18 +1410,9 @@
|
| int HttpCache::Transaction::DoPartialCacheReadCompleted(int result) {
|
| partial_->OnCacheReadCompleted(result);
|
|
|
| - if (result == 0) { // End of file.
|
| - if (partial_.get() && mode_ == READ_WRITE) {
|
| - // We need to move on to the next range.
|
| - result = ContinuePartialCacheValidation();
|
| - if (result != OK || !entry_) {
|
| - // Any error was already handled.
|
| - return result;
|
| - }
|
| - cache_->ConvertWriterToReader(entry_);
|
| - }
|
| - cache_->DoneReadingFromEntry(entry_, this);
|
| - entry_ = NULL;
|
| + if (result == 0 && mode_ == READ_WRITE) {
|
| + // We need to move on to the next range.
|
| + next_state_ = STATE_PARTIAL_CACHE_VALIDATION;
|
| }
|
| return result;
|
| }
|
| @@ -1420,19 +1525,11 @@
|
| }
|
| if (reading_ && partial_.get()) {
|
| if (network_trans_.get()) {
|
| - next_state_ = STATE_NETWORK_READ_COMPLETE;
|
| - result = ReadFromNetwork(read_buf_, read_buf_len_);
|
| + next_state_ = STATE_NETWORK_READ;
|
| } else {
|
| - next_state_ = STATE_CACHE_READ_DATA_COMPLETE;
|
| - result = ReadFromEntry(read_buf_, read_buf_len_);
|
| + next_state_ = STATE_CACHE_READ_DATA;
|
| }
|
| - if (result >= 0 || result == ERR_IO_PENDING) {
|
| - // Keep looping.
|
| - return result;
|
| - } else {
|
| - // Don't keep looping when we return.
|
| - next_state_ = STATE_NONE;
|
| - }
|
| + result = OK;
|
| } else if (mode_ != NONE && partial_.get()) {
|
| // We are about to return the headers for a byte-range request to the
|
| // user, so let's fix them.
|
|
|