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

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

Issue 901303002: Make SDCH dictionaries persistent across browser restart. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: More fixes 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/net_log.h" 16 #include "net/base/net_log.h"
17 #include "net/base/sdch_net_log_params.h" 17 #include "net/base/sdch_net_log_params.h"
18 #include "net/http/http_response_headers.h"
18 #include "net/url_request/url_request_context.h" 19 #include "net/url_request/url_request_context.h"
19 #include "net/url_request/url_request_status.h" 20 #include "net/url_request/url_request_status.h"
20 #include "net/url_request/url_request_throttler_manager.h" 21 #include "net/url_request/url_request_throttler_manager.h"
21 22
22 namespace net { 23 namespace net {
23 24
24 namespace { 25 namespace {
25 26
26 const int kBufferSize = 4096; 27 const int kBufferSize = 4096;
27 28
28 // Map the bytes_read result from a read attempt and a URLRequest's 29 // Map the bytes_read result from a read attempt and a URLRequest's
29 // status into a single net return value. 30 // status into a single net return value.
30 int GetReadResult(int bytes_read, const URLRequest* request) { 31 int GetReadResult(int bytes_read, const URLRequest* request) {
31 int rv = request->status().error(); 32 int rv = request->status().error();
32 if (request->status().is_success() && bytes_read < 0) { 33 if (request->status().is_success() && bytes_read < 0) {
33 rv = ERR_FAILED; 34 rv = ERR_FAILED;
34 request->net_log().AddEventWithNetErrorCode( 35 request->net_log().AddEventWithNetErrorCode(
35 NetLog::TYPE_SDCH_DICTIONARY_FETCH_IMPLIED_ERROR, rv); 36 NetLog::TYPE_SDCH_DICTIONARY_FETCH_IMPLIED_ERROR, rv);
36 } 37 }
37 38
38 if (rv == OK) 39 if (rv == OK)
39 rv = bytes_read; 40 rv = bytes_read;
40 41
41 return rv; 42 return rv;
42 } 43 }
43 44
44 } // namespace 45 } // namespace
45 46
46 SdchDictionaryFetcher::SdchDictionaryFetcher( 47 SdchDictionaryFetcher::SdchDictionaryFetcher(URLRequestContext* context)
47 URLRequestContext* context,
48 const OnDictionaryFetchedCallback& callback)
49 : next_state_(STATE_NONE), 48 : next_state_(STATE_NONE),
50 in_loop_(false), 49 in_loop_(false),
51 context_(context), 50 context_(context),
52 dictionary_fetched_callback_(callback),
53 weak_factory_(this) { 51 weak_factory_(this) {
54 DCHECK(CalledOnValidThread()); 52 DCHECK(CalledOnValidThread());
55 DCHECK(context); 53 DCHECK(context);
56 } 54 }
57 55
58 SdchDictionaryFetcher::~SdchDictionaryFetcher() { 56 SdchDictionaryFetcher::~SdchDictionaryFetcher() {
59 DCHECK(CalledOnValidThread());
60 } 57 }
61 58
62 void SdchDictionaryFetcher::Schedule(const GURL& dictionary_url) { 59 void SdchDictionaryFetcher::Schedule(
63 DCHECK(CalledOnValidThread()); 60 const GURL& dictionary_url,
61 const OnDictionaryFetchedCallback& callback) {
62 ScheduleInternal(dictionary_url, false, callback);
63 }
64 64
65 // Avoid pushing duplicate copy onto queue. We may fetch this url again later 65 void SdchDictionaryFetcher::ScheduleReload(
66 // and get a different dictionary, but there is no reason to have it in the 66 const GURL& dictionary_url,
67 // queue twice at one time. 67 const OnDictionaryFetchedCallback& callback) {
68 if ((!fetch_queue_.empty() && fetch_queue_.back() == dictionary_url) || 68 ScheduleInternal(dictionary_url, true, callback);
69 attempted_load_.find(dictionary_url) != attempted_load_.end()) {
70 // TODO(rdsmith): log this error to the net log of the URLRequest
71 // initiating this fetch, once URLRequest will be passed here.
72 SdchManager::SdchErrorRecovery(
73 SDCH_DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD);
74 return;
75 }
76
77 attempted_load_.insert(dictionary_url);
78 fetch_queue_.push(dictionary_url);
79
80 // If the loop is already processing, it'll pick up the above in the
81 // normal course of events.
82 if (next_state_ != STATE_NONE)
83 return;
84
85 next_state_ = STATE_SEND_REQUEST;
86
87 // There are no callbacks to user code from the dictionary fetcher,
88 // and Schedule() is only called from user code, so this call to DoLoop()
89 // does not require an |if (in_loop_) return;| guard.
90 DoLoop(OK);
91 } 69 }
92 70
93 void SdchDictionaryFetcher::Cancel() { 71 void SdchDictionaryFetcher::Cancel() {
94 DCHECK(CalledOnValidThread()); 72 DCHECK(CalledOnValidThread());
95 73
96 next_state_ = STATE_NONE; 74 next_state_ = STATE_NONE;
75 current_request_.reset();
76 buffer_ = nullptr;
77 current_callback_.Reset();
97 78
98 while (!fetch_queue_.empty())
99 fetch_queue_.pop();
100 attempted_load_.clear(); 79 attempted_load_.clear();
101 weak_factory_.InvalidateWeakPtrs(); 80 weak_factory_.InvalidateWeakPtrs();
102 current_request_.reset(NULL);
103 buffer_ = NULL;
104 dictionary_.clear(); 81 dictionary_.clear();
105 } 82 }
106 83
107 void SdchDictionaryFetcher::OnResponseStarted(URLRequest* request) { 84 void SdchDictionaryFetcher::OnResponseStarted(URLRequest* request) {
108 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. 85 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
109 tracked_objects::ScopedTracker tracking_profile( 86 tracked_objects::ScopedTracker tracking_profile(
110 FROM_HERE_WITH_EXPLICIT_FUNCTION( 87 FROM_HERE_WITH_EXPLICIT_FUNCTION(
111 "423948 SdchDictionaryFetcher::OnResponseStarted")); 88 "423948 SdchDictionaryFetcher::OnResponseStarted"));
112 89
113 DCHECK(CalledOnValidThread()); 90 DCHECK(CalledOnValidThread());
114 DCHECK_EQ(request, current_request_.get()); 91 DCHECK_EQ(request, current_request_.get());
115 DCHECK_EQ(next_state_, STATE_SEND_REQUEST_COMPLETE); 92 DCHECK_EQ(next_state_, STATE_SEND_REQUEST_COMPLETE);
116 DCHECK(!in_loop_); 93 DCHECK(!in_loop_);
117 94
95 // Confirm that the response isn't a stale read from the cache (as
96 // may happen in the reload case). If the response was not retrieved over
97 // HTTP, it is presumed to be fresh.
98 HttpResponseHeaders* response_headers = request->response_headers();
99 if (response_headers) {
100 ValidationType validation_type = response_headers->RequiresValidation(
101 request->response_info().request_time,
102 request->response_info().response_time, base::Time::Now());
103 // TODO(rdsmith): Maybe handle VALIDATION_ASYNCHRONOUS by queueing
104 // a non-reload request for the dictionary.
105 if (validation_type != VALIDATION_NONE) {
106 // Stale entry; drop it on the floor.
107 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.
108 return;
109 }
110 }
111
118 DoLoop(request->status().error()); 112 DoLoop(request->status().error());
119 } 113 }
120 114
121 void SdchDictionaryFetcher::OnReadCompleted(URLRequest* request, 115 void SdchDictionaryFetcher::OnReadCompleted(URLRequest* request,
122 int bytes_read) { 116 int bytes_read) {
123 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. 117 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
124 tracked_objects::ScopedTracker tracking_profile( 118 tracked_objects::ScopedTracker tracking_profile(
125 FROM_HERE_WITH_EXPLICIT_FUNCTION( 119 FROM_HERE_WITH_EXPLICIT_FUNCTION(
126 "423948 SdchDictionaryFetcher::OnReadCompleted")); 120 "423948 SdchDictionaryFetcher::OnReadCompleted"));
127 121
128 DCHECK(CalledOnValidThread()); 122 DCHECK(CalledOnValidThread());
129 DCHECK_EQ(request, current_request_.get()); 123 DCHECK_EQ(request, current_request_.get());
130 DCHECK_EQ(next_state_, STATE_READ_BODY_COMPLETE); 124 DCHECK_EQ(next_state_, STATE_READ_BODY_COMPLETE);
131 DCHECK(!in_loop_); 125 DCHECK(!in_loop_);
132 126
133 DoLoop(GetReadResult(bytes_read, current_request_.get())); 127 DoLoop(GetReadResult(bytes_read, current_request_.get()));
134 } 128 }
135 129
130 SdchDictionaryFetcher::QueuedInfo::QueuedInfo()
131 : download_only_from_cache(false) {
132 }
133
134 SdchDictionaryFetcher::QueuedInfo::QueuedInfo(
135 const GURL& url,
136 bool download_only_from_cache,
137 const OnDictionaryFetchedCallback& callback)
138 : url(url),
139 download_only_from_cache(download_only_from_cache),
140 callback(callback) {
141 }
142
143 SdchDictionaryFetcher::QueuedInfo::QueuedInfo(const QueuedInfo& rhs) = default;
144
145 SdchDictionaryFetcher::QueuedInfo&
146 SdchDictionaryFetcher::QueuedInfo::operator=(const QueuedInfo& rhs) = default;
147
148 SdchDictionaryFetcher::QueuedInfo::~QueuedInfo() {
149 }
150
151 void SdchDictionaryFetcher::ScheduleInternal(
152 const GURL& dictionary_url,
153 bool reload,
154 const OnDictionaryFetchedCallback& callback) {
155 DCHECK(CalledOnValidThread());
mmenke 2015/02/12 20:40:35 Include base/logging.h
Elly Fong-Jones 2015/02/13 23:35:01 Done.
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, callback));
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_SEND_REQUEST;
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_callback_.Reset();
192 next_state_ = STATE_SEND_REQUEST;
193 dictionary_.clear();
194
195 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.
196 DoLoop(OK);
197 return;
198 }
199
136 int SdchDictionaryFetcher::DoLoop(int rv) { 200 int SdchDictionaryFetcher::DoLoop(int rv) {
137 DCHECK(!in_loop_); 201 DCHECK(!in_loop_);
138 base::AutoReset<bool> auto_reset_in_loop(&in_loop_, true); 202 base::AutoReset<bool> auto_reset_in_loop(&in_loop_, true);
139 203
140 do { 204 do {
141 State state = next_state_; 205 State state = next_state_;
142 next_state_ = STATE_NONE; 206 next_state_ = STATE_NONE;
143 switch (state) { 207 switch (state) {
144 case STATE_SEND_REQUEST: 208 case STATE_SEND_REQUEST:
145 rv = DoSendRequest(rv); 209 rv = DoSendRequest(rv);
(...skipping 25 matching lines...) Expand all
171 // affect the next request. 235 // affect the next request.
172 236
173 if (fetch_queue_.empty() || current_request_.get()) { 237 if (fetch_queue_.empty() || current_request_.get()) {
174 next_state_ = STATE_NONE; 238 next_state_ = STATE_NONE;
175 return OK; 239 return OK;
176 } 240 }
177 241
178 next_state_ = STATE_SEND_REQUEST_COMPLETE; 242 next_state_ = STATE_SEND_REQUEST_COMPLETE;
179 243
180 current_request_ = 244 current_request_ =
181 context_->CreateRequest(fetch_queue_.front(), IDLE, this, NULL); 245 context_->CreateRequest(fetch_queue_.front().url, IDLE, this, NULL);
182 current_request_->SetLoadFlags(LOAD_DO_NOT_SEND_COOKIES | 246 current_request_->SetLoadFlags(
183 LOAD_DO_NOT_SAVE_COOKIES); 247 LOAD_DO_NOT_SEND_COOKIES | LOAD_DO_NOT_SAVE_COOKIES |
248 (fetch_queue_.front().download_only_from_cache ? LOAD_ONLY_FROM_CACHE
249 : 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.
250
184 buffer_ = new IOBuffer(kBufferSize); 251 buffer_ = new IOBuffer(kBufferSize);
252 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
185 fetch_queue_.pop(); 253 fetch_queue_.pop();
186 254
187 current_request_->Start(); 255 current_request_->Start();
188 current_request_->net_log().AddEvent(NetLog::TYPE_SDCH_DICTIONARY_FETCH); 256 current_request_->net_log().AddEvent(NetLog::TYPE_SDCH_DICTIONARY_FETCH);
189 257
190 return ERR_IO_PENDING; 258 return ERR_IO_PENDING;
191 } 259 }
192 260
193 int SdchDictionaryFetcher::DoSendRequestComplete(int rv) { 261 int SdchDictionaryFetcher::DoSendRequestComplete(int rv) {
194 DCHECK(CalledOnValidThread()); 262 DCHECK(CalledOnValidThread());
195 263
196 // If there's been an error, abort the current request. 264 // If there's been an error, abort the current request.
197 if (rv != OK) { 265 if (rv != OK) {
198 current_request_.reset(); 266 current_request_.reset();
199 buffer_ = NULL; 267 buffer_ = NULL;
200 next_state_ = STATE_SEND_REQUEST; 268 next_state_ = STATE_SEND_REQUEST;
201 269
202 return OK; 270 return OK;
203 } 271 }
204 272
205 next_state_ = STATE_READ_BODY; 273 next_state_ = STATE_READ_BODY;
206 return OK; 274 return OK;
207 } 275 }
208 276
209 int SdchDictionaryFetcher::DoReadBody(int rv) { 277 int SdchDictionaryFetcher::DoReadBody(int rv) {
210 DCHECK(CalledOnValidThread()); 278 DCHECK(CalledOnValidThread());
211 279
212 // If there's been an error, abort the current request. 280 // If there's been an error, abort the current request.
213 if (rv != OK) { 281 if (rv != OK) {
214 current_request_.reset(); 282 ResetRequest();
215 buffer_ = NULL;
216 next_state_ = STATE_SEND_REQUEST;
217
218 return OK; 283 return OK;
219 } 284 }
220 285
221 next_state_ = STATE_READ_BODY_COMPLETE; 286 next_state_ = STATE_READ_BODY_COMPLETE;
222 int bytes_read = 0; 287 int bytes_read = 0;
223 current_request_->Read(buffer_.get(), kBufferSize, &bytes_read); 288 current_request_->Read(buffer_.get(), kBufferSize, &bytes_read);
224 if (current_request_->status().is_io_pending()) 289 if (current_request_->status().is_io_pending())
225 return ERR_IO_PENDING; 290 return ERR_IO_PENDING;
226 291
227 return GetReadResult(bytes_read, current_request_.get()); 292 return GetReadResult(bytes_read, current_request_.get());
(...skipping 20 matching lines...) Expand all
248 } 313 }
249 314
250 // End of file; complete the request. 315 // End of file; complete the request.
251 next_state_ = STATE_REQUEST_COMPLETE; 316 next_state_ = STATE_REQUEST_COMPLETE;
252 return OK; 317 return OK;
253 } 318 }
254 319
255 int SdchDictionaryFetcher::DoCompleteRequest(int rv) { 320 int SdchDictionaryFetcher::DoCompleteRequest(int rv) {
256 DCHECK(CalledOnValidThread()); 321 DCHECK(CalledOnValidThread());
257 322
258 // DoReadBodyComplete() only transitions to this state 323 // If the dictionary was successfully fetched, add it to the manager.
259 // on success. 324 if (rv == OK) {
260 DCHECK_EQ(OK, rv); 325 current_callback_.Run(dictionary_, current_request_->url(),
326 current_request_->net_log());
327 }
261 328
262 dictionary_fetched_callback_.Run(dictionary_, current_request_->url(), 329 ResetRequest();
263 current_request_->net_log());
264 current_request_.reset();
265 buffer_ = NULL;
266 dictionary_.clear();
267
268 next_state_ = STATE_SEND_REQUEST;
269
270 return OK; 330 return OK;
271 } 331 }
272 332
273 } // namespace net 333 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698