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

Side by Side Diff: webkit/appcache/appcache_update_job.cc

Issue 326002: Add storage code to appcache update process. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « webkit/appcache/appcache_update_job.h ('k') | webkit/appcache/appcache_update_job_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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 "webkit/appcache/appcache_update_job.h" 5 #include "webkit/appcache/appcache_update_job.h"
6 6
7 #include "base/compiler_specific.h" 7 #include "base/compiler_specific.h"
8 #include "base/message_loop.h" 8 #include "base/message_loop.h"
9 #include "base/string_util.h" 9 #include "base/string_util.h"
10 #include "net/base/io_buffer.h" 10 #include "net/base/io_buffer.h"
11 #include "net/base/load_flags.h" 11 #include "net/base/load_flags.h"
12 #include "webkit/appcache/appcache_group.h" 12 #include "webkit/appcache/appcache_group.h"
13 #include "webkit/appcache/appcache_host.h" 13 #include "webkit/appcache/appcache_host.h"
14 14
15 namespace appcache { 15 namespace appcache {
16 16
17 static const int kBufferSize = 4096; 17 static const int kBufferSize = 4096;
18 static const size_t kMaxConcurrentUrlFetches = 2; 18 static const size_t kMaxConcurrentUrlFetches = 2;
19 static const int kMax503Retries = 3; 19 static const int kMax503Retries = 3;
20 20
21 // Extra info associated with requests for use during response processing. 21 // Extra info associated with requests for use during response processing.
22 // This info is deleted when the URLRequest is deleted. 22 // This info is deleted when the URLRequest is deleted.
23 struct UpdateJobInfo : public URLRequest::UserData { 23 class UpdateJobInfo : public URLRequest::UserData {
24 public:
24 enum RequestType { 25 enum RequestType {
25 MANIFEST_FETCH, 26 MANIFEST_FETCH,
26 URL_FETCH, 27 URL_FETCH,
27 MANIFEST_REFETCH, 28 MANIFEST_REFETCH,
28 }; 29 };
29 30
30 explicit UpdateJobInfo(RequestType request_type) 31 explicit UpdateJobInfo(RequestType request_type)
31 : type(request_type), 32 : type_(request_type),
32 buffer(new net::IOBuffer(kBufferSize)), 33 buffer_(new net::IOBuffer(kBufferSize)),
33 retry_503_attempts(0) { 34 retry_503_attempts_(0),
35 update_job_(NULL),
36 request_(NULL),
37 wrote_response_info_(false),
38 ALLOW_THIS_IN_INITIALIZER_LIST(write_callback_(
39 this, &UpdateJobInfo::OnWriteComplete)) {
34 } 40 }
35 41
36 RequestType type; 42 void SetUpResponseWriter(AppCacheResponseWriter* writer,
37 scoped_refptr<net::IOBuffer> buffer; 43 AppCacheUpdateJob* update,
38 // TODO(jennb): need storage info to stream response data to storage 44 URLRequest* request) {
45 DCHECK(!response_writer_.get());
46 response_writer_.reset(writer);
47 update_job_ = update;
48 request_ = request;
49 }
39 50
40 int retry_503_attempts; 51 void OnWriteComplete(int result) {
52 // A completed write may delete the URL request and this object.
53 update_job_->OnWriteResponseComplete(result, request_, this);
54 }
55
56 RequestType type_;
57 scoped_refptr<net::IOBuffer> buffer_;
58 int retry_503_attempts_;
59
60 // Info needed to write responses to storage and process callbacks.
61 scoped_ptr<AppCacheResponseWriter> response_writer_;
62 AppCacheUpdateJob* update_job_;
63 URLRequest* request_;
64 bool wrote_response_info_;
65 net::CompletionCallbackImpl<UpdateJobInfo> write_callback_;
41 }; 66 };
42 67
43 // Helper class for collecting hosts per frontend when sending notifications 68 // Helper class for collecting hosts per frontend when sending notifications
44 // so that only one notification is sent for all hosts using the same frontend. 69 // so that only one notification is sent for all hosts using the same frontend.
45 class HostNotifier { 70 class HostNotifier {
46 public: 71 public:
47 typedef std::vector<int> HostIds; 72 typedef std::vector<int> HostIds;
48 typedef std::map<AppCacheFrontend*, HostIds> NotifyHostMap; 73 typedef std::map<AppCacheFrontend*, HostIds> NotifyHostMap;
49 74
50 // Caller is responsible for ensuring there will be no duplicate hosts. 75 // Caller is responsible for ensuring there will be no duplicate hosts.
(...skipping 24 matching lines...) Expand all
75 100
76 AppCacheUpdateJob::AppCacheUpdateJob(AppCacheService* service, 101 AppCacheUpdateJob::AppCacheUpdateJob(AppCacheService* service,
77 AppCacheGroup* group) 102 AppCacheGroup* group)
78 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), 103 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
79 service_(service), 104 service_(service),
80 group_(group), 105 group_(group),
81 update_type_(UNKNOWN_TYPE), 106 update_type_(UNKNOWN_TYPE),
82 internal_state_(FETCH_MANIFEST), 107 internal_state_(FETCH_MANIFEST),
83 master_entries_completed_(0), 108 master_entries_completed_(0),
84 url_fetches_completed_(0), 109 url_fetches_completed_(0),
85 manifest_url_request_(NULL) { 110 manifest_url_request_(NULL),
111 ALLOW_THIS_IN_INITIALIZER_LIST(manifest_info_write_callback_(
112 this, &AppCacheUpdateJob::OnManifestInfoWriteComplete)),
113 ALLOW_THIS_IN_INITIALIZER_LIST(manifest_data_write_callback_(
114 this, &AppCacheUpdateJob::OnManifestDataWriteComplete)) {
86 DCHECK(group_); 115 DCHECK(group_);
87 manifest_url_ = group_->manifest_url(); 116 manifest_url_ = group_->manifest_url();
88 } 117 }
89 118
90 AppCacheUpdateJob::~AppCacheUpdateJob() { 119 AppCacheUpdateJob::~AppCacheUpdateJob() {
91 if (internal_state_ != COMPLETED) 120 if (internal_state_ != COMPLETED)
92 Cancel(); 121 Cancel();
93 122
94 DCHECK(!manifest_url_request_); 123 DCHECK(!manifest_url_request_);
95 DCHECK(pending_url_fetches_.empty()); 124 DCHECK(pending_url_fetches_.empty());
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 182
154 void AppCacheUpdateJob::OnResponseStarted(URLRequest *request) { 183 void AppCacheUpdateJob::OnResponseStarted(URLRequest *request) {
155 if (request->status().is_success()) 184 if (request->status().is_success())
156 ReadResponseData(request); 185 ReadResponseData(request);
157 else 186 else
158 OnResponseCompleted(request); 187 OnResponseCompleted(request);
159 } 188 }
160 189
161 void AppCacheUpdateJob::ReadResponseData(URLRequest* request) { 190 void AppCacheUpdateJob::ReadResponseData(URLRequest* request) {
162 if (internal_state_ == CACHE_FAILURE || internal_state_ == CANCELLED || 191 if (internal_state_ == CACHE_FAILURE || internal_state_ == CANCELLED ||
163 internal_state_ == COMPLETED) 192 internal_state_ == COMPLETED) {
164 return; 193 return;
194 }
165 195
166 int bytes_read = 0; 196 int bytes_read = 0;
167 UpdateJobInfo* info = 197 UpdateJobInfo* info =
168 static_cast<UpdateJobInfo*>(request->GetUserData(this)); 198 static_cast<UpdateJobInfo*>(request->GetUserData(this));
169 request->Read(info->buffer, kBufferSize, &bytes_read); 199 request->Read(info->buffer_, kBufferSize, &bytes_read);
170 OnReadCompleted(request, bytes_read); 200 OnReadCompleted(request, bytes_read);
171 } 201 }
172 202
173 void AppCacheUpdateJob::OnReadCompleted(URLRequest* request, int bytes_read) { 203 void AppCacheUpdateJob::OnReadCompleted(URLRequest* request, int bytes_read) {
174 bool data_consumed = true; 204 bool data_consumed = true;
175 if (request->status().is_success() && bytes_read > 0) { 205 if (request->status().is_success() && bytes_read > 0) {
176 UpdateJobInfo* info = 206 UpdateJobInfo* info =
177 static_cast<UpdateJobInfo*>(request->GetUserData(this)); 207 static_cast<UpdateJobInfo*>(request->GetUserData(this));
178 208
179 data_consumed = ConsumeResponseData(request, info, bytes_read); 209 data_consumed = ConsumeResponseData(request, info, bytes_read);
180 if (data_consumed) { 210 if (data_consumed) {
181 bytes_read = 0; 211 bytes_read = 0;
182 while (request->Read(info->buffer, kBufferSize, &bytes_read)) { 212 while (request->Read(info->buffer_, kBufferSize, &bytes_read)) {
183 if (bytes_read > 0) { 213 if (bytes_read > 0) {
184 data_consumed = ConsumeResponseData(request, info, bytes_read); 214 data_consumed = ConsumeResponseData(request, info, bytes_read);
185 if (!data_consumed) 215 if (!data_consumed)
186 break; // wait for async data processing, then read more 216 break; // wait for async data processing, then read more
187 } else { 217 } else {
188 break; 218 break;
189 } 219 }
190 } 220 }
191 } 221 }
192 } 222 }
193 223
194 if (data_consumed && !request->status().is_io_pending()) 224 if (data_consumed && !request->status().is_io_pending())
195 OnResponseCompleted(request); 225 OnResponseCompleted(request);
196 } 226 }
197 227
198 bool AppCacheUpdateJob::ConsumeResponseData(URLRequest* request, 228 bool AppCacheUpdateJob::ConsumeResponseData(URLRequest* request,
199 UpdateJobInfo* info, 229 UpdateJobInfo* info,
200 int bytes_read) { 230 int bytes_read) {
201 switch (info->type) { 231 DCHECK_GT(bytes_read, 0);
232 switch (info->type_) {
202 case UpdateJobInfo::MANIFEST_FETCH: 233 case UpdateJobInfo::MANIFEST_FETCH:
203 manifest_data_.append(info->buffer->data(), bytes_read); 234 manifest_data_.append(info->buffer_->data(), bytes_read);
204 break; 235 break;
205 case UpdateJobInfo::URL_FETCH: 236 case UpdateJobInfo::URL_FETCH:
206 // TODO(jennb): stream data to storage. will be async so need to wait 237 if (!info->response_writer_.get()) {
207 // for callback before reading next chunk. 238 info->SetUpResponseWriter(
208 // For now, schedule a task to continue reading to simulate async-ness. 239 service_->storage()->CreateResponseWriter(manifest_url_),
209 MessageLoop::current()->PostTask(FROM_HERE, 240 this, request);
michaeln 2009/10/30 18:48:16 indents are off here
jennb 2009/10/30 18:50:33 Done.
210 method_factory_.NewRunnableMethod( 241 }
211 &AppCacheUpdateJob::ReadResponseData, request)); 242 info->response_writer_->WriteData(info->buffer_, bytes_read,
212 return false; 243 &info->write_callback_);
244 return false; // wait for async write completion to continue reading
213 case UpdateJobInfo::MANIFEST_REFETCH: 245 case UpdateJobInfo::MANIFEST_REFETCH:
214 manifest_refetch_data_.append(info->buffer->data(), bytes_read); 246 manifest_refetch_data_.append(info->buffer_->data(), bytes_read);
215 break; 247 break;
216 default: 248 default:
217 NOTREACHED(); 249 NOTREACHED();
218 } 250 }
219 return true; 251 return true;
220 } 252 }
221 253
254 void AppCacheUpdateJob::OnWriteResponseComplete(int result,
255 URLRequest* request,
256 UpdateJobInfo* info) {
257 DCHECK(internal_state_ == DOWNLOADING);
258
259 if (result < 0) {
260 request->Cancel();
261 OnResponseCompleted(request);
262 return;
263 }
264
265 if (!info->wrote_response_info_) {
266 info->wrote_response_info_ = true;
267 scoped_refptr<HttpResponseInfoIOBuffer> io_buffer =
268 new HttpResponseInfoIOBuffer(
269 new net::HttpResponseInfo(request->response_info()));
270 info->response_writer_->WriteInfo(io_buffer, &info->write_callback_);
271 return;
272 }
273
274 ReadResponseData(request);
275 }
276
222 void AppCacheUpdateJob::OnReceivedRedirect(URLRequest* request, 277 void AppCacheUpdateJob::OnReceivedRedirect(URLRequest* request,
223 const GURL& new_url, 278 const GURL& new_url,
224 bool* defer_redirect) { 279 bool* defer_redirect) {
225 // Redirect is not allowed by the update process. 280 // Redirect is not allowed by the update process.
226 request->Cancel(); 281 request->Cancel();
227 OnResponseCompleted(request); 282 OnResponseCompleted(request);
228 } 283 }
229 284
230 void AppCacheUpdateJob::OnResponseCompleted(URLRequest* request) { 285 void AppCacheUpdateJob::OnResponseCompleted(URLRequest* request) {
231 // Retry for 503s where retry-after is 0. 286 // Retry for 503s where retry-after is 0.
232 if (request->status().is_success() && 287 if (request->status().is_success() &&
233 request->GetResponseCode() == 503 && 288 request->GetResponseCode() == 503 &&
234 RetryRequest(request)) { 289 RetryRequest(request)) {
235 return; 290 return;
236 } 291 }
237 292
238 UpdateJobInfo* info = 293 UpdateJobInfo* info =
239 static_cast<UpdateJobInfo*>(request->GetUserData(this)); 294 static_cast<UpdateJobInfo*>(request->GetUserData(this));
240 switch (info->type) { 295 switch (info->type_) {
241 case UpdateJobInfo::MANIFEST_FETCH: 296 case UpdateJobInfo::MANIFEST_FETCH:
242 HandleManifestFetchCompleted(request); 297 HandleManifestFetchCompleted(request);
243 break; 298 break;
244 case UpdateJobInfo::URL_FETCH: 299 case UpdateJobInfo::URL_FETCH:
245 HandleUrlFetchCompleted(request); 300 HandleUrlFetchCompleted(request);
246 break; 301 break;
247 case UpdateJobInfo::MANIFEST_REFETCH: 302 case UpdateJobInfo::MANIFEST_REFETCH:
248 HandleManifestRefetchCompleted(request); 303 HandleManifestRefetchCompleted(request);
249 break; 304 break;
250 default: 305 default:
251 NOTREACHED(); 306 NOTREACHED();
252 } 307 }
253 308
254 delete request; 309 delete request;
255 } 310 }
256 311
257 bool AppCacheUpdateJob::RetryRequest(URLRequest* request) { 312 bool AppCacheUpdateJob::RetryRequest(URLRequest* request) {
258 UpdateJobInfo* info = 313 UpdateJobInfo* info =
259 static_cast<UpdateJobInfo*>(request->GetUserData(this)); 314 static_cast<UpdateJobInfo*>(request->GetUserData(this));
260 if (info->retry_503_attempts >= kMax503Retries) { 315 if (info->retry_503_attempts_ >= kMax503Retries) {
261 return false; 316 return false;
262 } 317 }
263 318
264 if (!request->response_headers()->HasHeaderValue("retry-after", "0")) 319 if (!request->response_headers()->HasHeaderValue("retry-after", "0"))
265 return false; 320 return false;
266 321
267 const GURL& url = request->original_url(); 322 const GURL& url = request->original_url();
268 URLRequest* retry = new URLRequest(url, this); 323 URLRequest* retry = new URLRequest(url, this);
269 UpdateJobInfo* retry_info = new UpdateJobInfo(info->type); 324 UpdateJobInfo* retry_info = new UpdateJobInfo(info->type_);
270 retry_info->retry_503_attempts = info->retry_503_attempts + 1; 325 retry_info->retry_503_attempts_ = info->retry_503_attempts_ + 1;
271 retry->SetUserData(this, retry_info); 326 retry->SetUserData(this, retry_info);
272 retry->set_context(request->context()); 327 retry->set_context(request->context());
273 retry->set_load_flags(request->load_flags()); 328 retry->set_load_flags(request->load_flags());
274 329
275 switch (info->type) { 330 switch (info->type_) {
276 case UpdateJobInfo::MANIFEST_FETCH: 331 case UpdateJobInfo::MANIFEST_FETCH:
277 case UpdateJobInfo::MANIFEST_REFETCH: 332 case UpdateJobInfo::MANIFEST_REFETCH:
278 manifest_url_request_ = retry; 333 manifest_url_request_ = retry;
279 manifest_data_.clear(); 334 manifest_data_.clear();
280 break; 335 break;
281 case UpdateJobInfo::URL_FETCH: 336 case UpdateJobInfo::URL_FETCH:
282 pending_url_fetches_.erase(url); 337 pending_url_fetches_.erase(url);
283 pending_url_fetches_.insert(PendingUrlFetches::value_type(url, retry)); 338 pending_url_fetches_.insert(PendingUrlFetches::value_type(url, retry));
284 break; 339 break;
285 default: 340 default:
(...skipping 14 matching lines...) Expand all
300 LOG(INFO) << "Request non-success, status: " << request->status().status() 355 LOG(INFO) << "Request non-success, status: " << request->status().status()
301 << " os_error: " << request->status().os_error(); 356 << " os_error: " << request->status().os_error();
302 internal_state_ = CACHE_FAILURE; 357 internal_state_ = CACHE_FAILURE;
303 MaybeCompleteUpdate(); // if not done, run async cache failure steps 358 MaybeCompleteUpdate(); // if not done, run async cache failure steps
304 return; 359 return;
305 } 360 }
306 361
307 int response_code = request->GetResponseCode(); 362 int response_code = request->GetResponseCode();
308 std::string mime_type; 363 std::string mime_type;
309 request->GetMimeType(&mime_type); 364 request->GetMimeType(&mime_type);
365 manifest_response_info_.reset(
366 new net::HttpResponseInfo(request->response_info()));
310 367
311 if ((response_code / 100 == 2) && mime_type == kManifestMimeType) { 368 if ((response_code / 100 == 2) && mime_type == kManifestMimeType) {
312 if (update_type_ == UPGRADE_ATTEMPT) 369 if (update_type_ == UPGRADE_ATTEMPT)
313 CheckIfManifestChanged(); // continues asynchronously 370 CheckIfManifestChanged(); // continues asynchronously
314 else 371 else
315 ContinueHandleManifestFetchCompleted(true); 372 ContinueHandleManifestFetchCompleted(true);
316 } else if (response_code == 304 && update_type_ == UPGRADE_ATTEMPT) { 373 } else if (response_code == 304 && update_type_ == UPGRADE_ATTEMPT) {
317 ContinueHandleManifestFetchCompleted(false); 374 ContinueHandleManifestFetchCompleted(false);
375 } else if (response_code == 404 || response_code == 410) {
376 service_->storage()->MakeGroupObsolete(group_, this); // async
318 } else { 377 } else {
319 if (response_code == 404 || response_code == 410) { 378 LOG(INFO) << "Cache failure, response code: " << response_code;
320 group_->set_obsolete(true); 379 internal_state_ = CACHE_FAILURE;
321 NotifyAllAssociatedHosts(OBSOLETE_EVENT);
322 NotifyAllPendingMasterHosts(ERROR_EVENT);
323 internal_state_ = COMPLETED;
324 } else {
325 LOG(INFO) << "Cache failure, response code: " << response_code;
326 internal_state_ = CACHE_FAILURE;
327 }
328 MaybeCompleteUpdate(); // if not done, run async cache failure steps 380 MaybeCompleteUpdate(); // if not done, run async cache failure steps
329 } 381 }
330 } 382 }
331 383
384 void AppCacheUpdateJob::OnGroupMadeObsolete(AppCacheGroup* group,
385 bool success) {
386 NotifyAllPendingMasterHosts(ERROR_EVENT);
387 if (success) {
388 DCHECK(group->is_obsolete());
389 NotifyAllAssociatedHosts(OBSOLETE_EVENT);
390 internal_state_ = COMPLETED;
391 } else {
392 // Treat failure to mark group obsolete as a cache failure.
393 internal_state_ = CACHE_FAILURE;
394 }
395 MaybeCompleteUpdate();
396 }
397
332 void AppCacheUpdateJob::ContinueHandleManifestFetchCompleted(bool changed) { 398 void AppCacheUpdateJob::ContinueHandleManifestFetchCompleted(bool changed) {
333 DCHECK(internal_state_ == FETCH_MANIFEST); 399 DCHECK(internal_state_ == FETCH_MANIFEST);
334 400
335 if (!changed) { 401 if (!changed) {
336 DCHECK(update_type_ == UPGRADE_ATTEMPT); 402 DCHECK(update_type_ == UPGRADE_ATTEMPT);
337 internal_state_ = NO_UPDATE; 403 internal_state_ = NO_UPDATE;
338 MaybeCompleteUpdate(); // if not done, run async 6.9.4 step 7 substeps 404 MaybeCompleteUpdate(); // if not done, run async 6.9.4 step 7 substeps
339 return; 405 return;
340 } 406 }
341 407
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 void AppCacheUpdateJob::HandleUrlFetchCompleted(URLRequest* request) { 441 void AppCacheUpdateJob::HandleUrlFetchCompleted(URLRequest* request) {
376 DCHECK(internal_state_ == DOWNLOADING); 442 DCHECK(internal_state_ == DOWNLOADING);
377 443
378 const GURL& url = request->original_url(); 444 const GURL& url = request->original_url();
379 pending_url_fetches_.erase(url); 445 pending_url_fetches_.erase(url);
380 ++url_fetches_completed_; 446 ++url_fetches_completed_;
381 447
382 int response_code = request->GetResponseCode(); 448 int response_code = request->GetResponseCode();
383 AppCacheEntry& entry = url_file_list_.find(url)->second; 449 AppCacheEntry& entry = url_file_list_.find(url)->second;
384 450
451 UpdateJobInfo* info =
452 static_cast<UpdateJobInfo*>(request->GetUserData(this));
453
385 if (request->status().is_success() && (response_code / 100 == 2)) { 454 if (request->status().is_success() && (response_code / 100 == 2)) {
386 // TODO(jennb): associate storage with the new entry 455 // Associate storage with the new entry.
456 DCHECK(info->response_writer_.get());
457 entry.set_response_id(info->response_writer_->response_id());
458
387 inprogress_cache_->AddEntry(url, entry); 459 inprogress_cache_->AddEntry(url, entry);
388 460
389 // Foreign entries will be detected during cache selection. 461 // Foreign entries will be detected during cache selection.
390 // Note: 6.9.4, step 17.9 possible optimization: if resource is HTML or XML 462 // Note: 6.9.4, step 17.9 possible optimization: if resource is HTML or XML
391 // file whose root element is an html element with a manifest attribute 463 // file whose root element is an html element with a manifest attribute
392 // whose value doesn't match the manifest url of the application cache 464 // whose value doesn't match the manifest url of the application cache
393 // being processed, mark the entry as being foreign. 465 // being processed, mark the entry as being foreign.
394 } else { 466 } else {
395 LOG(INFO) << "Request status: " << request->status().status() 467 LOG(INFO) << "Request status: " << request->status().status()
396 << " os_error: " << request->status().os_error() 468 << " os_error: " << request->status().os_error()
397 << " response code: " << response_code; 469 << " response code: " << response_code;
398 470
399 // TODO(jennb): discard any stored data for this entry 471 // TODO(jennb): Discard any stored data for this entry? May be unnecessary
472 // if handled automatically by storage layer.
473
400 if (entry.IsExplicit() || entry.IsFallback()) { 474 if (entry.IsExplicit() || entry.IsFallback()) {
401 internal_state_ = CACHE_FAILURE; 475 internal_state_ = CACHE_FAILURE;
402 476
403 // Cancel any pending URL requests. 477 // Cancel any pending URL requests.
404 for (PendingUrlFetches::iterator it = pending_url_fetches_.begin(); 478 for (PendingUrlFetches::iterator it = pending_url_fetches_.begin();
405 it != pending_url_fetches_.end(); ++it) { 479 it != pending_url_fetches_.end(); ++it) {
406 delete it->second; 480 delete it->second;
407 } 481 }
408 482
409 url_fetches_completed_ += 483 url_fetches_completed_ +=
(...skipping 17 matching lines...) Expand all
427 501
428 MaybeCompleteUpdate(); 502 MaybeCompleteUpdate();
429 } 503 }
430 504
431 void AppCacheUpdateJob::HandleManifestRefetchCompleted(URLRequest* request) { 505 void AppCacheUpdateJob::HandleManifestRefetchCompleted(URLRequest* request) {
432 DCHECK(internal_state_ == REFETCH_MANIFEST); 506 DCHECK(internal_state_ == REFETCH_MANIFEST);
433 manifest_url_request_ = NULL; 507 manifest_url_request_ = NULL;
434 508
435 int response_code = request->GetResponseCode(); 509 int response_code = request->GetResponseCode();
436 if (response_code == 304 || manifest_data_ == manifest_refetch_data_) { 510 if (response_code == 304 || manifest_data_ == manifest_refetch_data_) {
437 AppCacheEntry entry(AppCacheEntry::MANIFEST); 511 // Only need to store response in storage if manifest is not already an
438 // TODO(jennb): add manifest_data_ to storage and put storage key in entry 512 // an entry in the cache.
439 // Also store response headers from request for HTTP cache control. 513 AppCacheEntry* entry = inprogress_cache_->GetEntry(manifest_url_);
440 inprogress_cache_->AddOrModifyEntry(manifest_url_, entry); 514 if (entry) {
441 inprogress_cache_->set_update_time(base::TimeTicks::Now()); 515 entry->add_types(AppCacheEntry::MANIFEST);
442 516 CompleteInprogressCache();
443 // TODO(jennb): start of part to make async (cache/group storage may fail)
444 inprogress_cache_->set_complete(true);
445 group_->AddCache(inprogress_cache_);
446 protect_new_cache_.swap(inprogress_cache_);
447
448 // TODO(jennb): write new group and cache to storage here
449
450 if (update_type_ == CACHE_ATTEMPT) {
451 NotifyAllAssociatedHosts(CACHED_EVENT);
452 } else { 517 } else {
453 NotifyAllAssociatedHosts(UPDATE_READY_EVENT); 518 manifest_response_writer_.reset(
519 service_->storage()->CreateResponseWriter(manifest_url_));
520 scoped_refptr<HttpResponseInfoIOBuffer> io_buffer =
521 new HttpResponseInfoIOBuffer(manifest_response_info_.release());
522 manifest_response_writer_->WriteInfo(io_buffer,
523 &manifest_info_write_callback_);
454 } 524 }
455 internal_state_ = COMPLETED;
456 // TODO(jennb): end of part that needs to be made async.
457 } else { 525 } else {
458 LOG(INFO) << "Request status: " << request->status().status() 526 LOG(INFO) << "Request status: " << request->status().status()
459 << " os_error: " << request->status().os_error() 527 << " os_error: " << request->status().os_error()
460 << " response code: " << response_code; 528 << " response code: " << response_code;
529 HandleManifestRefetchFailure();
530 }
531 }
532
533 void AppCacheUpdateJob::OnManifestInfoWriteComplete(int result) {
534 if (result > 0) {
535 scoped_refptr<net::StringIOBuffer> io_buffer =
536 new net::StringIOBuffer(manifest_data_);
537 manifest_response_writer_->WriteData(io_buffer, manifest_data_.length(),
538 &manifest_data_write_callback_);
539 } else {
540 // Treat storage failure as if refetch of manifest failed.
541 HandleManifestRefetchFailure();
542 }
543 }
544
545 void AppCacheUpdateJob::OnManifestDataWriteComplete(int result) {
546 if (result > 0) {
547 AppCacheEntry entry(AppCacheEntry::MANIFEST,
548 manifest_response_writer_->response_id());
549 inprogress_cache_->AddOrModifyEntry(manifest_url_, entry);
550 CompleteInprogressCache();
551 } else {
552 // Treat storage failure as if refetch of manifest failed.
553 HandleManifestRefetchFailure();
554 }
555 }
556
557 void AppCacheUpdateJob::CompleteInprogressCache() {
558 inprogress_cache_->set_update_time(base::TimeTicks::Now());
559 inprogress_cache_->set_complete(true);
560
561 protect_former_newest_cache_ = group_->newest_complete_cache();
562 group_->AddCache(inprogress_cache_);
563 protect_new_cache_.swap(inprogress_cache_);
564
565 service_->storage()->StoreGroupAndNewestCache(group_, this); // async
566 }
567
568 void AppCacheUpdateJob::OnGroupAndNewestCacheStored(AppCacheGroup* group,
569 bool success) {
570 if (success) {
571 if (update_type_ == CACHE_ATTEMPT)
572 NotifyAllAssociatedHosts(CACHED_EVENT);
573 else
574 NotifyAllAssociatedHosts(UPDATE_READY_EVENT);
575 internal_state_ = COMPLETED;
576 MaybeCompleteUpdate(); // will definitely complete
577 } else {
578 // TODO(jennb): Change storage so clients won't need to revert group state?
579 // Change group back to reflect former newest group.
580 group_->RestoreCacheAsNewest(protect_former_newest_cache_);
581 protect_new_cache_ = NULL;
582
583 // Treat storage failure as if manifest refetch failed.
584 HandleManifestRefetchFailure();
585 }
586 protect_former_newest_cache_ = NULL;
587 }
588
589 void AppCacheUpdateJob::HandleManifestRefetchFailure() {
461 ScheduleUpdateRetry(kRerunDelayMs); 590 ScheduleUpdateRetry(kRerunDelayMs);
462 internal_state_ = CACHE_FAILURE; 591 internal_state_ = CACHE_FAILURE;
463 } 592 MaybeCompleteUpdate(); // will definitely complete
464
465 MaybeCompleteUpdate(); // will definitely complete
466 } 593 }
467 594
468 void AppCacheUpdateJob::NotifySingleHost(AppCacheHost* host, 595 void AppCacheUpdateJob::NotifySingleHost(AppCacheHost* host,
469 EventID event_id) { 596 EventID event_id) {
470 std::vector<int> ids(1, host->host_id()); 597 std::vector<int> ids(1, host->host_id());
471 host->frontend()->OnEventRaised(ids, event_id); 598 host->frontend()->OnEventRaised(ids, event_id);
472 } 599 }
473 600
474 void AppCacheUpdateJob::NotifyAllPendingMasterHosts(EventID event_id) { 601 void AppCacheUpdateJob::NotifyAllPendingMasterHosts(EventID event_id) {
475 // Collect hosts so we only send one notification per frontend. 602 // Collect hosts so we only send one notification per frontend.
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
647 774
648 // Re-insert url at front of fetch list. Indicate storage has been checked. 775 // Re-insert url at front of fetch list. Indicate storage has been checked.
649 urls_to_fetch_.push_front(AppCacheUpdateJob::UrlToFetch(url, true)); 776 urls_to_fetch_.push_front(AppCacheUpdateJob::UrlToFetch(url, true));
650 FetchUrls(); 777 FetchUrls();
651 } 778 }
652 779
653 void AppCacheUpdateJob::CopyEntryToCache(const GURL& url, 780 void AppCacheUpdateJob::CopyEntryToCache(const GURL& url,
654 const AppCacheEntry& src, 781 const AppCacheEntry& src,
655 AppCacheEntry* dest) { 782 AppCacheEntry* dest) {
656 DCHECK(dest); 783 DCHECK(dest);
657 // TODO(jennb): copy storage key from src to dest 784 dest->set_response_id(src.response_id());
658 inprogress_cache_->AddEntry(url, *dest); 785 inprogress_cache_->AddEntry(url, *dest);
659 } 786 }
660 787
661 void AppCacheUpdateJob::MaybeCompleteUpdate() { 788 void AppCacheUpdateJob::MaybeCompleteUpdate() {
662 // Must wait for any pending master entries or url fetches to complete. 789 // Must wait for any pending master entries or url fetches to complete.
663 if (master_entries_completed_ != pending_master_entries_.size() || 790 if (master_entries_completed_ != pending_master_entries_.size() ||
664 url_fetches_completed_ != url_file_list_.size() ) { 791 url_fetches_completed_ != url_file_list_.size() ) {
665 DCHECK(internal_state_ != COMPLETED); 792 DCHECK(internal_state_ != COMPLETED);
666 return; 793 return;
667 } 794 }
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
711 manifest_url_request_ = NULL; 838 manifest_url_request_ = NULL;
712 } 839 }
713 840
714 for (PendingUrlFetches::iterator it = pending_url_fetches_.begin(); 841 for (PendingUrlFetches::iterator it = pending_url_fetches_.begin();
715 it != pending_url_fetches_.end(); ++it) { 842 it != pending_url_fetches_.end(); ++it) {
716 delete it->second; 843 delete it->second;
717 } 844 }
718 845
719 pending_master_entries_.clear(); 846 pending_master_entries_.clear();
720 DiscardInprogressCache(); 847 DiscardInprogressCache();
721 // TODO(jennb): cancel any storage callbacks 848
849 // Delete response writer to avoid any callbacks.
850 if (manifest_response_writer_.get())
851 manifest_response_writer_.reset();
852
853 service_->storage()->CancelDelegateCallbacks(this);
722 } 854 }
723 855
724 void AppCacheUpdateJob::DiscardInprogressCache() { 856 void AppCacheUpdateJob::DiscardInprogressCache() {
725 if (!inprogress_cache_) 857 if (!inprogress_cache_)
726 return; 858 return;
727 859
728 // TODO(jennb): cleanup stored responses for entries in the cache 860 // TODO(jennb): Cleanup stored responses for entries in the cache?
861 // May not be necessary if handled automatically by storage layer.
862
729 inprogress_cache_ = NULL; 863 inprogress_cache_ = NULL;
730 } 864 }
731 865
732 void AppCacheUpdateJob::DeleteSoon() { 866 void AppCacheUpdateJob::DeleteSoon() {
867 manifest_response_writer_.reset();
868 service_->storage()->CancelDelegateCallbacks(this);
869
733 // Break the connection with the group so the group cannot call delete 870 // Break the connection with the group so the group cannot call delete
734 // on this object after we've posted a task to delete ourselves. 871 // on this object after we've posted a task to delete ourselves.
735 group_->SetUpdateStatus(AppCacheGroup::IDLE); 872 group_->SetUpdateStatus(AppCacheGroup::IDLE);
736 protect_new_cache_ = NULL; 873 protect_new_cache_ = NULL;
737 group_ = NULL; 874 group_ = NULL;
738 875
739 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 876 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
740 } 877 }
741 878
742 } // namespace appcache 879 } // namespace appcache
OLDNEW
« no previous file with comments | « webkit/appcache/appcache_update_job.h ('k') | webkit/appcache/appcache_update_job_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698