Chromium Code Reviews| Index: net/url_request/sdch_dictionary_fetcher.cc |
| diff --git a/net/url_request/sdch_dictionary_fetcher.cc b/net/url_request/sdch_dictionary_fetcher.cc |
| index b30f78ac2bd06e0f4318d1752494171e9cfb5682..10d8a172503b8bbbf5243c7e40f2c3ad8ea8f532 100644 |
| --- a/net/url_request/sdch_dictionary_fetcher.cc |
| +++ b/net/url_request/sdch_dictionary_fetcher.cc |
| @@ -14,6 +14,7 @@ |
| #include "net/base/io_buffer.h" |
| #include "net/base/load_flags.h" |
| #include "net/base/sdch_net_log_params.h" |
| +#include "net/http/http_response_headers.h" |
| #include "net/url_request/url_request_context.h" |
| #include "net/url_request/url_request_status.h" |
| #include "net/url_request/url_request_throttler_manager.h" |
| @@ -40,50 +41,39 @@ SdchDictionaryFetcher::SdchDictionaryFetcher( |
| SdchDictionaryFetcher::~SdchDictionaryFetcher() { |
| DCHECK(CalledOnValidThread()); |
| -} |
| -void SdchDictionaryFetcher::Schedule(const GURL& dictionary_url) { |
| - DCHECK(CalledOnValidThread()); |
| + while (!fetch_queue_.empty()) { |
|
Bernhard Bauer
2015/01/29 17:42:24
Maybe extract this into a method EmptyQueue()?
Randy Smith (Not in Mondays)
2015/01/30 20:11:10
I hit the code duplication with a slightly bigger
Bernhard Bauer
2015/02/02 14:39:46
Acknowledged.
|
| + delete fetch_queue_.front().extra_data; |
| - // Avoid pushing duplicate copy onto queue. We may fetch this url again later |
| - // and get a different dictionary, but there is no reason to have it in the |
| - // queue twice at one time. |
| - if ((!fetch_queue_.empty() && fetch_queue_.back() == dictionary_url) || |
| - attempted_load_.find(dictionary_url) != attempted_load_.end()) { |
| - // TODO(rdsmith): log this error to the net log of the URLRequest |
| - // initiating this fetch, once URLRequest will be passed here. |
| - SdchManager::SdchErrorRecovery( |
| - SDCH_DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD); |
| - return; |
| + fetch_queue_.pop(); |
| } |
| +} |
| - attempted_load_.insert(dictionary_url); |
| - fetch_queue_.push(dictionary_url); |
| - |
| - // If the loop is already processing, it'll pick up the above in the |
| - // normal course of events. |
| - if (next_state_ != STATE_NONE) |
| - return; |
| - |
| - next_state_ = STATE_IDLE; |
| +void SdchDictionaryFetcher::Schedule(const GURL& dictionary_url, |
| + scoped_ptr<Data> extra_data) { |
| + ScheduleInternal(dictionary_url, false, extra_data.Pass()); |
| +} |
| - // There are no callbacks to user code from the dictionary fetcher, |
| - // and Schedule() is only called from user code, so this call to DoLoop() |
| - // does not require an |if (in_loop_) return;| guard. |
| - DoLoop(OK); |
| +void SdchDictionaryFetcher::ScheduleReload(const GURL& dictionary_url, |
| + scoped_ptr<Data> extra_data) { |
| + ScheduleInternal(dictionary_url, true, extra_data.Pass()); |
| } |
| void SdchDictionaryFetcher::Cancel() { |
| DCHECK(CalledOnValidThread()); |
| next_state_ = STATE_NONE; |
| + current_request_.reset(); |
| + buffer_ = nullptr; |
| + current_extra_data_.reset(); |
| + |
| + while (!fetch_queue_.empty()) { |
| + delete fetch_queue_.front().extra_data; |
| - while (!fetch_queue_.empty()) |
| fetch_queue_.pop(); |
| + } |
| attempted_load_.clear(); |
| weak_factory_.InvalidateWeakPtrs(); |
| - current_request_.reset(NULL); |
| - buffer_ = NULL; |
| dictionary_.clear(); |
| } |
| @@ -97,6 +87,23 @@ void SdchDictionaryFetcher::OnResponseStarted(URLRequest* request) { |
| DCHECK_EQ(request, current_request_.get()); |
| DCHECK_EQ(next_state_, STATE_REQUEST_STARTED); |
| + // Confirm that the response isn't a stale read from the cache (as |
| + // may happen in the reload case). If the response was not retrieved over |
| + // HTTP, it is presumed to be fresh. |
| + HttpResponseHeaders* response_headers = request->response_headers(); |
| + if (response_headers) { |
| + ValidationType validation_type = response_headers->RequiresValidation( |
| + request->response_info().request_time, |
| + request->response_info().response_time, base::Time::Now()); |
| + // TODO(rdsmith): Maybe handle VALIDATION_ASYNCHRONOUS by queueing |
| + // a non-reload request for the dictionary. |
| + if (validation_type != VALIDATION_NONE) { |
| + // Stale entry; drop it on the floor. |
| + ResetRequest(); |
| + return; |
| + } |
| + } |
| + |
| // The response has started, so the stream can be read from. |
| next_state_ = STATE_REQUEST_READING; |
| @@ -135,6 +142,65 @@ void SdchDictionaryFetcher::OnReadCompleted(URLRequest* request, |
| DoLoop(request->status().error()); |
| } |
| +SdchDictionaryFetcher::QueuedInfo::QueuedInfo(const GURL& url, |
| + bool download_only_from_cache, |
| + scoped_ptr<Data> extra_data) |
| + : url(url), |
| + download_only_from_cache(download_only_from_cache), |
| + // The QueuedInfo structure takes ownership of the data. A |
| + // scoped_ptr<> cannot be used because structures used in std::queue<> |
| + // need to be copyable. |
| + extra_data(extra_data.release()) { |
| +} |
| + |
| +void SdchDictionaryFetcher::ScheduleInternal(const GURL& dictionary_url, |
| + bool reload, |
| + scoped_ptr<Data> extra_data) { |
| + DCHECK(CalledOnValidThread()); |
| + |
| + // Avoid pushing duplicate copy onto queue. We may fetch this url again later |
| + // and get a different dictionary, but there is no reason to have it in the |
| + // queue twice at one time. |
| + if ((!fetch_queue_.empty() && fetch_queue_.back().url == dictionary_url) || |
| + attempted_load_.find(dictionary_url) != attempted_load_.end()) { |
| + // TODO(rdsmith): Log this error to the net log. In the case of a |
| + // normal fetch, this can be through the URLRequest |
| + // initiating this fetch (once the URLRequest is passed to the fetcher); |
| + // in the case of a reload, it's more complicated. |
| + SdchManager::SdchErrorRecovery( |
| + SDCH_DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD); |
| + return; |
| + } |
| + |
| + if (!reload) |
| + attempted_load_.insert(dictionary_url); |
| + fetch_queue_.push(QueuedInfo(dictionary_url, reload, extra_data.Pass())); |
| + |
| + // If the loop is already processing, it'll pick up the above in the |
| + // normal course of events. |
| + if (next_state_ != STATE_NONE) |
| + return; |
| + |
| + next_state_ = STATE_IDLE; |
| + |
| + // There are no callbacks to user code from the dictionary fetcher, |
| + // and Schedule() is only called from user code, so this call to DoLoop() |
| + // does not require an |if (in_loop_) return;| guard. |
| + DoLoop(OK); |
| +} |
| + |
| +void SdchDictionaryFetcher::ResetRequest() { |
| + current_request_.reset(); |
| + buffer_ = nullptr; |
| + current_extra_data_.reset(); |
| + next_state_ = STATE_IDLE; |
| + dictionary_.clear(); |
| + |
| + if (!in_loop_) |
| + DoLoop(OK); |
| + return; |
| +} |
| + |
| int SdchDictionaryFetcher::DoLoop(int rv) { |
| DCHECK(!in_loop_); |
| base::AutoReset<bool> auto_reset_in_loop(&in_loop_, true); |
| @@ -175,10 +241,14 @@ int SdchDictionaryFetcher::DoDispatchRequest(int rv) { |
| } |
| current_request_ = |
| - context_->CreateRequest(fetch_queue_.front(), IDLE, this, NULL); |
| - current_request_->SetLoadFlags(LOAD_DO_NOT_SEND_COOKIES | |
| - LOAD_DO_NOT_SAVE_COOKIES); |
| + context_->CreateRequest(fetch_queue_.front().url, IDLE, this, NULL); |
| + current_request_->SetLoadFlags( |
| + LOAD_DO_NOT_SEND_COOKIES | LOAD_DO_NOT_SAVE_COOKIES | |
| + (fetch_queue_.front().download_only_from_cache ? LOAD_ONLY_FROM_CACHE |
| + : 0)); |
| + |
| buffer_ = new IOBuffer(kBufferSize); |
| + current_extra_data_.reset(fetch_queue_.front().extra_data); |
| fetch_queue_.pop(); |
| next_state_ = STATE_REQUEST_STARTED; |
| @@ -207,10 +277,7 @@ int SdchDictionaryFetcher::DoRead(int rv) { |
| // If there's been an error, abort the current request. |
| if (rv != OK) { |
| - current_request_.reset(); |
| - buffer_ = NULL; |
| - next_state_ = STATE_IDLE; |
| - |
| + ResetRequest(); |
| return OK; |
| } |
| @@ -249,15 +316,11 @@ int SdchDictionaryFetcher::DoCompleteRequest(int rv) { |
| // If the dictionary was successfully fetched, add it to the manager. |
| if (rv == OK) { |
| dictionary_fetched_callback_.Run(dictionary_, current_request_->url(), |
| + current_extra_data_.Pass(), |
| current_request_->net_log()); |
| } |
| - current_request_.reset(); |
| - buffer_ = NULL; |
| - dictionary_.clear(); |
| - |
| - next_state_ = STATE_IDLE; |
| - |
| + ResetRequest(); |
| return OK; |
| } |