Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Side by Side Diff: net/url_request/sdch_dictionary_fetcher.cc

Issue 881413003: Make SDCH dictionaries persistent across browser restart. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Incorporated Matt's comments. Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/url_request/sdch_dictionary_fetcher.h" 5 #include "net/url_request/sdch_dictionary_fetcher.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include "base/auto_reset.h" 9 #include "base/auto_reset.h"
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/compiler_specific.h" 11 #include "base/compiler_specific.h"
12 #include "base/profiler/scoped_tracker.h" 12 #include "base/profiler/scoped_tracker.h"
13 #include "base/thread_task_runner_handle.h" 13 #include "base/thread_task_runner_handle.h"
14 #include "net/base/io_buffer.h" 14 #include "net/base/io_buffer.h"
15 #include "net/base/load_flags.h" 15 #include "net/base/load_flags.h"
16 #include "net/base/sdch_net_log_params.h" 16 #include "net/base/sdch_net_log_params.h"
17 #include "net/http/http_response_headers.h"
17 #include "net/url_request/url_request_context.h" 18 #include "net/url_request/url_request_context.h"
18 #include "net/url_request/url_request_status.h" 19 #include "net/url_request/url_request_status.h"
19 #include "net/url_request/url_request_throttler_manager.h" 20 #include "net/url_request/url_request_throttler_manager.h"
20 21
21 namespace { 22 namespace {
22 23
23 const int kBufferSize = 4096; 24 const int kBufferSize = 4096;
24 25
25 } // namespace 26 } // namespace
26 27
27 namespace net { 28 namespace net {
28 29
29 SdchDictionaryFetcher::SdchDictionaryFetcher( 30 SdchDictionaryFetcher::SdchDictionaryFetcher(
30 URLRequestContext* context, 31 URLRequestContext* context,
31 const OnDictionaryFetchedCallback& callback) 32 const OnDictionaryFetchedCallback& callback)
32 : next_state_(STATE_NONE), 33 : next_state_(STATE_NONE),
33 in_loop_(false), 34 in_loop_(false),
34 context_(context), 35 context_(context),
35 dictionary_fetched_callback_(callback), 36 dictionary_fetched_callback_(callback),
36 weak_factory_(this) { 37 weak_factory_(this) {
37 DCHECK(CalledOnValidThread()); 38 DCHECK(CalledOnValidThread());
38 DCHECK(context); 39 DCHECK(context);
39 } 40 }
40 41
41 SdchDictionaryFetcher::~SdchDictionaryFetcher() { 42 SdchDictionaryFetcher::~SdchDictionaryFetcher() {
42 DCHECK(CalledOnValidThread()); 43 DCHECK(CalledOnValidThread());
44 // To tear down the QueuedInfo::extra_data attached to the fetch_queue_.
45 Cancel();
43 } 46 }
44 47
45 void SdchDictionaryFetcher::Schedule(const GURL& dictionary_url) { 48 void SdchDictionaryFetcher::Schedule(const GURL& dictionary_url,
46 DCHECK(CalledOnValidThread()); 49 scoped_ptr<Data> extra_data) {
50 ScheduleInternal(dictionary_url, false, extra_data.Pass());
51 }
47 52
48 // Avoid pushing duplicate copy onto queue. We may fetch this url again later 53 void SdchDictionaryFetcher::ScheduleReload(const GURL& dictionary_url,
49 // and get a different dictionary, but there is no reason to have it in the 54 scoped_ptr<Data> extra_data) {
50 // queue twice at one time. 55 ScheduleInternal(dictionary_url, true, extra_data.Pass());
51 if ((!fetch_queue_.empty() && fetch_queue_.back() == dictionary_url) ||
52 attempted_load_.find(dictionary_url) != attempted_load_.end()) {
53 // TODO(rdsmith): log this error to the net log of the URLRequest
54 // initiating this fetch, once URLRequest will be passed here.
55 SdchManager::SdchErrorRecovery(
56 SDCH_DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD);
57 return;
58 }
59
60 attempted_load_.insert(dictionary_url);
61 fetch_queue_.push(dictionary_url);
62
63 // If the loop is already processing, it'll pick up the above in the
64 // normal course of events.
65 if (next_state_ != STATE_NONE)
66 return;
67
68 next_state_ = STATE_IDLE;
69
70 // There are no callbacks to user code from the dictionary fetcher,
71 // and Schedule() is only called from user code, so this call to DoLoop()
72 // does not require an |if (in_loop_) return;| guard.
73 DoLoop(OK);
74 } 56 }
75 57
76 void SdchDictionaryFetcher::Cancel() { 58 void SdchDictionaryFetcher::Cancel() {
77 DCHECK(CalledOnValidThread()); 59 DCHECK(CalledOnValidThread());
78 60
79 next_state_ = STATE_NONE; 61 next_state_ = STATE_NONE;
62 current_request_.reset();
63 buffer_ = nullptr;
64 current_extra_data_.reset();
80 65
81 while (!fetch_queue_.empty()) 66 while (!fetch_queue_.empty()) {
67 delete fetch_queue_.front().extra_data;
68
82 fetch_queue_.pop(); 69 fetch_queue_.pop();
70 }
83 attempted_load_.clear(); 71 attempted_load_.clear();
84 weak_factory_.InvalidateWeakPtrs(); 72 weak_factory_.InvalidateWeakPtrs();
85 current_request_.reset(NULL);
86 buffer_ = NULL;
87 dictionary_.clear(); 73 dictionary_.clear();
88 } 74 }
89 75
90 void SdchDictionaryFetcher::OnResponseStarted(URLRequest* request) { 76 void SdchDictionaryFetcher::OnResponseStarted(URLRequest* request) {
91 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. 77 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
92 tracked_objects::ScopedTracker tracking_profile( 78 tracked_objects::ScopedTracker tracking_profile(
93 FROM_HERE_WITH_EXPLICIT_FUNCTION( 79 FROM_HERE_WITH_EXPLICIT_FUNCTION(
94 "423948 SdchDictionaryFetcher::OnResponseStarted")); 80 "423948 SdchDictionaryFetcher::OnResponseStarted"));
95 81
96 DCHECK(CalledOnValidThread()); 82 DCHECK(CalledOnValidThread());
97 DCHECK_EQ(request, current_request_.get()); 83 DCHECK_EQ(request, current_request_.get());
98 DCHECK_EQ(next_state_, STATE_REQUEST_STARTED); 84 DCHECK_EQ(next_state_, STATE_REQUEST_STARTED);
99 85
86 // Confirm that the response isn't a stale read from the cache (as
87 // may happen in the reload case). If the response was not retrieved over
88 // HTTP, it is presumed to be fresh.
89 HttpResponseHeaders* response_headers = request->response_headers();
90 if (response_headers) {
91 ValidationType validation_type = response_headers->RequiresValidation(
92 request->response_info().request_time,
93 request->response_info().response_time, base::Time::Now());
94 // TODO(rdsmith): Maybe handle VALIDATION_ASYNCHRONOUS by queueing
95 // a non-reload request for the dictionary.
96 if (validation_type != VALIDATION_NONE) {
97 // Stale entry; drop it on the floor.
98 ResetRequest();
99 return;
100 }
101 }
102
100 // The response has started, so the stream can be read from. 103 // The response has started, so the stream can be read from.
101 next_state_ = STATE_REQUEST_READING; 104 next_state_ = STATE_REQUEST_READING;
102 105
103 // If this function was synchronously called, the containing 106 // If this function was synchronously called, the containing
104 // state machine loop will handle the state transition. Otherwise, 107 // state machine loop will handle the state transition. Otherwise,
105 // restart the state machine loop. 108 // restart the state machine loop.
106 if (in_loop_) 109 if (in_loop_)
107 return; 110 return;
108 111
109 DoLoop(request->status().error()); 112 DoLoop(request->status().error());
(...skipping 18 matching lines...) Expand all
128 131
129 // If this function was synchronously called, the containing 132 // If this function was synchronously called, the containing
130 // state machine loop will handle the state transition. Otherwise, 133 // state machine loop will handle the state transition. Otherwise,
131 // restart the state machine loop. 134 // restart the state machine loop.
132 if (in_loop_) 135 if (in_loop_)
133 return; 136 return;
134 137
135 DoLoop(request->status().error()); 138 DoLoop(request->status().error());
136 } 139 }
137 140
141 SdchDictionaryFetcher::QueuedInfo::QueuedInfo(const GURL& url,
142 bool download_only_from_cache,
143 scoped_ptr<Data> extra_data)
144 : url(url),
145 download_only_from_cache(download_only_from_cache),
146 // The QueuedInfo structure takes ownership of the data. A
147 // scoped_ptr<> cannot be used because structures used in std::queue<>
148 // need to be copyable.
149 extra_data(extra_data.release()) {
150 }
151
152 void SdchDictionaryFetcher::ScheduleInternal(const GURL& dictionary_url,
153 bool reload,
154 scoped_ptr<Data> extra_data) {
155 DCHECK(CalledOnValidThread());
156
157 // Avoid pushing duplicate copy onto queue. We may fetch this url again later
158 // and get a different dictionary, but there is no reason to have it in the
159 // queue twice at one time.
160 if ((!fetch_queue_.empty() && fetch_queue_.back().url == dictionary_url) ||
161 attempted_load_.find(dictionary_url) != attempted_load_.end()) {
162 // TODO(rdsmith): Log this error to the net log. In the case of a
163 // normal fetch, this can be through the URLRequest
164 // initiating this fetch (once the URLRequest is passed to the fetcher);
165 // in the case of a reload, it's more complicated.
166 SdchManager::SdchErrorRecovery(
167 SDCH_DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD);
168 return;
169 }
170
171 if (!reload)
172 attempted_load_.insert(dictionary_url);
173 fetch_queue_.push(QueuedInfo(dictionary_url, reload, extra_data.Pass()));
174
175 // If the loop is already processing, it'll pick up the above in the
176 // normal course of events.
177 if (next_state_ != STATE_NONE)
178 return;
179
180 next_state_ = STATE_IDLE;
181
182 // There are no callbacks to user code from the dictionary fetcher,
183 // and Schedule() is only called from user code, so this call to DoLoop()
184 // does not require an |if (in_loop_) return;| guard.
185 DoLoop(OK);
186 }
187
188 void SdchDictionaryFetcher::ResetRequest() {
189 current_request_.reset();
190 buffer_ = nullptr;
191 current_extra_data_.reset();
192 next_state_ = STATE_IDLE;
193 dictionary_.clear();
194
195 if (!in_loop_)
196 DoLoop(OK);
197 return;
198 }
199
138 int SdchDictionaryFetcher::DoLoop(int rv) { 200 int SdchDictionaryFetcher::DoLoop(int rv) {
139 DCHECK(!in_loop_); 201 DCHECK(!in_loop_);
140 base::AutoReset<bool> auto_reset_in_loop(&in_loop_, true); 202 base::AutoReset<bool> auto_reset_in_loop(&in_loop_, true);
141 203
142 do { 204 do {
143 State state = next_state_; 205 State state = next_state_;
144 next_state_ = STATE_NONE; 206 next_state_ = STATE_NONE;
145 switch (state) { 207 switch (state) {
146 case STATE_IDLE: 208 case STATE_IDLE:
147 rv = DoDispatchRequest(rv); 209 rv = DoDispatchRequest(rv);
(...skipping 20 matching lines...) Expand all
168 230
169 // |rv| is ignored, as the result from the previous request doesn't 231 // |rv| is ignored, as the result from the previous request doesn't
170 // affect the next request. 232 // affect the next request.
171 233
172 if (fetch_queue_.empty() || current_request_.get()) { 234 if (fetch_queue_.empty() || current_request_.get()) {
173 next_state_ = STATE_NONE; 235 next_state_ = STATE_NONE;
174 return OK; 236 return OK;
175 } 237 }
176 238
177 current_request_ = 239 current_request_ =
178 context_->CreateRequest(fetch_queue_.front(), IDLE, this, NULL); 240 context_->CreateRequest(fetch_queue_.front().url, IDLE, this, NULL);
179 current_request_->SetLoadFlags(LOAD_DO_NOT_SEND_COOKIES | 241 current_request_->SetLoadFlags(
180 LOAD_DO_NOT_SAVE_COOKIES); 242 LOAD_DO_NOT_SEND_COOKIES | LOAD_DO_NOT_SAVE_COOKIES |
243 (fetch_queue_.front().download_only_from_cache ? LOAD_ONLY_FROM_CACHE
244 : 0));
245
181 buffer_ = new IOBuffer(kBufferSize); 246 buffer_ = new IOBuffer(kBufferSize);
247 current_extra_data_.reset(fetch_queue_.front().extra_data);
182 fetch_queue_.pop(); 248 fetch_queue_.pop();
183 249
184 next_state_ = STATE_REQUEST_STARTED; 250 next_state_ = STATE_REQUEST_STARTED;
185 current_request_->Start(); 251 current_request_->Start();
186 current_request_->net_log().AddEvent(NetLog::TYPE_SDCH_DICTIONARY_FETCH); 252 current_request_->net_log().AddEvent(NetLog::TYPE_SDCH_DICTIONARY_FETCH);
187 253
188 return OK; 254 return OK;
189 } 255 }
190 256
191 int SdchDictionaryFetcher::DoRequestStarted(int rv) { 257 int SdchDictionaryFetcher::DoRequestStarted(int rv) {
192 DCHECK(CalledOnValidThread()); 258 DCHECK(CalledOnValidThread());
193 DCHECK_EQ(rv, OK); // Can only come straight from above function. 259 DCHECK_EQ(rv, OK); // Can only come straight from above function.
194 260
195 // The transition to STATE_REQUEST_READING occurs in the 261 // The transition to STATE_REQUEST_READING occurs in the
196 // OnResponseStarted() callback triggered by URLRequest::Start() 262 // OnResponseStarted() callback triggered by URLRequest::Start()
197 // (called in DoDispatchRequest(), above). If that callback did not 263 // (called in DoDispatchRequest(), above). If that callback did not
198 // occur synchronously, this routine is executed; it returns ERR_IO_PENDING, 264 // occur synchronously, this routine is executed; it returns ERR_IO_PENDING,
199 // indicating to the controlling loop that no further work should be done 265 // indicating to the controlling loop that no further work should be done
200 // until the callback occurs (which will re-invoke DoLoop()). 266 // until the callback occurs (which will re-invoke DoLoop()).
201 next_state_ = STATE_REQUEST_STARTED; 267 next_state_ = STATE_REQUEST_STARTED;
202 return ERR_IO_PENDING; 268 return ERR_IO_PENDING;
203 } 269 }
204 270
205 int SdchDictionaryFetcher::DoRead(int rv) { 271 int SdchDictionaryFetcher::DoRead(int rv) {
206 DCHECK(CalledOnValidThread()); 272 DCHECK(CalledOnValidThread());
207 273
208 // If there's been an error, abort the current request. 274 // If there's been an error, abort the current request.
209 if (rv != OK) { 275 if (rv != OK) {
210 current_request_.reset(); 276 ResetRequest();
211 buffer_ = NULL;
212 next_state_ = STATE_IDLE;
213
214 return OK; 277 return OK;
215 } 278 }
216 279
217 next_state_ = STATE_REQUEST_READING; 280 next_state_ = STATE_REQUEST_READING;
218 int bytes_read = 0; 281 int bytes_read = 0;
219 current_request_->Read(buffer_.get(), kBufferSize, &bytes_read); 282 current_request_->Read(buffer_.get(), kBufferSize, &bytes_read);
220 if (current_request_->status().is_io_pending()) 283 if (current_request_->status().is_io_pending())
221 return ERR_IO_PENDING; 284 return ERR_IO_PENDING;
222 285
223 if (bytes_read < 0 || !current_request_->status().is_success()) { 286 if (bytes_read < 0 || !current_request_->status().is_success()) {
(...skipping 18 matching lines...) Expand all
242 305
243 return OK; 306 return OK;
244 } 307 }
245 308
246 int SdchDictionaryFetcher::DoCompleteRequest(int rv) { 309 int SdchDictionaryFetcher::DoCompleteRequest(int rv) {
247 DCHECK(CalledOnValidThread()); 310 DCHECK(CalledOnValidThread());
248 311
249 // If the dictionary was successfully fetched, add it to the manager. 312 // If the dictionary was successfully fetched, add it to the manager.
250 if (rv == OK) { 313 if (rv == OK) {
251 dictionary_fetched_callback_.Run(dictionary_, current_request_->url(), 314 dictionary_fetched_callback_.Run(dictionary_, current_request_->url(),
315 current_extra_data_.Pass(),
252 current_request_->net_log()); 316 current_request_->net_log());
253 } 317 }
254 318
255 current_request_.reset(); 319 ResetRequest();
256 buffer_ = NULL;
257 dictionary_.clear();
258
259 next_state_ = STATE_IDLE;
260
261 return OK; 320 return OK;
262 } 321 }
263 322
264 } // namespace net 323 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698