OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |