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 |
| 11 #if defined(OS_POSIX) | 11 #if defined(OS_POSIX) |
| 12 #include <unistd.h> | 12 #include <unistd.h> |
| 13 #endif | 13 #endif |
| 14 | 14 |
| 15 #include "base/bind.h" | 15 #include "base/bind.h" |
| 16 #include "base/bind_helpers.h" | 16 #include "base/bind_helpers.h" |
| 17 #include "base/callback.h" | 17 #include "base/callback.h" |
| 18 #include "base/file_util.h" | 18 #include "base/file_util.h" |
| 19 #include "base/format_macros.h" | 19 #include "base/format_macros.h" |
| 20 #include "base/location.h" | 20 #include "base/location.h" |
| 21 #include "base/memory/ref_counted.h" | 21 #include "base/memory/ref_counted.h" |
| 22 #include "base/message_loop/message_loop.h" | 22 #include "base/message_loop/message_loop.h" |
| 23 #include "base/metrics/field_trial.h" | 23 #include "base/metrics/field_trial.h" |
| 24 #include "base/metrics/histogram.h" | |
| 24 #include "base/pickle.h" | 25 #include "base/pickle.h" |
| 25 #include "base/stl_util.h" | 26 #include "base/stl_util.h" |
| 26 #include "base/strings/string_number_conversions.h" | 27 #include "base/strings/string_number_conversions.h" |
| 27 #include "base/strings/string_util.h" | 28 #include "base/strings/string_util.h" |
| 28 #include "base/strings/stringprintf.h" | 29 #include "base/strings/stringprintf.h" |
| 29 #include "base/threading/worker_pool.h" | 30 #include "base/threading/worker_pool.h" |
| 31 #include "base/time/time.h" | |
| 30 #include "net/base/cache_type.h" | 32 #include "net/base/cache_type.h" |
| 31 #include "net/base/io_buffer.h" | 33 #include "net/base/io_buffer.h" |
| 32 #include "net/base/load_flags.h" | 34 #include "net/base/load_flags.h" |
| 33 #include "net/base/net_errors.h" | 35 #include "net/base/net_errors.h" |
| 36 #include "net/base/network_delegate.h" | |
| 34 #include "net/base/upload_data_stream.h" | 37 #include "net/base/upload_data_stream.h" |
| 35 #include "net/disk_cache/disk_cache.h" | 38 #include "net/disk_cache/disk_cache.h" |
| 36 #include "net/http/disk_based_cert_cache.h" | 39 #include "net/http/disk_based_cert_cache.h" |
| 37 #include "net/http/disk_cache_based_quic_server_info.h" | 40 #include "net/http/disk_cache_based_quic_server_info.h" |
| 38 #include "net/http/http_cache_transaction.h" | 41 #include "net/http/http_cache_transaction.h" |
| 39 #include "net/http/http_network_layer.h" | 42 #include "net/http/http_network_layer.h" |
| 40 #include "net/http/http_network_session.h" | 43 #include "net/http/http_network_session.h" |
| 41 #include "net/http/http_request_info.h" | 44 #include "net/http/http_request_info.h" |
| 42 #include "net/http/http_response_headers.h" | 45 #include "net/http/http_response_headers.h" |
| 43 #include "net/http/http_response_info.h" | 46 #include "net/http/http_response_info.h" |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 285 virtual QuicServerInfo* GetForServer( | 288 virtual QuicServerInfo* GetForServer( |
| 286 const QuicServerId& server_id) OVERRIDE { | 289 const QuicServerId& server_id) OVERRIDE { |
| 287 return new DiskCacheBasedQuicServerInfo(server_id, http_cache_); | 290 return new DiskCacheBasedQuicServerInfo(server_id, http_cache_); |
| 288 } | 291 } |
| 289 | 292 |
| 290 private: | 293 private: |
| 291 HttpCache* const http_cache_; | 294 HttpCache* const http_cache_; |
| 292 }; | 295 }; |
| 293 | 296 |
| 294 //----------------------------------------------------------------------------- | 297 //----------------------------------------------------------------------------- |
| 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, NetworkDelegate* network_delegate); | |
| 306 | |
| 307 private: | |
| 308 void OnStarted(int result); | |
| 309 void DoRead(); | |
| 310 void OnRead(int result); | |
| 311 | |
| 312 // Terminate this request with net error code |result|. Logs the transaction | |
| 313 // result and asks HttpCache to delete this object. | |
| 314 // If there was a client or server certificate error, it cannot be recovered | |
| 315 // asynchronously, so we need to prevent futures attempts to asynchronously | |
| 316 // fetch the resource. In this case, the cache entry is doomed. | |
| 317 void Terminate(int result); | |
| 318 | |
| 319 HttpRequestInfo request_; | |
| 320 scoped_refptr<IOBuffer> buf_; | |
| 321 CompletionCallback read_callback_; | |
| 322 scoped_ptr<Transaction> transaction_; | |
| 323 base::Time start_time_; | |
| 324 | |
| 325 // The HttpCache object owns this object. This object is always deleted before | |
| 326 // the pointer to the cache becomes invalid. | |
| 327 HttpCache* cache_; | |
| 328 | |
| 329 DISALLOW_COPY_AND_ASSIGN(AsyncValidation); | |
| 330 }; | |
| 331 | |
| 332 void HttpCache::AsyncValidation::Start(const BoundNetLog& net_log, | |
| 333 NetworkDelegate* network_delegate) { | |
| 334 transaction_.reset(new Transaction(IDLE, cache_)); | |
|
rvargas (doing something else)
2014/08/29 23:36:06
It's better to keep transaction creation centraliz
Adam Rice
2014/09/01 14:42:59
Done.
| |
| 335 if (network_delegate) { | |
| 336 // This code is necessary to enable async transactions to pass over the | |
| 337 // data-reduction proxy. This is a violation of the "once-and-only-once" | |
| 338 // principle, since it copies code from URLRequestHttpJob. We cannot use the | |
| 339 // original callback passed to HttpCache::Transaction by URLRequestHttpJob | |
| 340 // as it will only be valid as long as the URLRequestHttpJob object is | |
| 341 // alive, and that object will be deleted as soon as the synchronous request | |
| 342 // completes. | |
| 343 // | |
| 344 // This code is also an encapsulation violation. We are exploiting the fact | |
| 345 // that the |request| parameter to NotifyBeforeSendProxyHeaders() is never | |
| 346 // actually used for anything, and so can be NULL. | |
| 347 // | |
| 348 // TODO(ricea): Do this better. | |
| 349 transaction_->SetBeforeProxyHeadersSentCallback( | |
| 350 base::Bind(&NetworkDelegate::NotifyBeforeSendProxyHeaders, | |
| 351 base::Unretained(network_delegate), | |
| 352 static_cast<URLRequest*>(NULL))); | |
| 353 // The above use of base::Unretained is safe because the NetworkDelegate has | |
| 354 // to live at least as long as the HttpNetworkSession which has to live as | |
| 355 // least as long as the HttpNetworkLayer which has to live at least as long | |
| 356 // this HttpCache object. | |
| 357 } | |
| 358 | |
| 359 transaction_->ValidateInternalCache(); | |
|
rvargas (doing something else)
2014/08/29 23:36:06
This looks out of the blue
I just found the menti
Adam Rice
2014/09/01 14:43:00
I originally was using load flags, but it made me
rvargas (doing something else)
2014/09/03 01:25:53
I think it is interesting to bring this up. Basica
Adam Rice
2014/09/05 15:17:11
Okay, I have added LOAD_ASYNC_REVALIDATION and rem
| |
| 360 start_time_ = base::Time::Now(); | |
| 361 // This use of base::Unretained is safe because |transaction_| is owned by | |
| 362 // this object. | |
| 363 read_callback_ = base::Bind(&AsyncValidation::OnRead, base::Unretained(this)); | |
| 364 // This use of base::Unretained is safe as above. | |
| 365 int rv = transaction_->Start( | |
| 366 &request_, | |
| 367 base::Bind(&AsyncValidation::OnStarted, base::Unretained(this)), | |
| 368 net_log); | |
| 369 | |
| 370 if (rv == ERR_IO_PENDING) | |
| 371 return; | |
| 372 | |
| 373 OnStarted(rv); | |
| 374 } | |
| 375 | |
| 376 void HttpCache::AsyncValidation::OnStarted(int result) { | |
| 377 if (result != OK) { | |
| 378 DVLOG(1) << "Asynchronous transaction start failed for " << request_.url; | |
| 379 Terminate(result); | |
| 380 return; | |
| 381 } | |
| 382 | |
| 383 DoRead(); | |
| 384 } | |
| 385 | |
| 386 void HttpCache::AsyncValidation::DoRead() { | |
| 387 const size_t kBufSize = 4096; | |
| 388 if (!buf_) | |
| 389 buf_ = new IOBuffer(kBufSize); | |
| 390 | |
| 391 int rv = 0; | |
| 392 do { | |
| 393 rv = transaction_->Read(buf_.get(), kBufSize, read_callback_); | |
| 394 } while (rv > 0); | |
| 395 | |
| 396 if (rv == ERR_IO_PENDING) | |
| 397 return; | |
| 398 | |
| 399 OnRead(rv); | |
| 400 } | |
| 401 | |
| 402 void HttpCache::AsyncValidation::OnRead(int result) { | |
| 403 if (result > 0) { | |
| 404 DoRead(); | |
| 405 return; | |
| 406 } | |
| 407 Terminate(result); | |
| 408 } | |
| 409 | |
| 410 void HttpCache::AsyncValidation::Terminate(int result) { | |
| 411 if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED || IsCertificateError(result)) | |
| 412 cache_->DoomEntry(transaction_->key(), transaction_.get()); | |
|
rvargas (doing something else)
2014/08/29 23:36:06
why? Looks like a problem with this code, not with
Adam Rice
2014/09/01 14:43:00
Consider the case where the remote server suddenly
rvargas (doing something else)
2014/09/03 01:25:53
We don't have to pop up an auth dialog for every r
Adam Rice
2014/09/05 15:17:11
For the final design, I'm thinking of something li
rvargas (doing something else)
2014/09/05 22:52:39
My suggestion for the final design would be that t
Adam Rice
2014/09/09 12:36:45
The fact that another asynchronous validation shou
| |
| 413 base::TimeDelta time_saved = base::Time::Now() - start_time_; | |
| 414 UMA_HISTOGRAM_TIMES("HttpCache.AsyncValidationTimeSaved", time_saved); | |
|
rvargas (doing something else)
2014/08/29 23:36:06
What is this measuring? This cannot be accounted a
Adam Rice
2014/09/01 14:43:00
Sadly, no.
I was thinking of splitting it into tw
rvargas (doing something else)
2014/09/03 01:25:53
I'm fine with it as long as we don't use as a metr
Adam Rice
2014/09/05 15:17:11
I renamed it AsyncValidationDuration to avoid misu
| |
| 415 transaction_->net_log().EndEventWithNetErrorCode( | |
| 416 NetLog::TYPE_ASYNC_REVALIDATION, result); | |
| 417 cache_->DeleteAsyncValidation(this); | |
| 418 // |this| is deleted. | |
| 419 } | |
| 420 | |
| 421 //----------------------------------------------------------------------------- | |
| 295 HttpCache::HttpCache(const net::HttpNetworkSession::Params& params, | 422 HttpCache::HttpCache(const net::HttpNetworkSession::Params& params, |
| 296 BackendFactory* backend_factory) | 423 BackendFactory* backend_factory) |
| 297 : net_log_(params.net_log), | 424 : net_log_(params.net_log), |
| 298 backend_factory_(backend_factory), | 425 backend_factory_(backend_factory), |
| 299 building_backend_(false), | 426 building_backend_(false), |
| 300 bypass_lock_for_test_(false), | 427 bypass_lock_for_test_(false), |
| 428 use_stale_while_revalidate_(params.use_stale_while_revalidate), | |
| 301 mode_(NORMAL), | 429 mode_(NORMAL), |
| 302 network_layer_(new HttpNetworkLayer(new HttpNetworkSession(params))), | 430 network_layer_(new HttpNetworkLayer(new HttpNetworkSession(params))), |
| 303 weak_factory_(this) { | 431 weak_factory_(this) { |
| 304 SetupQuicServerInfoFactory(network_layer_->GetSession()); | 432 SetupQuicServerInfoFactory(network_layer_->GetSession()); |
| 305 } | 433 } |
| 306 | 434 |
| 307 | 435 |
| 308 // This call doesn't change the shared |session|'s QuicServerInfoFactory because | 436 // This call doesn't change the shared |session|'s QuicServerInfoFactory because |
| 309 // |session| is shared. | 437 // |session| is shared. |
| 310 HttpCache::HttpCache(HttpNetworkSession* session, | 438 HttpCache::HttpCache(HttpNetworkSession* session, |
| 311 BackendFactory* backend_factory) | 439 BackendFactory* backend_factory) |
| 312 : net_log_(session->net_log()), | 440 : net_log_(session->net_log()), |
| 313 backend_factory_(backend_factory), | 441 backend_factory_(backend_factory), |
| 314 building_backend_(false), | 442 building_backend_(false), |
| 315 bypass_lock_for_test_(false), | 443 bypass_lock_for_test_(false), |
| 444 use_stale_while_revalidate_(session->params().use_stale_while_revalidate), | |
| 316 mode_(NORMAL), | 445 mode_(NORMAL), |
| 317 network_layer_(new HttpNetworkLayer(session)), | 446 network_layer_(new HttpNetworkLayer(session)), |
| 318 weak_factory_(this) { | 447 weak_factory_(this) { |
| 319 } | 448 } |
| 320 | 449 |
| 321 HttpCache::HttpCache(HttpTransactionFactory* network_layer, | 450 HttpCache::HttpCache(HttpTransactionFactory* network_layer, |
| 322 NetLog* net_log, | 451 NetLog* net_log, |
| 323 BackendFactory* backend_factory) | 452 BackendFactory* backend_factory) |
| 324 : net_log_(net_log), | 453 : net_log_(net_log), |
| 325 backend_factory_(backend_factory), | 454 backend_factory_(backend_factory), |
| 326 building_backend_(false), | 455 building_backend_(false), |
| 327 bypass_lock_for_test_(false), | 456 bypass_lock_for_test_(false), |
| 457 use_stale_while_revalidate_(false), | |
| 328 mode_(NORMAL), | 458 mode_(NORMAL), |
| 329 network_layer_(network_layer), | 459 network_layer_(network_layer), |
| 330 weak_factory_(this) { | 460 weak_factory_(this) { |
| 331 SetupQuicServerInfoFactory(network_layer_->GetSession()); | 461 SetupQuicServerInfoFactory(network_layer_->GetSession()); |
| 462 HttpNetworkSession* session = network_layer_->GetSession(); | |
| 463 if (session) | |
| 464 use_stale_while_revalidate_ = session->params().use_stale_while_revalidate; | |
| 332 } | 465 } |
| 333 | 466 |
| 334 HttpCache::~HttpCache() { | 467 HttpCache::~HttpCache() { |
| 335 // Transactions should see an invalid cache after this point; otherwise they | 468 // Transactions should see an invalid cache after this point; otherwise they |
| 336 // could see an inconsistent object (half destroyed). | 469 // could see an inconsistent object (half destroyed). |
| 337 weak_factory_.InvalidateWeakPtrs(); | 470 weak_factory_.InvalidateWeakPtrs(); |
| 338 | 471 |
| 339 // If we have any active entries remaining, then we need to deactivate them. | 472 // 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 | 473 // 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 | 474 // won't run (due to our destruction), we can simply ignore the corresponding |
| 342 // will_process_pending_queue flag. | 475 // will_process_pending_queue flag. |
| 343 while (!active_entries_.empty()) { | 476 while (!active_entries_.empty()) { |
| 344 ActiveEntry* entry = active_entries_.begin()->second; | 477 ActiveEntry* entry = active_entries_.begin()->second; |
| 345 entry->will_process_pending_queue = false; | 478 entry->will_process_pending_queue = false; |
| 346 entry->pending_queue.clear(); | 479 entry->pending_queue.clear(); |
| 347 entry->readers.clear(); | 480 entry->readers.clear(); |
| 348 entry->writer = NULL; | 481 entry->writer = NULL; |
| 349 DeactivateEntry(entry); | 482 DeactivateEntry(entry); |
| 350 } | 483 } |
| 351 | 484 |
| 352 STLDeleteElements(&doomed_entries_); | 485 STLDeleteElements(&doomed_entries_); |
| 486 STLDeleteElements(&async_validations_); | |
| 353 | 487 |
| 354 // Before deleting pending_ops_, we have to make sure that the disk cache is | 488 // 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. | 489 // done with said operations, or it will attempt to use deleted data. |
| 356 cert_cache_.reset(); | 490 cert_cache_.reset(); |
| 357 disk_cache_.reset(); | 491 disk_cache_.reset(); |
| 358 | 492 |
| 359 PendingOpsMap::iterator pending_it = pending_ops_.begin(); | 493 PendingOpsMap::iterator pending_it = pending_ops_.begin(); |
| 360 for (; pending_it != pending_ops_.end(); ++pending_it) { | 494 for (; pending_it != pending_ops_.end(); ++pending_it) { |
| 361 // We are not notifying the transactions about the cache going away, even | 495 // We are not notifying the transactions about the cache going away, even |
| 362 // though they are waiting for a callback that will never fire. | 496 // 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. | 1165 // not delete the entry before OnProcessPendingQueue runs. |
| 1032 if (entry->will_process_pending_queue) | 1166 if (entry->will_process_pending_queue) |
| 1033 return; | 1167 return; |
| 1034 entry->will_process_pending_queue = true; | 1168 entry->will_process_pending_queue = true; |
| 1035 | 1169 |
| 1036 base::MessageLoop::current()->PostTask( | 1170 base::MessageLoop::current()->PostTask( |
| 1037 FROM_HERE, | 1171 FROM_HERE, |
| 1038 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry)); | 1172 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry)); |
| 1039 } | 1173 } |
| 1040 | 1174 |
| 1175 void HttpCache::PerformAsyncValidation(const HttpRequestInfo& original_request, | |
| 1176 const BoundNetLog& net_log) { | |
| 1177 DCHECK(use_stale_while_revalidate_); | |
| 1178 AsyncValidation* job = new AsyncValidation(original_request, this); | |
| 1179 bool insert_ok = async_validations_.insert(job).second; | |
| 1180 DCHECK(insert_ok); | |
|
rvargas (doing something else)
2014/08/29 23:36:06
why can't this fail?
Adam Rice
2014/09/01 14:43:00
It is matched with the erase() in DeleteAsyncValid
rvargas (doing something else)
2014/09/03 01:25:52
But we should not be performing two async validati
Adam Rice
2014/09/05 15:17:11
It might be possible to get multiple AsyncValidati
rvargas (doing something else)
2014/09/05 22:52:39
Sorry I was not clear. Yes, things will be queued
Adam Rice
2014/09/09 12:36:45
Done.
| |
| 1181 HttpNetworkSession* network_session = GetSession(); | |
| 1182 NetworkDelegate* network_delegate = NULL; | |
| 1183 if (network_session) | |
| 1184 network_delegate = network_session->network_delegate(); | |
| 1185 job->Start(net_log, network_delegate); | |
|
rvargas (doing something else)
2014/08/29 23:36:06
AsyncValidation is not a UrlRequest::Job so it's b
Adam Rice
2014/09/01 14:43:00
Done.
| |
| 1186 // |job| may have been deleted here. | |
| 1187 } | |
| 1188 | |
| 1189 void HttpCache::DeleteAsyncValidation(AsyncValidation* async_validation) { | |
| 1190 size_t erased = async_validations_.erase(async_validation); | |
| 1191 DCHECK_EQ(1U, erased); | |
| 1192 delete async_validation; | |
| 1193 } | |
| 1194 | |
| 1041 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) { | 1195 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) { |
| 1042 entry->will_process_pending_queue = false; | 1196 entry->will_process_pending_queue = false; |
| 1043 DCHECK(!entry->writer); | 1197 DCHECK(!entry->writer); |
| 1044 | 1198 |
| 1045 // If no one is interested in this entry, then we can deactivate it. | 1199 // If no one is interested in this entry, then we can deactivate it. |
| 1046 if (entry->pending_queue.empty()) { | 1200 if (entry->pending_queue.empty()) { |
| 1047 if (entry->readers.empty()) | 1201 if (entry->readers.empty()) |
| 1048 DestroyEntry(entry); | 1202 DestroyEntry(entry); |
| 1049 return; | 1203 return; |
| 1050 } | 1204 } |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1201 building_backend_ = false; | 1355 building_backend_ = false; |
| 1202 DeletePendingOp(pending_op); | 1356 DeletePendingOp(pending_op); |
| 1203 } | 1357 } |
| 1204 | 1358 |
| 1205 // The cache may be gone when we return from the callback. | 1359 // The cache may be gone when we return from the callback. |
| 1206 if (!item->DoCallback(result, disk_cache_.get())) | 1360 if (!item->DoCallback(result, disk_cache_.get())) |
| 1207 item->NotifyTransaction(result, NULL); | 1361 item->NotifyTransaction(result, NULL); |
| 1208 } | 1362 } |
| 1209 | 1363 |
| 1210 } // namespace net | 1364 } // namespace net |
| OLD | NEW |