Chromium Code Reviews| 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 |