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; |
} |