| 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/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 #include "base/strings/string_util.h" | 23 #include "base/strings/string_util.h" |
| 24 #include "base/strings/stringprintf.h" | 24 #include "base/strings/stringprintf.h" |
| 25 #include "base/thread_task_runner_handle.h" | 25 #include "base/thread_task_runner_handle.h" |
| 26 #include "base/threading/worker_pool.h" | 26 #include "base/threading/worker_pool.h" |
| 27 #include "base/time/default_clock.h" | 27 #include "base/time/default_clock.h" |
| 28 #include "base/time/time.h" | 28 #include "base/time/time.h" |
| 29 #include "net/base/cache_type.h" | 29 #include "net/base/cache_type.h" |
| 30 #include "net/base/io_buffer.h" | 30 #include "net/base/io_buffer.h" |
| 31 #include "net/base/load_flags.h" | 31 #include "net/base/load_flags.h" |
| 32 #include "net/base/net_errors.h" | 32 #include "net/base/net_errors.h" |
| 33 #include "net/base/network_delegate.h" | |
| 34 #include "net/base/upload_data_stream.h" | 33 #include "net/base/upload_data_stream.h" |
| 35 #include "net/disk_cache/disk_cache.h" | 34 #include "net/disk_cache/disk_cache.h" |
| 36 #include "net/http/disk_based_cert_cache.h" | 35 #include "net/http/disk_based_cert_cache.h" |
| 37 #include "net/http/disk_cache_based_quic_server_info.h" | 36 #include "net/http/disk_cache_based_quic_server_info.h" |
| 38 #include "net/http/http_cache_transaction.h" | 37 #include "net/http/http_cache_transaction.h" |
| 39 #include "net/http/http_network_layer.h" | 38 #include "net/http/http_network_layer.h" |
| 40 #include "net/http/http_network_session.h" | 39 #include "net/http/http_network_session.h" |
| 41 #include "net/http/http_request_info.h" | 40 #include "net/http/http_request_info.h" |
| 42 #include "net/http/http_response_headers.h" | 41 #include "net/http/http_response_headers.h" |
| 43 #include "net/http/http_response_info.h" | 42 #include "net/http/http_response_info.h" |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 | 287 |
| 289 QuicServerInfo* GetForServer(const QuicServerId& server_id) override { | 288 QuicServerInfo* GetForServer(const QuicServerId& server_id) override { |
| 290 return new DiskCacheBasedQuicServerInfo(server_id, http_cache_); | 289 return new DiskCacheBasedQuicServerInfo(server_id, http_cache_); |
| 291 } | 290 } |
| 292 | 291 |
| 293 private: | 292 private: |
| 294 HttpCache* const http_cache_; | 293 HttpCache* const http_cache_; |
| 295 }; | 294 }; |
| 296 | 295 |
| 297 //----------------------------------------------------------------------------- | 296 //----------------------------------------------------------------------------- |
| 298 | |
| 299 class HttpCache::AsyncValidation { | |
| 300 public: | |
| 301 AsyncValidation(const HttpRequestInfo& original_request, HttpCache* cache) | |
| 302 : request_(original_request), cache_(cache) {} | |
| 303 ~AsyncValidation() {} | |
| 304 | |
| 305 void Start(const BoundNetLog& net_log, | |
| 306 scoped_ptr<Transaction> transaction, | |
| 307 NetworkDelegate* network_delegate); | |
| 308 | |
| 309 private: | |
| 310 void OnStarted(int result); | |
| 311 void DoRead(); | |
| 312 void OnRead(int result); | |
| 313 | |
| 314 // Terminate this request with net error code |result|. Logs the transaction | |
| 315 // result and asks HttpCache to delete this object. | |
| 316 // If there was a client or server certificate error, it cannot be recovered | |
| 317 // asynchronously, so we need to prevent future attempts to asynchronously | |
| 318 // fetch the resource. In this case, the cache entry is doomed. | |
| 319 void Terminate(int result); | |
| 320 | |
| 321 HttpRequestInfo request_; | |
| 322 scoped_refptr<IOBuffer> buf_; | |
| 323 CompletionCallback read_callback_; | |
| 324 scoped_ptr<Transaction> transaction_; | |
| 325 base::Time start_time_; | |
| 326 | |
| 327 // The HttpCache object owns this object. This object is always deleted before | |
| 328 // the pointer to the cache becomes invalid. | |
| 329 HttpCache* cache_; | |
| 330 | |
| 331 DISALLOW_COPY_AND_ASSIGN(AsyncValidation); | |
| 332 }; | |
| 333 | |
| 334 void HttpCache::AsyncValidation::Start(const BoundNetLog& net_log, | |
| 335 scoped_ptr<Transaction> transaction, | |
| 336 NetworkDelegate* network_delegate) { | |
| 337 transaction_ = transaction.Pass(); | |
| 338 if (network_delegate) { | |
| 339 // This code is necessary to enable async transactions to pass over the | |
| 340 // data-reduction proxy. This is a violation of the "once-and-only-once" | |
| 341 // principle, since it copies code from URLRequestHttpJob. We cannot use the | |
| 342 // original callback passed to HttpCache::Transaction by URLRequestHttpJob | |
| 343 // as it will only be valid as long as the URLRequestHttpJob object is | |
| 344 // alive, and that object will be deleted as soon as the synchronous request | |
| 345 // completes. | |
| 346 // | |
| 347 // This code is also an encapsulation violation. We are exploiting the fact | |
| 348 // that the |request| parameter to NotifyBeforeSendProxyHeaders() is never | |
| 349 // actually used for anything, and so can be NULL. | |
| 350 // | |
| 351 // TODO(ricea): Do this better. | |
| 352 transaction_->SetBeforeProxyHeadersSentCallback( | |
| 353 base::Bind(&NetworkDelegate::NotifyBeforeSendProxyHeaders, | |
| 354 base::Unretained(network_delegate), | |
| 355 static_cast<URLRequest*>(NULL))); | |
| 356 // The above use of base::Unretained is safe because the NetworkDelegate has | |
| 357 // to live at least as long as the HttpNetworkSession which has to live as | |
| 358 // least as long as the HttpNetworkLayer which has to live at least as long | |
| 359 // this HttpCache object. | |
| 360 } | |
| 361 | |
| 362 DCHECK_EQ(0, request_.load_flags & LOAD_ASYNC_REVALIDATION); | |
| 363 request_.load_flags |= LOAD_ASYNC_REVALIDATION; | |
| 364 start_time_ = cache_->clock()->Now(); | |
| 365 // This use of base::Unretained is safe because |transaction_| is owned by | |
| 366 // this object. | |
| 367 read_callback_ = base::Bind(&AsyncValidation::OnRead, base::Unretained(this)); | |
| 368 // This use of base::Unretained is safe as above. | |
| 369 int rv = transaction_->Start( | |
| 370 &request_, | |
| 371 base::Bind(&AsyncValidation::OnStarted, base::Unretained(this)), | |
| 372 net_log); | |
| 373 | |
| 374 if (rv == ERR_IO_PENDING) | |
| 375 return; | |
| 376 | |
| 377 OnStarted(rv); | |
| 378 } | |
| 379 | |
| 380 void HttpCache::AsyncValidation::OnStarted(int result) { | |
| 381 if (result != OK) { | |
| 382 DVLOG(1) << "Asynchronous transaction start failed for " << request_.url; | |
| 383 Terminate(result); | |
| 384 return; | |
| 385 } | |
| 386 | |
| 387 while (transaction_->IsReadyToRestartForAuth()) { | |
| 388 // This code is based on URLRequestHttpJob::RestartTransactionWithAuth, | |
| 389 // however when we do this here cookies on the response will not be | |
| 390 // stored. Fortunately only a tiny number of sites set cookies on 401 | |
| 391 // responses, and none of them use stale-while-revalidate. | |
| 392 result = transaction_->RestartWithAuth( | |
| 393 AuthCredentials(), | |
| 394 base::Bind(&AsyncValidation::OnStarted, base::Unretained(this))); | |
| 395 if (result == ERR_IO_PENDING) | |
| 396 return; | |
| 397 if (result != OK) { | |
| 398 DVLOG(1) << "Synchronous transaction restart with auth failed for " | |
| 399 << request_.url; | |
| 400 Terminate(result); | |
| 401 return; | |
| 402 } | |
| 403 } | |
| 404 | |
| 405 DoRead(); | |
| 406 } | |
| 407 | |
| 408 void HttpCache::AsyncValidation::DoRead() { | |
| 409 const size_t kBufSize = 4096; | |
| 410 if (!buf_.get()) | |
| 411 buf_ = new IOBuffer(kBufSize); | |
| 412 | |
| 413 int rv = 0; | |
| 414 do { | |
| 415 rv = transaction_->Read(buf_.get(), kBufSize, read_callback_); | |
| 416 } while (rv > 0); | |
| 417 | |
| 418 if (rv == ERR_IO_PENDING) | |
| 419 return; | |
| 420 | |
| 421 OnRead(rv); | |
| 422 } | |
| 423 | |
| 424 void HttpCache::AsyncValidation::OnRead(int result) { | |
| 425 if (result > 0) { | |
| 426 DoRead(); | |
| 427 return; | |
| 428 } | |
| 429 Terminate(result); | |
| 430 } | |
| 431 | |
| 432 void HttpCache::AsyncValidation::Terminate(int result) { | |
| 433 if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED || IsCertificateError(result)) { | |
| 434 // We should not attempt to access this resource asynchronously again until | |
| 435 // the certificate problem has been resolved. | |
| 436 // TODO(ricea): For ERR_SSL_CLIENT_AUTH_CERT_NEEDED, mark the entry as | |
| 437 // requiring synchronous revalidation rather than just deleting it. Other | |
| 438 // certificate errors cause the resource to be considered uncacheable | |
| 439 // anyway. | |
| 440 cache_->DoomEntry(transaction_->key(), transaction_.get()); | |
| 441 } | |
| 442 base::TimeDelta duration = cache_->clock()->Now() - start_time_; | |
| 443 UMA_HISTOGRAM_TIMES("HttpCache.AsyncValidationDuration", duration); | |
| 444 transaction_->net_log().EndEventWithNetErrorCode( | |
| 445 NetLog::TYPE_ASYNC_REVALIDATION, result); | |
| 446 cache_->DeleteAsyncValidation(cache_->GenerateCacheKey(&request_)); | |
| 447 // |this| is deleted. | |
| 448 } | |
| 449 | |
| 450 //----------------------------------------------------------------------------- | |
| 451 HttpCache::HttpCache(const HttpNetworkSession::Params& params, | 297 HttpCache::HttpCache(const HttpNetworkSession::Params& params, |
| 452 BackendFactory* backend_factory) | 298 BackendFactory* backend_factory) |
| 453 : net_log_(params.net_log), | 299 : net_log_(params.net_log), |
| 454 backend_factory_(backend_factory), | 300 backend_factory_(backend_factory), |
| 455 building_backend_(false), | 301 building_backend_(false), |
| 456 bypass_lock_for_test_(false), | 302 bypass_lock_for_test_(false), |
| 457 fail_conditionalization_for_test_(false), | 303 fail_conditionalization_for_test_(false), |
| 458 use_stale_while_revalidate_(params.use_stale_while_revalidate), | |
| 459 mode_(NORMAL), | 304 mode_(NORMAL), |
| 460 network_layer_(new HttpNetworkLayer(new HttpNetworkSession(params))), | 305 network_layer_(new HttpNetworkLayer(new HttpNetworkSession(params))), |
| 461 clock_(new base::DefaultClock()), | 306 clock_(new base::DefaultClock()), |
| 462 weak_factory_(this) { | 307 weak_factory_(this) { |
| 463 SetupQuicServerInfoFactory(network_layer_->GetSession()); | 308 SetupQuicServerInfoFactory(network_layer_->GetSession()); |
| 464 } | 309 } |
| 465 | 310 |
| 466 | 311 |
| 467 // This call doesn't change the shared |session|'s QuicServerInfoFactory because | 312 // This call doesn't change the shared |session|'s QuicServerInfoFactory because |
| 468 // |session| is shared. | 313 // |session| is shared. |
| 469 HttpCache::HttpCache(HttpNetworkSession* session, | 314 HttpCache::HttpCache(HttpNetworkSession* session, |
| 470 BackendFactory* backend_factory) | 315 BackendFactory* backend_factory) |
| 471 : net_log_(session->net_log()), | 316 : net_log_(session->net_log()), |
| 472 backend_factory_(backend_factory), | 317 backend_factory_(backend_factory), |
| 473 building_backend_(false), | 318 building_backend_(false), |
| 474 bypass_lock_for_test_(false), | 319 bypass_lock_for_test_(false), |
| 475 fail_conditionalization_for_test_(false), | 320 fail_conditionalization_for_test_(false), |
| 476 use_stale_while_revalidate_(session->params().use_stale_while_revalidate), | |
| 477 mode_(NORMAL), | 321 mode_(NORMAL), |
| 478 network_layer_(new HttpNetworkLayer(session)), | 322 network_layer_(new HttpNetworkLayer(session)), |
| 479 clock_(new base::DefaultClock()), | 323 clock_(new base::DefaultClock()), |
| 480 weak_factory_(this) { | 324 weak_factory_(this) { |
| 481 } | 325 } |
| 482 | 326 |
| 483 HttpCache::HttpCache(HttpTransactionFactory* network_layer, | 327 HttpCache::HttpCache(HttpTransactionFactory* network_layer, |
| 484 NetLog* net_log, | 328 NetLog* net_log, |
| 485 BackendFactory* backend_factory) | 329 BackendFactory* backend_factory) |
| 486 : net_log_(net_log), | 330 : net_log_(net_log), |
| 487 backend_factory_(backend_factory), | 331 backend_factory_(backend_factory), |
| 488 building_backend_(false), | 332 building_backend_(false), |
| 489 bypass_lock_for_test_(false), | 333 bypass_lock_for_test_(false), |
| 490 fail_conditionalization_for_test_(false), | 334 fail_conditionalization_for_test_(false), |
| 491 use_stale_while_revalidate_(false), | |
| 492 mode_(NORMAL), | 335 mode_(NORMAL), |
| 493 network_layer_(network_layer), | 336 network_layer_(network_layer), |
| 494 clock_(new base::DefaultClock()), | 337 clock_(new base::DefaultClock()), |
| 495 weak_factory_(this) { | 338 weak_factory_(this) { |
| 496 SetupQuicServerInfoFactory(network_layer_->GetSession()); | 339 SetupQuicServerInfoFactory(network_layer_->GetSession()); |
| 497 HttpNetworkSession* session = network_layer_->GetSession(); | |
| 498 if (session) | |
| 499 use_stale_while_revalidate_ = session->params().use_stale_while_revalidate; | |
| 500 } | 340 } |
| 501 | 341 |
| 502 HttpCache::~HttpCache() { | 342 HttpCache::~HttpCache() { |
| 503 // Transactions should see an invalid cache after this point; otherwise they | 343 // Transactions should see an invalid cache after this point; otherwise they |
| 504 // could see an inconsistent object (half destroyed). | 344 // could see an inconsistent object (half destroyed). |
| 505 weak_factory_.InvalidateWeakPtrs(); | 345 weak_factory_.InvalidateWeakPtrs(); |
| 506 | 346 |
| 507 // If we have any active entries remaining, then we need to deactivate them. | 347 // If we have any active entries remaining, then we need to deactivate them. |
| 508 // We may have some pending calls to OnProcessPendingQueue, but since those | 348 // We may have some pending calls to OnProcessPendingQueue, but since those |
| 509 // won't run (due to our destruction), we can simply ignore the corresponding | 349 // won't run (due to our destruction), we can simply ignore the corresponding |
| 510 // will_process_pending_queue flag. | 350 // will_process_pending_queue flag. |
| 511 while (!active_entries_.empty()) { | 351 while (!active_entries_.empty()) { |
| 512 ActiveEntry* entry = active_entries_.begin()->second; | 352 ActiveEntry* entry = active_entries_.begin()->second; |
| 513 entry->will_process_pending_queue = false; | 353 entry->will_process_pending_queue = false; |
| 514 entry->pending_queue.clear(); | 354 entry->pending_queue.clear(); |
| 515 entry->readers.clear(); | 355 entry->readers.clear(); |
| 516 entry->writer = NULL; | 356 entry->writer = NULL; |
| 517 DeactivateEntry(entry); | 357 DeactivateEntry(entry); |
| 518 } | 358 } |
| 519 | 359 |
| 520 STLDeleteElements(&doomed_entries_); | 360 STLDeleteElements(&doomed_entries_); |
| 521 STLDeleteValues(&async_validations_); | |
| 522 | 361 |
| 523 // Before deleting pending_ops_, we have to make sure that the disk cache is | 362 // Before deleting pending_ops_, we have to make sure that the disk cache is |
| 524 // done with said operations, or it will attempt to use deleted data. | 363 // done with said operations, or it will attempt to use deleted data. |
| 525 cert_cache_.reset(); | 364 cert_cache_.reset(); |
| 526 disk_cache_.reset(); | 365 disk_cache_.reset(); |
| 527 | 366 |
| 528 PendingOpsMap::iterator pending_it = pending_ops_.begin(); | 367 PendingOpsMap::iterator pending_it = pending_ops_.begin(); |
| 529 for (; pending_it != pending_ops_.end(); ++pending_it) { | 368 for (; pending_it != pending_ops_.end(); ++pending_it) { |
| 530 // We are not notifying the transactions about the cache going away, even | 369 // We are not notifying the transactions about the cache going away, even |
| 531 // though they are waiting for a callback that will never fire. | 370 // though they are waiting for a callback that will never fire. |
| (...skipping 641 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1173 // not delete the entry before OnProcessPendingQueue runs. | 1012 // not delete the entry before OnProcessPendingQueue runs. |
| 1174 if (entry->will_process_pending_queue) | 1013 if (entry->will_process_pending_queue) |
| 1175 return; | 1014 return; |
| 1176 entry->will_process_pending_queue = true; | 1015 entry->will_process_pending_queue = true; |
| 1177 | 1016 |
| 1178 base::ThreadTaskRunnerHandle::Get()->PostTask( | 1017 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 1179 FROM_HERE, | 1018 FROM_HERE, |
| 1180 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry)); | 1019 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry)); |
| 1181 } | 1020 } |
| 1182 | 1021 |
| 1183 void HttpCache::PerformAsyncValidation(const HttpRequestInfo& original_request, | |
| 1184 const BoundNetLog& net_log) { | |
| 1185 DCHECK(use_stale_while_revalidate_); | |
| 1186 std::string key = GenerateCacheKey(&original_request); | |
| 1187 AsyncValidation* async_validation = | |
| 1188 new AsyncValidation(original_request, this); | |
| 1189 typedef AsyncValidationMap::value_type AsyncValidationKeyValue; | |
| 1190 bool insert_ok = | |
| 1191 async_validations_.insert(AsyncValidationKeyValue(key, async_validation)) | |
| 1192 .second; | |
| 1193 if (!insert_ok) { | |
| 1194 DVLOG(1) << "Harmless race condition detected on URL " | |
| 1195 << original_request.url << "; discarding redundant revalidation."; | |
| 1196 delete async_validation; | |
| 1197 return; | |
| 1198 } | |
| 1199 HttpNetworkSession* network_session = GetSession(); | |
| 1200 NetworkDelegate* network_delegate = NULL; | |
| 1201 if (network_session) | |
| 1202 network_delegate = network_session->network_delegate(); | |
| 1203 scoped_ptr<HttpTransaction> transaction; | |
| 1204 CreateTransaction(IDLE, &transaction); | |
| 1205 scoped_ptr<Transaction> downcast_transaction( | |
| 1206 static_cast<Transaction*>(transaction.release())); | |
| 1207 async_validation->Start( | |
| 1208 net_log, downcast_transaction.Pass(), network_delegate); | |
| 1209 // |async_validation| may have been deleted here. | |
| 1210 } | |
| 1211 | |
| 1212 void HttpCache::DeleteAsyncValidation(const std::string& url) { | |
| 1213 AsyncValidationMap::iterator it = async_validations_.find(url); | |
| 1214 CHECK(it != async_validations_.end()); // security-critical invariant | |
| 1215 AsyncValidation* async_validation = it->second; | |
| 1216 async_validations_.erase(it); | |
| 1217 delete async_validation; | |
| 1218 } | |
| 1219 | |
| 1220 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) { | 1022 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) { |
| 1221 entry->will_process_pending_queue = false; | 1023 entry->will_process_pending_queue = false; |
| 1222 DCHECK(!entry->writer); | 1024 DCHECK(!entry->writer); |
| 1223 | 1025 |
| 1224 // If no one is interested in this entry, then we can deactivate it. | 1026 // If no one is interested in this entry, then we can deactivate it. |
| 1225 if (entry->pending_queue.empty()) { | 1027 if (entry->pending_queue.empty()) { |
| 1226 if (entry->readers.empty()) | 1028 if (entry->readers.empty()) |
| 1227 DestroyEntry(entry); | 1029 DestroyEntry(entry); |
| 1228 return; | 1030 return; |
| 1229 } | 1031 } |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1379 building_backend_ = false; | 1181 building_backend_ = false; |
| 1380 DeletePendingOp(pending_op); | 1182 DeletePendingOp(pending_op); |
| 1381 } | 1183 } |
| 1382 | 1184 |
| 1383 // The cache may be gone when we return from the callback. | 1185 // The cache may be gone when we return from the callback. |
| 1384 if (!item->DoCallback(result, disk_cache_.get())) | 1186 if (!item->DoCallback(result, disk_cache_.get())) |
| 1385 item->NotifyTransaction(result, NULL); | 1187 item->NotifyTransaction(result, NULL); |
| 1386 } | 1188 } |
| 1387 | 1189 |
| 1388 } // namespace net | 1190 } // namespace net |
| OLD | NEW |