Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/http/http_cache.h" | 5 #include "net/http/http_cache.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
| 10 | 10 |
| (...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 285 virtual QuicServerInfo* GetForServer( | 285 virtual QuicServerInfo* GetForServer( |
| 286 const QuicServerId& server_id) OVERRIDE { | 286 const QuicServerId& server_id) OVERRIDE { |
| 287 return new DiskCacheBasedQuicServerInfo(server_id, http_cache_); | 287 return new DiskCacheBasedQuicServerInfo(server_id, http_cache_); |
| 288 } | 288 } |
| 289 | 289 |
| 290 private: | 290 private: |
| 291 HttpCache* const http_cache_; | 291 HttpCache* const http_cache_; |
| 292 }; | 292 }; |
| 293 | 293 |
| 294 //----------------------------------------------------------------------------- | 294 //----------------------------------------------------------------------------- |
| 295 | |
| 296 class HttpCache::AsyncValidation { | |
| 297 public: | |
| 298 AsyncValidation(const HttpRequestInfo& original_request, HttpCache* cache) | |
| 299 : request_(original_request), cache_(cache) {} | |
| 300 ~AsyncValidation() {} | |
| 301 | |
| 302 void Start(const BoundNetLog& net_log); | |
| 303 | |
| 304 private: | |
| 305 void OnStarted(int result); | |
| 306 void DoRead(); | |
| 307 void OnRead(int result); | |
| 308 | |
| 309 // Terminate this request with net error code |result|. Logs the transaction | |
| 310 // result and asks HttpCache to delete this object. | |
| 311 // If there was a client or server certificate error, it cannot be recovered | |
| 312 // asynchronously, so we need to prevent futures attempts to asynchronously | |
| 313 // fetch the resource. In this case, the cache entry is doomed. | |
| 314 void Terminate(int result); | |
| 315 | |
| 316 HttpRequestInfo request_; | |
| 317 scoped_refptr<IOBuffer> buf_; | |
| 318 CompletionCallback read_callback_; | |
| 319 scoped_ptr<Transaction> transaction_; | |
| 320 | |
| 321 // The HttpCache object owns this object. This object is always deleted before | |
| 322 // the pointer to the cache becomes invalid. | |
| 323 HttpCache* cache_; | |
| 324 | |
| 325 DISALLOW_COPY_AND_ASSIGN(AsyncValidation); | |
| 326 }; | |
| 327 | |
| 328 void HttpCache::AsyncValidation::Start(const BoundNetLog& net_log) { | |
| 329 transaction_.reset(new Transaction(IDLE, cache_)); | |
| 330 request_.load_flags |= LOAD_VALIDATE_CACHE; | |
| 331 // This use of base::Unretained is safe because |transaction_| is owned by | |
| 332 // this object. | |
| 333 read_callback_ = base::Bind(&AsyncValidation::OnRead, base::Unretained(this)); | |
| 334 // This use of base::Unretained is safe as above. | |
| 335 int rv = transaction_->Start( | |
| 336 &request_, | |
| 337 base::Bind(&AsyncValidation::OnStarted, base::Unretained(this)), | |
| 338 net_log); | |
| 339 | |
| 340 if (rv == ERR_IO_PENDING) | |
| 341 return; | |
| 342 | |
| 343 OnStarted(rv); | |
| 344 } | |
| 345 | |
| 346 void HttpCache::AsyncValidation::OnStarted(int result) { | |
| 347 if (result != OK) { | |
| 348 DVLOG(1) << "Asynchronous transaction start failed for " << request_.url; | |
| 349 Terminate(result); | |
| 350 return; | |
| 351 } | |
| 352 | |
| 353 DoRead(); | |
| 354 } | |
| 355 | |
| 356 void HttpCache::AsyncValidation::DoRead() { | |
| 357 const size_t kBufSize = 4096; | |
| 358 if (!buf_) | |
| 359 buf_ = new IOBuffer(kBufSize); | |
| 360 | |
| 361 int rv = 0; | |
| 362 while (rv > 0) { | |
|
yhirano
2014/08/26 07:52:01
dead code :)
Adam Rice
2014/08/26 13:38:41
Amazing! This doesn't seem to make any difference
| |
| 363 rv = transaction_->Read(buf_.get(), kBufSize, read_callback_); | |
| 364 } | |
| 365 | |
| 366 if (rv == ERR_IO_PENDING) | |
| 367 return; | |
| 368 | |
| 369 OnRead(rv); | |
| 370 } | |
| 371 | |
| 372 void HttpCache::AsyncValidation::OnRead(int result) { | |
| 373 if (result > 0) { | |
| 374 DoRead(); | |
| 375 return; | |
| 376 } | |
| 377 Terminate(result); | |
| 378 } | |
| 379 | |
| 380 void HttpCache::AsyncValidation::Terminate(int result) { | |
| 381 if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED || IsCertificateError(result)) | |
| 382 cache_->DoomEntry(transaction_->key(), transaction_.get()); | |
| 383 transaction_->net_log().EndEventWithNetErrorCode( | |
| 384 NetLog::TYPE_ASYNC_REVALIDATION, result); | |
| 385 cache_->DeleteAsyncValidation(this); | |
| 386 // |this| is deleted. | |
| 387 } | |
| 388 | |
| 389 //----------------------------------------------------------------------------- | |
| 295 HttpCache::HttpCache(const net::HttpNetworkSession::Params& params, | 390 HttpCache::HttpCache(const net::HttpNetworkSession::Params& params, |
| 296 BackendFactory* backend_factory) | 391 BackendFactory* backend_factory) |
| 297 : net_log_(params.net_log), | 392 : net_log_(params.net_log), |
| 298 backend_factory_(backend_factory), | 393 backend_factory_(backend_factory), |
| 299 building_backend_(false), | 394 building_backend_(false), |
| 300 bypass_lock_for_test_(false), | 395 bypass_lock_for_test_(false), |
| 396 use_stale_while_revalidate_(params.use_stale_while_revalidate), | |
| 301 mode_(NORMAL), | 397 mode_(NORMAL), |
| 302 network_layer_(new HttpNetworkLayer(new HttpNetworkSession(params))), | 398 network_layer_(new HttpNetworkLayer(new HttpNetworkSession(params))), |
| 303 weak_factory_(this) { | 399 weak_factory_(this) { |
| 304 SetupQuicServerInfoFactory(network_layer_->GetSession()); | 400 SetupQuicServerInfoFactory(network_layer_->GetSession()); |
| 305 } | 401 } |
| 306 | 402 |
| 307 | 403 |
| 308 // This call doesn't change the shared |session|'s QuicServerInfoFactory because | 404 // This call doesn't change the shared |session|'s QuicServerInfoFactory because |
| 309 // |session| is shared. | 405 // |session| is shared. |
| 310 HttpCache::HttpCache(HttpNetworkSession* session, | 406 HttpCache::HttpCache(HttpNetworkSession* session, |
| 311 BackendFactory* backend_factory) | 407 BackendFactory* backend_factory) |
| 312 : net_log_(session->net_log()), | 408 : net_log_(session->net_log()), |
| 313 backend_factory_(backend_factory), | 409 backend_factory_(backend_factory), |
| 314 building_backend_(false), | 410 building_backend_(false), |
| 315 bypass_lock_for_test_(false), | 411 bypass_lock_for_test_(false), |
| 412 use_stale_while_revalidate_(session->params().use_stale_while_revalidate), | |
| 316 mode_(NORMAL), | 413 mode_(NORMAL), |
| 317 network_layer_(new HttpNetworkLayer(session)), | 414 network_layer_(new HttpNetworkLayer(session)), |
| 318 weak_factory_(this) { | 415 weak_factory_(this) { |
| 319 } | 416 } |
| 320 | 417 |
| 321 HttpCache::HttpCache(HttpTransactionFactory* network_layer, | 418 HttpCache::HttpCache(HttpTransactionFactory* network_layer, |
| 322 NetLog* net_log, | 419 NetLog* net_log, |
| 323 BackendFactory* backend_factory) | 420 BackendFactory* backend_factory) |
| 324 : net_log_(net_log), | 421 : net_log_(net_log), |
| 325 backend_factory_(backend_factory), | 422 backend_factory_(backend_factory), |
| 326 building_backend_(false), | 423 building_backend_(false), |
| 327 bypass_lock_for_test_(false), | 424 bypass_lock_for_test_(false), |
| 425 use_stale_while_revalidate_(false), | |
| 328 mode_(NORMAL), | 426 mode_(NORMAL), |
| 329 network_layer_(network_layer), | 427 network_layer_(network_layer), |
| 330 weak_factory_(this) { | 428 weak_factory_(this) { |
| 331 SetupQuicServerInfoFactory(network_layer_->GetSession()); | 429 SetupQuicServerInfoFactory(network_layer_->GetSession()); |
| 430 HttpNetworkSession* session = network_layer_->GetSession(); | |
| 431 if (session) | |
| 432 use_stale_while_revalidate_ = session->params().use_stale_while_revalidate; | |
| 332 } | 433 } |
| 333 | 434 |
| 334 HttpCache::~HttpCache() { | 435 HttpCache::~HttpCache() { |
| 335 // Transactions should see an invalid cache after this point; otherwise they | 436 // Transactions should see an invalid cache after this point; otherwise they |
| 336 // could see an inconsistent object (half destroyed). | 437 // could see an inconsistent object (half destroyed). |
| 337 weak_factory_.InvalidateWeakPtrs(); | 438 weak_factory_.InvalidateWeakPtrs(); |
| 338 | 439 |
| 339 // If we have any active entries remaining, then we need to deactivate them. | 440 // If we have any active entries remaining, then we need to deactivate them. |
| 340 // We may have some pending calls to OnProcessPendingQueue, but since those | 441 // We may have some pending calls to OnProcessPendingQueue, but since those |
| 341 // won't run (due to our destruction), we can simply ignore the corresponding | 442 // won't run (due to our destruction), we can simply ignore the corresponding |
| 342 // will_process_pending_queue flag. | 443 // will_process_pending_queue flag. |
| 343 while (!active_entries_.empty()) { | 444 while (!active_entries_.empty()) { |
| 344 ActiveEntry* entry = active_entries_.begin()->second; | 445 ActiveEntry* entry = active_entries_.begin()->second; |
| 345 entry->will_process_pending_queue = false; | 446 entry->will_process_pending_queue = false; |
| 346 entry->pending_queue.clear(); | 447 entry->pending_queue.clear(); |
| 347 entry->readers.clear(); | 448 entry->readers.clear(); |
| 348 entry->writer = NULL; | 449 entry->writer = NULL; |
| 349 DeactivateEntry(entry); | 450 DeactivateEntry(entry); |
| 350 } | 451 } |
| 351 | 452 |
| 352 STLDeleteElements(&doomed_entries_); | 453 STLDeleteElements(&doomed_entries_); |
| 454 STLDeleteElements(&async_validations_); | |
| 353 | 455 |
| 354 // Before deleting pending_ops_, we have to make sure that the disk cache is | 456 // Before deleting pending_ops_, we have to make sure that the disk cache is |
| 355 // done with said operations, or it will attempt to use deleted data. | 457 // done with said operations, or it will attempt to use deleted data. |
| 356 cert_cache_.reset(); | 458 cert_cache_.reset(); |
| 357 disk_cache_.reset(); | 459 disk_cache_.reset(); |
| 358 | 460 |
| 359 PendingOpsMap::iterator pending_it = pending_ops_.begin(); | 461 PendingOpsMap::iterator pending_it = pending_ops_.begin(); |
| 360 for (; pending_it != pending_ops_.end(); ++pending_it) { | 462 for (; pending_it != pending_ops_.end(); ++pending_it) { |
| 361 // We are not notifying the transactions about the cache going away, even | 463 // We are not notifying the transactions about the cache going away, even |
| 362 // though they are waiting for a callback that will never fire. | 464 // though they are waiting for a callback that will never fire. |
| (...skipping 668 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1031 // not delete the entry before OnProcessPendingQueue runs. | 1133 // not delete the entry before OnProcessPendingQueue runs. |
| 1032 if (entry->will_process_pending_queue) | 1134 if (entry->will_process_pending_queue) |
| 1033 return; | 1135 return; |
| 1034 entry->will_process_pending_queue = true; | 1136 entry->will_process_pending_queue = true; |
| 1035 | 1137 |
| 1036 base::MessageLoop::current()->PostTask( | 1138 base::MessageLoop::current()->PostTask( |
| 1037 FROM_HERE, | 1139 FROM_HERE, |
| 1038 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry)); | 1140 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry)); |
| 1039 } | 1141 } |
| 1040 | 1142 |
| 1143 void HttpCache::PerformAsyncValidation(const HttpRequestInfo& original_request, | |
| 1144 const BoundNetLog& net_log) { | |
|
yhirano
2014/08/26 07:52:01
DCHECK(use_stale_while_revalidate_)?
Adam Rice
2014/08/26 13:38:41
Done.
| |
| 1145 scoped_ptr<AsyncValidation> job(new AsyncValidation(original_request, this)); | |
| 1146 job->Start(net_log); | |
|
yhirano
2014/08/26 07:52:01
When all operations are done synchronously, |this-
Adam Rice
2014/08/26 13:38:41
Good catch! Thanks!
I have added a test (Synchron
| |
| 1147 bool insert_ok = async_validations_.insert(job.release()).second; | |
| 1148 DCHECK(insert_ok); | |
| 1149 } | |
| 1150 | |
| 1151 void HttpCache::DeleteAsyncValidation(AsyncValidation* async_validation) { | |
| 1152 size_t erased = async_validations_.erase(async_validation); | |
| 1153 DCHECK_EQ(1U, erased); | |
| 1154 delete async_validation; | |
| 1155 } | |
| 1156 | |
| 1041 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) { | 1157 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) { |
| 1042 entry->will_process_pending_queue = false; | 1158 entry->will_process_pending_queue = false; |
| 1043 DCHECK(!entry->writer); | 1159 DCHECK(!entry->writer); |
| 1044 | 1160 |
| 1045 // If no one is interested in this entry, then we can deactivate it. | 1161 // If no one is interested in this entry, then we can deactivate it. |
| 1046 if (entry->pending_queue.empty()) { | 1162 if (entry->pending_queue.empty()) { |
| 1047 if (entry->readers.empty()) | 1163 if (entry->readers.empty()) |
| 1048 DestroyEntry(entry); | 1164 DestroyEntry(entry); |
| 1049 return; | 1165 return; |
| 1050 } | 1166 } |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1201 building_backend_ = false; | 1317 building_backend_ = false; |
| 1202 DeletePendingOp(pending_op); | 1318 DeletePendingOp(pending_op); |
| 1203 } | 1319 } |
| 1204 | 1320 |
| 1205 // The cache may be gone when we return from the callback. | 1321 // The cache may be gone when we return from the callback. |
| 1206 if (!item->DoCallback(result, disk_cache_.get())) | 1322 if (!item->DoCallback(result, disk_cache_.get())) |
| 1207 item->NotifyTransaction(result, NULL); | 1323 item->NotifyTransaction(result, NULL); |
| 1208 } | 1324 } |
| 1209 | 1325 |
| 1210 } // namespace net | 1326 } // namespace net |
| OLD | NEW |