Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(455)

Side by Side Diff: content/browser/cache_storage/cache_storage_cache.cc

Issue 2085583002: [CacheStorage] Don't call GetUsageAndQuota from a scheduled operation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixes Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "content/browser/cache_storage/cache_storage_cache.h" 5 #include "content/browser/cache_storage/cache_storage_cache.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <string> 8 #include <string>
9 #include <utility> 9 #include <utility>
10 10
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 response(std::move(response)), 267 response(std::move(response)),
268 blob_data_handle(std::move(blob_data_handle)), 268 blob_data_handle(std::move(blob_data_handle)),
269 callback(callback) {} 269 callback(callback) {}
270 270
271 // Input parameters to the Put function. 271 // Input parameters to the Put function.
272 std::unique_ptr<ServiceWorkerFetchRequest> request; 272 std::unique_ptr<ServiceWorkerFetchRequest> request;
273 std::unique_ptr<ServiceWorkerResponse> response; 273 std::unique_ptr<ServiceWorkerResponse> response;
274 std::unique_ptr<storage::BlobDataHandle> blob_data_handle; 274 std::unique_ptr<storage::BlobDataHandle> blob_data_handle;
275 CacheStorageCache::ErrorCallback callback; 275 CacheStorageCache::ErrorCallback callback;
276 disk_cache::ScopedEntryPtr cache_entry; 276 disk_cache::ScopedEntryPtr cache_entry;
277 int64_t available_bytes = 0;
278 277
279 private: 278 private:
280 DISALLOW_COPY_AND_ASSIGN(PutContext); 279 DISALLOW_COPY_AND_ASSIGN(PutContext);
281 }; 280 };
282 281
283 // static 282 // static
284 scoped_refptr<CacheStorageCache> CacheStorageCache::CreateMemoryCache( 283 scoped_refptr<CacheStorageCache> CacheStorageCache::CreateMemoryCache(
285 const GURL& origin, 284 const GURL& origin,
286 const std::string& cache_name, 285 const std::string& cache_name,
287 scoped_refptr<net::URLRequestContextGetter> request_context_getter, 286 scoped_refptr<net::URLRequestContextGetter> request_context_getter,
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
351 weak_ptr_factory_.GetWeakPtr(), 350 weak_ptr_factory_.GetWeakPtr(),
352 base::Passed(std::move(context)))); 351 base::Passed(std::move(context))));
353 } 352 }
354 353
355 void CacheStorageCache::WriteSideData(const ErrorCallback& callback, 354 void CacheStorageCache::WriteSideData(const ErrorCallback& callback,
356 const GURL& url, 355 const GURL& url,
357 base::Time expected_response_time, 356 base::Time expected_response_time,
358 scoped_refptr<net::IOBuffer> buffer, 357 scoped_refptr<net::IOBuffer> buffer,
359 int buf_len) { 358 int buf_len) {
360 if (!LazyInitialize()) { 359 if (!LazyInitialize()) {
361 callback.Run(CACHE_STORAGE_ERROR_STORAGE); 360 base::ThreadTaskRunnerHandle::Get()->PostTask(
jsbell 2016/06/21 15:19:55 Necessary for this CL, or just to ensure consisten
jkarlin 2016/06/21 15:22:53 Just to return consistently. I need to go over the
361 FROM_HERE, base::Bind(callback, CACHE_STORAGE_ERROR_STORAGE));
362 return; 362 return;
363 } 363 }
364 ErrorCallback pending_callback =
365 base::Bind(&CacheStorageCache::PendingErrorCallback,
366 weak_ptr_factory_.GetWeakPtr(), callback);
367 364
368 scheduler_->ScheduleOperation(base::Bind( 365 // GetUsageAndQuota is called before entering a scheduled operation since it
369 &CacheStorageCache::WriteSideDataImpl, weak_ptr_factory_.GetWeakPtr(), 366 // can call Size, another scheduled operation.
370 pending_callback, url, expected_response_time, buffer, buf_len)); 367 quota_manager_proxy_->GetUsageAndQuota(
368 base::ThreadTaskRunnerHandle::Get().get(), origin_,
369 storage::kStorageTypeTemporary,
370 base::Bind(&CacheStorageCache::WriteSideDataDidGetQuota,
371 weak_ptr_factory_.GetWeakPtr(), callback, url,
372 expected_response_time, buffer, buf_len));
371 } 373 }
372 374
373 void CacheStorageCache::BatchOperation( 375 void CacheStorageCache::BatchOperation(
374 const std::vector<CacheStorageBatchOperation>& operations, 376 const std::vector<CacheStorageBatchOperation>& operations,
375 const ErrorCallback& callback) { 377 const ErrorCallback& callback) {
376 if (!LazyInitialize()) { 378 if (!LazyInitialize()) {
377 callback.Run(CACHE_STORAGE_ERROR_STORAGE); 379 base::ThreadTaskRunnerHandle::Get()->PostTask(
380 FROM_HERE, base::Bind(callback, CACHE_STORAGE_ERROR_STORAGE));
378 return; 381 return;
379 } 382 }
380 383
384 // Estimate the required size of the put operations. The size of the deletes
385 // is unknown and not considered.
386 int64_t space_required = 0;
387 for (const auto& operation : operations) {
388 if (operation.operation_type == CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT) {
389 space_required +=
390 operation.request.blob_size + operation.response.blob_size;
391 }
392 }
393 if (space_required > 0) {
394 // GetUsageAndQuota is called before entering a scheduled operation since it
395 // can call Size, another scheduled operation. This is racy. The decision
396 // to commit is made before the scheduled Put operation runs. By the time
397 // Put runs, the cache might already be full and the origin will be larger
398 // than it's supposed to be.
399 quota_manager_proxy_->GetUsageAndQuota(
400 base::ThreadTaskRunnerHandle::Get().get(), origin_,
401 storage::kStorageTypeTemporary,
402 base::Bind(&CacheStorageCache::BatchDidGetUsageAndQuota,
403 weak_ptr_factory_.GetWeakPtr(), operations, callback,
404 space_required));
405 return;
406 }
407
408 BatchDidGetUsageAndQuota(operations, callback, 0 /* space_required */,
409 storage::kQuotaStatusOk, 0 /* usage */,
410 0 /* quota */);
411 }
412
413 void CacheStorageCache::BatchDidGetUsageAndQuota(
414 const std::vector<CacheStorageBatchOperation>& operations,
415 const ErrorCallback& callback,
416 int64_t space_required,
417 storage::QuotaStatusCode status_code,
418 int64_t usage,
419 int64_t quota) {
420 if (status_code != storage::kQuotaStatusOk ||
421 space_required > quota - usage) {
422 base::ThreadTaskRunnerHandle::Get()->PostTask(
423 FROM_HERE, base::Bind(callback, CACHE_STORAGE_ERROR_QUOTA_EXCEEDED));
424 return;
425 }
426
381 std::unique_ptr<ErrorCallback> callback_copy(new ErrorCallback(callback)); 427 std::unique_ptr<ErrorCallback> callback_copy(new ErrorCallback(callback));
382 ErrorCallback* callback_ptr = callback_copy.get(); 428 ErrorCallback* callback_ptr = callback_copy.get();
383 base::Closure barrier_closure = base::BarrierClosure( 429 base::Closure barrier_closure = base::BarrierClosure(
384 operations.size(), 430 operations.size(),
385 base::Bind(&CacheStorageCache::BatchDidAllOperations, this, 431 base::Bind(&CacheStorageCache::BatchDidAllOperations, this,
386 base::Passed(std::move(callback_copy)))); 432 base::Passed(std::move(callback_copy))));
387 ErrorCallback completion_callback = 433 ErrorCallback completion_callback =
388 base::Bind(&CacheStorageCache::BatchDidOneOperation, this, 434 base::Bind(&CacheStorageCache::BatchDidOneOperation, this,
389 barrier_closure, callback_ptr); 435 barrier_closure, callback_ptr);
390 436
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
456 } 502 }
457 503
458 void CacheStorageCache::Size(const SizeCallback& callback) { 504 void CacheStorageCache::Size(const SizeCallback& callback) {
459 if (!LazyInitialize()) { 505 if (!LazyInitialize()) {
460 // TODO(jkarlin): Delete caches that can't be initialized. 506 // TODO(jkarlin): Delete caches that can't be initialized.
461 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 507 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
462 base::Bind(callback, 0)); 508 base::Bind(callback, 0));
463 return; 509 return;
464 } 510 }
465 511
466 if (initializing_) { 512 SizeCallback pending_callback =
467 // Note that Size doesn't use the scheduler, see header comments for why. 513 base::Bind(&CacheStorageCache::PendingSizeCallback,
468 pending_size_callbacks_.push_back(callback); 514 weak_ptr_factory_.GetWeakPtr(), callback);
469 return;
470 }
471 515
472 // Run immediately so that we don't deadlock on 516 scheduler_->ScheduleOperation(base::Bind(&CacheStorageCache::SizeImpl,
473 // CacheStorageCache::PutDidDelete's call to 517 weak_ptr_factory_.GetWeakPtr(),
474 // quota_manager_proxy_->GetUsageAndQuota. 518 pending_callback));
475 SizeImpl(callback);
476 } 519 }
477 520
478 void CacheStorageCache::GetSizeThenClose(const SizeCallback& callback) { 521 void CacheStorageCache::GetSizeThenClose(const SizeCallback& callback) {
479 if (!LazyInitialize()) { 522 if (!LazyInitialize()) {
480 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 523 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
481 base::Bind(callback, 0)); 524 base::Bind(callback, 0));
482 return; 525 return;
483 } 526 }
484 527
485 SizeCallback pending_callback = 528 SizeCallback pending_callback =
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after
769 } 812 }
770 813
771 std::unique_ptr<storage::BlobDataHandle> blob_data_handle = 814 std::unique_ptr<storage::BlobDataHandle> blob_data_handle =
772 PopulateResponseBody(std::move(entry), &response); 815 PopulateResponseBody(std::move(entry), &response);
773 816
774 context->out_responses->push_back(response); 817 context->out_responses->push_back(response);
775 context->out_blob_data_handles->push_back(*blob_data_handle); 818 context->out_blob_data_handles->push_back(*blob_data_handle);
776 MatchAllProcessNextEntry(std::move(context), iter + 1); 819 MatchAllProcessNextEntry(std::move(context), iter + 1);
777 } 820 }
778 821
822 void CacheStorageCache::WriteSideDataDidGetQuota(
823 const ErrorCallback& callback,
824 const GURL& url,
825 base::Time expected_response_time,
826 scoped_refptr<net::IOBuffer> buffer,
827 int buf_len,
828 storage::QuotaStatusCode status_code,
829 int64_t usage,
830 int64_t quota) {
831 if (status_code != storage::kQuotaStatusOk || (buf_len > quota - usage)) {
832 base::ThreadTaskRunnerHandle::Get()->PostTask(
833 FROM_HERE, base::Bind(callback, CACHE_STORAGE_ERROR_QUOTA_EXCEEDED));
834 return;
835 }
836
837 ErrorCallback pending_callback =
838 base::Bind(&CacheStorageCache::PendingErrorCallback,
839 weak_ptr_factory_.GetWeakPtr(), callback);
840
841 scheduler_->ScheduleOperation(base::Bind(
842 &CacheStorageCache::WriteSideDataImpl, weak_ptr_factory_.GetWeakPtr(),
843 pending_callback, url, expected_response_time, buffer, buf_len));
844 }
845
779 void CacheStorageCache::WriteSideDataImpl(const ErrorCallback& callback, 846 void CacheStorageCache::WriteSideDataImpl(const ErrorCallback& callback,
780 const GURL& url, 847 const GURL& url,
781 base::Time expected_response_time, 848 base::Time expected_response_time,
782 scoped_refptr<net::IOBuffer> buffer, 849 scoped_refptr<net::IOBuffer> buffer,
783 int buf_len) { 850 int buf_len) {
784 DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_); 851 DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_);
785 if (backend_state_ != BACKEND_OPEN) { 852 if (backend_state_ != BACKEND_OPEN) {
786 callback.Run(CACHE_STORAGE_ERROR_STORAGE); 853 callback.Run(CACHE_STORAGE_ERROR_STORAGE);
787 return; 854 return;
788 } 855 }
789 856
790 quota_manager_proxy_->GetUsageAndQuota(
791 base::ThreadTaskRunnerHandle::Get().get(), origin_,
792 storage::kStorageTypeTemporary,
793 base::Bind(&CacheStorageCache::WriteSideDataDidGetUsageAndQuota,
794 weak_ptr_factory_.GetWeakPtr(), callback, url,
795 expected_response_time, buffer, buf_len));
796 }
797
798 void CacheStorageCache::WriteSideDataDidGetUsageAndQuota(
799 const ErrorCallback& callback,
800 const GURL& url,
801 base::Time expected_response_time,
802 scoped_refptr<net::IOBuffer> buffer,
803 int buf_len,
804 storage::QuotaStatusCode status_code,
805 int64_t usage,
806 int64_t quota) {
807 if (status_code != storage::kQuotaStatusOk || quota - usage < buf_len) {
808 callback.Run(CACHE_STORAGE_ERROR_QUOTA_EXCEEDED);
809 return;
810 }
811 std::unique_ptr<disk_cache::Entry*> scoped_entry_ptr( 857 std::unique_ptr<disk_cache::Entry*> scoped_entry_ptr(
812 new disk_cache::Entry*()); 858 new disk_cache::Entry*());
813 disk_cache::Entry** entry_ptr = scoped_entry_ptr.get(); 859 disk_cache::Entry** entry_ptr = scoped_entry_ptr.get();
814 net::CompletionCallback open_entry_callback = base::Bind( 860 net::CompletionCallback open_entry_callback = base::Bind(
815 &CacheStorageCache::WriteSideDataDidOpenEntry, 861 &CacheStorageCache::WriteSideDataDidOpenEntry,
816 weak_ptr_factory_.GetWeakPtr(), callback, expected_response_time, buffer, 862 weak_ptr_factory_.GetWeakPtr(), callback, expected_response_time, buffer,
817 buf_len, base::Passed(std::move(scoped_entry_ptr))); 863 buf_len, base::Passed(std::move(scoped_entry_ptr)));
818 864
819 int rv = backend_->OpenEntry(url.spec(), entry_ptr, open_entry_callback); 865 int rv = backend_->OpenEntry(url.spec(), entry_ptr, open_entry_callback);
820 if (rv != net::ERR_IO_PENDING) 866 if (rv != net::ERR_IO_PENDING)
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
955 base::Passed(std::move(put_context)))); 1001 base::Passed(std::move(put_context))));
956 } 1002 }
957 1003
958 void CacheStorageCache::PutDidDelete(std::unique_ptr<PutContext> put_context, 1004 void CacheStorageCache::PutDidDelete(std::unique_ptr<PutContext> put_context,
959 CacheStorageError delete_error) { 1005 CacheStorageError delete_error) {
960 if (backend_state_ != BACKEND_OPEN) { 1006 if (backend_state_ != BACKEND_OPEN) {
961 put_context->callback.Run(CACHE_STORAGE_ERROR_STORAGE); 1007 put_context->callback.Run(CACHE_STORAGE_ERROR_STORAGE);
962 return; 1008 return;
963 } 1009 }
964 1010
965 quota_manager_proxy_->GetUsageAndQuota(
966 base::ThreadTaskRunnerHandle::Get().get(), origin_,
967 storage::kStorageTypeTemporary,
968 base::Bind(&CacheStorageCache::PutDidGetUsageAndQuota,
969 weak_ptr_factory_.GetWeakPtr(),
970 base::Passed(std::move(put_context))));
971 }
972
973 void CacheStorageCache::PutDidGetUsageAndQuota(
974 std::unique_ptr<PutContext> put_context,
975 storage::QuotaStatusCode status_code,
976 int64_t usage,
977 int64_t quota) {
978 if (backend_state_ != BACKEND_OPEN) {
979 put_context->callback.Run(CACHE_STORAGE_ERROR_STORAGE);
980 return;
981 }
982
983 if (status_code != storage::kQuotaStatusOk) {
984 put_context->callback.Run(CACHE_STORAGE_ERROR_QUOTA_EXCEEDED);
985 return;
986 }
987
988 put_context->available_bytes = quota - usage;
989
990 std::unique_ptr<disk_cache::Entry*> scoped_entry_ptr( 1011 std::unique_ptr<disk_cache::Entry*> scoped_entry_ptr(
991 new disk_cache::Entry*()); 1012 new disk_cache::Entry*());
992 disk_cache::Entry** entry_ptr = scoped_entry_ptr.get(); 1013 disk_cache::Entry** entry_ptr = scoped_entry_ptr.get();
993 ServiceWorkerFetchRequest* request_ptr = put_context->request.get(); 1014 ServiceWorkerFetchRequest* request_ptr = put_context->request.get();
994 disk_cache::Backend* backend_ptr = backend_.get(); 1015 disk_cache::Backend* backend_ptr = backend_.get();
995 1016
996 net::CompletionCallback create_entry_callback = base::Bind( 1017 net::CompletionCallback create_entry_callback = base::Bind(
997 &CacheStorageCache::PutDidCreateEntry, weak_ptr_factory_.GetWeakPtr(), 1018 &CacheStorageCache::PutDidCreateEntry, weak_ptr_factory_.GetWeakPtr(),
998 base::Passed(std::move(scoped_entry_ptr)), 1019 base::Passed(std::move(scoped_entry_ptr)),
999 base::Passed(std::move(put_context))); 1020 base::Passed(std::move(put_context)));
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
1051 1072
1052 std::unique_ptr<std::string> serialized(new std::string()); 1073 std::unique_ptr<std::string> serialized(new std::string());
1053 if (!metadata.SerializeToString(serialized.get())) { 1074 if (!metadata.SerializeToString(serialized.get())) {
1054 put_context->callback.Run(CACHE_STORAGE_ERROR_STORAGE); 1075 put_context->callback.Run(CACHE_STORAGE_ERROR_STORAGE);
1055 return; 1076 return;
1056 } 1077 }
1057 1078
1058 scoped_refptr<net::StringIOBuffer> buffer( 1079 scoped_refptr<net::StringIOBuffer> buffer(
1059 new net::StringIOBuffer(std::move(serialized))); 1080 new net::StringIOBuffer(std::move(serialized)));
1060 1081
1061 int64_t bytes_to_write = buffer->size() + put_context->response->blob_size;
1062 if (put_context->available_bytes < bytes_to_write) {
1063 put_context->callback.Run(CACHE_STORAGE_ERROR_QUOTA_EXCEEDED);
1064 return;
1065 }
1066
1067 // Get a temporary copy of the entry pointer before passing it in base::Bind. 1082 // Get a temporary copy of the entry pointer before passing it in base::Bind.
1068 disk_cache::Entry* temp_entry_ptr = put_context->cache_entry.get(); 1083 disk_cache::Entry* temp_entry_ptr = put_context->cache_entry.get();
1069 1084
1070 net::CompletionCallback write_headers_callback = base::Bind( 1085 net::CompletionCallback write_headers_callback = base::Bind(
1071 &CacheStorageCache::PutDidWriteHeaders, weak_ptr_factory_.GetWeakPtr(), 1086 &CacheStorageCache::PutDidWriteHeaders, weak_ptr_factory_.GetWeakPtr(),
1072 base::Passed(std::move(put_context)), buffer->size()); 1087 base::Passed(std::move(put_context)), buffer->size());
1073 1088
1074 rv = temp_entry_ptr->WriteData(INDEX_HEADERS, 0 /* offset */, buffer.get(), 1089 rv = temp_entry_ptr->WriteData(INDEX_HEADERS, 0 /* offset */, buffer.get(),
1075 buffer->size(), write_headers_callback, 1090 buffer->size(), write_headers_callback,
1076 true /* truncate */); 1091 true /* truncate */);
(...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after
1432 1447
1433 void CacheStorageCache::InitGotCacheSize(CacheStorageError cache_create_error, 1448 void CacheStorageCache::InitGotCacheSize(CacheStorageError cache_create_error,
1434 int cache_size) { 1449 int cache_size) {
1435 cache_size_ = cache_size; 1450 cache_size_ = cache_size;
1436 initializing_ = false; 1451 initializing_ = false;
1437 backend_state_ = (cache_create_error == CACHE_STORAGE_OK && backend_ && 1452 backend_state_ = (cache_create_error == CACHE_STORAGE_OK && backend_ &&
1438 backend_state_ == BACKEND_UNINITIALIZED) 1453 backend_state_ == BACKEND_UNINITIALIZED)
1439 ? BACKEND_OPEN 1454 ? BACKEND_OPEN
1440 : BACKEND_CLOSED; 1455 : BACKEND_CLOSED;
1441 1456
1442 for (const SizeCallback& callback : pending_size_callbacks_)
1443 SizeImpl(callback);
1444 pending_size_callbacks_.clear();
1445
1446 UMA_HISTOGRAM_ENUMERATION("ServiceWorkerCache.InitBackendResult", 1457 UMA_HISTOGRAM_ENUMERATION("ServiceWorkerCache.InitBackendResult",
1447 cache_create_error, CACHE_STORAGE_ERROR_LAST + 1); 1458 cache_create_error, CACHE_STORAGE_ERROR_LAST + 1);
1448 1459
1449 scheduler_->CompleteOperationAndRunNext(); 1460 scheduler_->CompleteOperationAndRunNext();
1450 } 1461 }
1451 1462
1452 void CacheStorageCache::PendingClosure(const base::Closure& callback) { 1463 void CacheStorageCache::PendingClosure(const base::Closure& callback) {
1453 base::WeakPtr<CacheStorageCache> cache = weak_ptr_factory_.GetWeakPtr(); 1464 base::WeakPtr<CacheStorageCache> cache = weak_ptr_factory_.GetWeakPtr();
1454 1465
1455 callback.Run(); 1466 callback.Run();
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
1544 storage::BlobDataBuilder blob_data(response->blob_uuid); 1555 storage::BlobDataBuilder blob_data(response->blob_uuid);
1545 1556
1546 disk_cache::Entry* temp_entry = entry.get(); 1557 disk_cache::Entry* temp_entry = entry.get();
1547 blob_data.AppendDiskCacheEntryWithSideData( 1558 blob_data.AppendDiskCacheEntryWithSideData(
1548 new CacheStorageCacheDataHandle(this, std::move(entry)), temp_entry, 1559 new CacheStorageCacheDataHandle(this, std::move(entry)), temp_entry,
1549 INDEX_RESPONSE_BODY, INDEX_SIDE_DATA); 1560 INDEX_RESPONSE_BODY, INDEX_SIDE_DATA);
1550 return blob_storage_context_->AddFinishedBlob(&blob_data); 1561 return blob_storage_context_->AddFinishedBlob(&blob_data);
1551 } 1562 }
1552 1563
1553 } // namespace content 1564 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/cache_storage/cache_storage_cache.h ('k') | content/browser/cache_storage/cache_storage_cache_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698