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

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

Powered by Google App Engine
This is Rietveld 408576698