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 3607bfd42a08531c55d05bc0075aa61e48261d0c..f546a9be8d5a7da724d2a0a1eb5ae60a8449fe9a 100644 |
| --- a/net/url_request/sdch_dictionary_fetcher.cc |
| +++ b/net/url_request/sdch_dictionary_fetcher.cc |
| @@ -15,6 +15,7 @@ |
| #include "net/base/load_flags.h" |
| #include "net/base/net_log.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" |
| @@ -43,64 +44,40 @@ int GetReadResult(int bytes_read, const URLRequest* request) { |
| } // namespace |
| -SdchDictionaryFetcher::SdchDictionaryFetcher( |
| - URLRequestContext* context, |
| - const OnDictionaryFetchedCallback& callback) |
| +SdchDictionaryFetcher::SdchDictionaryFetcher(URLRequestContext* context) |
| : next_state_(STATE_NONE), |
| in_loop_(false), |
| context_(context), |
| - dictionary_fetched_callback_(callback), |
| weak_factory_(this) { |
| DCHECK(CalledOnValidThread()); |
| DCHECK(context); |
| } |
| SdchDictionaryFetcher::~SdchDictionaryFetcher() { |
| - DCHECK(CalledOnValidThread()); |
| } |
| -void SdchDictionaryFetcher::Schedule(const GURL& dictionary_url) { |
| - 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() == 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; |
| - } |
| - |
| - 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_SEND_REQUEST; |
| +void SdchDictionaryFetcher::Schedule( |
| + const GURL& dictionary_url, |
| + const OnDictionaryFetchedCallback& callback) { |
| + ScheduleInternal(dictionary_url, false, callback); |
| +} |
| - // 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, |
| + const OnDictionaryFetchedCallback& callback) { |
| + ScheduleInternal(dictionary_url, true, callback); |
| } |
| void SdchDictionaryFetcher::Cancel() { |
| DCHECK(CalledOnValidThread()); |
| next_state_ = STATE_NONE; |
| + current_request_.reset(); |
| + buffer_ = nullptr; |
| + current_callback_.Reset(); |
| - while (!fetch_queue_.empty()) |
| - fetch_queue_.pop(); |
| attempted_load_.clear(); |
| weak_factory_.InvalidateWeakPtrs(); |
| - current_request_.reset(NULL); |
| - buffer_ = NULL; |
| dictionary_.clear(); |
| } |
| @@ -115,6 +92,23 @@ void SdchDictionaryFetcher::OnResponseStarted(URLRequest* request) { |
| DCHECK_EQ(next_state_, STATE_SEND_REQUEST_COMPLETE); |
| DCHECK(!in_loop_); |
| + // 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(); |
|
mmenke
2015/02/12 20:40:35
I think this is ugly...I have some other suggestio
Elly Fong-Jones
2015/02/13 23:35:00
Done.
|
| + return; |
| + } |
| + } |
| + |
| DoLoop(request->status().error()); |
| } |
| @@ -133,6 +127,76 @@ void SdchDictionaryFetcher::OnReadCompleted(URLRequest* request, |
| DoLoop(GetReadResult(bytes_read, current_request_.get())); |
| } |
| +SdchDictionaryFetcher::QueuedInfo::QueuedInfo() |
| + : download_only_from_cache(false) { |
| +} |
| + |
| +SdchDictionaryFetcher::QueuedInfo::QueuedInfo( |
| + const GURL& url, |
| + bool download_only_from_cache, |
| + const OnDictionaryFetchedCallback& callback) |
| + : url(url), |
| + download_only_from_cache(download_only_from_cache), |
| + callback(callback) { |
| +} |
| + |
| +SdchDictionaryFetcher::QueuedInfo::QueuedInfo(const QueuedInfo& rhs) = default; |
| + |
| +SdchDictionaryFetcher::QueuedInfo& |
| +SdchDictionaryFetcher::QueuedInfo::operator=(const QueuedInfo& rhs) = default; |
| + |
| +SdchDictionaryFetcher::QueuedInfo::~QueuedInfo() { |
| +} |
| + |
| +void SdchDictionaryFetcher::ScheduleInternal( |
| + const GURL& dictionary_url, |
| + bool reload, |
| + const OnDictionaryFetchedCallback& callback) { |
| + DCHECK(CalledOnValidThread()); |
|
mmenke
2015/02/12 20:40:35
Include base/logging.h
Elly Fong-Jones
2015/02/13 23:35:01
Done.
|
| + |
| + // 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, callback)); |
| + |
| + // 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_SEND_REQUEST; |
| + |
| + // 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_callback_.Reset(); |
| + next_state_ = STATE_SEND_REQUEST; |
| + dictionary_.clear(); |
| + |
| + if (!in_loop_) |
|
mmenke
2015/02/12 20:40:35
I think this in_loop_ check is pretty ugly.
Sugge
Elly Fong-Jones
2015/02/13 23:35:00
Done.
|
| + DoLoop(OK); |
| + return; |
| +} |
| + |
| int SdchDictionaryFetcher::DoLoop(int rv) { |
| DCHECK(!in_loop_); |
| base::AutoReset<bool> auto_reset_in_loop(&in_loop_, true); |
| @@ -178,10 +242,14 @@ int SdchDictionaryFetcher::DoSendRequest(int rv) { |
| next_state_ = STATE_SEND_REQUEST_COMPLETE; |
| 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)); |
|
mmenke
2015/02/12 20:40:35
optional: This is one cases where I think using a
Elly Fong-Jones
2015/02/13 23:35:01
Done.
|
| + |
| buffer_ = new IOBuffer(kBufferSize); |
| + current_callback_ = fetch_queue_.front().callback; |
|
mmenke
2015/02/12 20:40:35
optional: Might be simplest just to get rid of cu
Elly Fong-Jones
2015/02/13 23:35:01
Unfortunately we pull it out of the queue right af
|
| fetch_queue_.pop(); |
| current_request_->Start(); |
| @@ -211,10 +279,7 @@ int SdchDictionaryFetcher::DoReadBody(int rv) { |
| // If there's been an error, abort the current request. |
| if (rv != OK) { |
| - current_request_.reset(); |
| - buffer_ = NULL; |
| - next_state_ = STATE_SEND_REQUEST; |
| - |
| + ResetRequest(); |
| return OK; |
| } |
| @@ -255,18 +320,13 @@ int SdchDictionaryFetcher::DoReadBodyComplete(int rv) { |
| int SdchDictionaryFetcher::DoCompleteRequest(int rv) { |
| DCHECK(CalledOnValidThread()); |
| - // DoReadBodyComplete() only transitions to this state |
| - // on success. |
| - DCHECK_EQ(OK, rv); |
| - |
| - dictionary_fetched_callback_.Run(dictionary_, current_request_->url(), |
| - current_request_->net_log()); |
| - current_request_.reset(); |
| - buffer_ = NULL; |
| - dictionary_.clear(); |
| - |
| - next_state_ = STATE_SEND_REQUEST; |
| + // If the dictionary was successfully fetched, add it to the manager. |
| + if (rv == OK) { |
| + current_callback_.Run(dictionary_, current_request_->url(), |
| + current_request_->net_log()); |
| + } |
| + ResetRequest(); |
| return OK; |
| } |