| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/http/mock_http_cache.h" |
| |
| #include <algorithm> |
| #include <limits> |
| #include <memory> |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/callback_helpers.h" |
| #include "base/location.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "net/base/net_errors.h" |
| #include "net/http/http_cache_writers.h" |
| #include "starboard/memory.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace net { |
| |
| namespace { |
| |
| // During testing, we are going to limit the size of a cache entry to this many |
| // bytes using DCHECKs in order to prevent a test from causing unbounded memory |
| // growth. In practice cache entry shouldn't come anywhere near this limit for |
| // tests that use the mock cache. If they do, that's likely a problem with the |
| // test. If a test requires using massive cache entries, they should use a real |
| // cache backend instead. |
| const int kMaxMockCacheEntrySize = 100 * 1000 * 1000; |
| |
| // We can override the test mode for a given operation by setting this global |
| // variable. |
| int g_test_mode = 0; |
| |
| int GetTestModeForEntry(const std::string& key) { |
| // 'key' is prefixed with an identifier if it corresponds to a cached POST. |
| // Skip past that to locate the actual URL. |
| // |
| // TODO(darin): It breaks the abstraction a bit that we assume 'key' is an |
| // URL corresponding to a registered MockTransaction. It would be good to |
| // have another way to access the test_mode. |
| GURL url; |
| if (isdigit(key[0])) { |
| size_t slash = key.find('/'); |
| DCHECK(slash != std::string::npos); |
| url = GURL(key.substr(slash + 1)); |
| } else { |
| url = GURL(key); |
| } |
| const MockTransaction* t = FindMockTransaction(url); |
| DCHECK(t); |
| return t->test_mode; |
| } |
| |
| } // namespace |
| |
| //----------------------------------------------------------------------------- |
| |
| struct MockDiskEntry::CallbackInfo { |
| scoped_refptr<MockDiskEntry> entry; |
| net::CompletionOnceCallback callback; |
| int result; |
| }; |
| |
| MockDiskEntry::MockDiskEntry(const std::string& key) |
| : key_(key), |
| in_memory_data_(0), |
| doomed_(false), |
| sparse_(false), |
| fail_requests_(false), |
| fail_sparse_requests_(false), |
| busy_(false), |
| delayed_(false), |
| cancel_(false), |
| defer_op_(DEFER_NONE), |
| resume_return_code_(0) { |
| test_mode_ = GetTestModeForEntry(key); |
| } |
| |
| void MockDiskEntry::Doom() { |
| doomed_ = true; |
| } |
| |
| void MockDiskEntry::Close() { |
| Release(); |
| } |
| |
| std::string MockDiskEntry::GetKey() const { |
| return key_; |
| } |
| |
| base::Time MockDiskEntry::GetLastUsed() const { |
| return base::Time::Now(); |
| } |
| |
| base::Time MockDiskEntry::GetLastModified() const { |
| return base::Time::Now(); |
| } |
| |
| int32_t MockDiskEntry::GetDataSize(int index) const { |
| DCHECK(index >= 0 && index < kNumCacheEntryDataIndices); |
| return static_cast<int32_t>(data_[index].size()); |
| } |
| |
| int MockDiskEntry::ReadData(int index, |
| int offset, |
| IOBuffer* buf, |
| int buf_len, |
| CompletionOnceCallback callback) { |
| DCHECK(index >= 0 && index < kNumCacheEntryDataIndices); |
| DCHECK(!callback.is_null()); |
| |
| if (fail_requests_) |
| return ERR_CACHE_READ_FAILURE; |
| |
| if (offset < 0 || offset > static_cast<int>(data_[index].size())) |
| return ERR_FAILED; |
| if (static_cast<size_t>(offset) == data_[index].size()) |
| return 0; |
| |
| int num = std::min(buf_len, static_cast<int>(data_[index].size()) - offset); |
| memcpy(buf->data(), &data_[index][offset], num); |
| |
| if (MockHttpCache::GetTestMode(test_mode_) & TEST_MODE_SYNC_CACHE_READ) |
| return num; |
| |
| // Pause and resume. |
| if (defer_op_ == DEFER_READ) { |
| defer_op_ = DEFER_NONE; |
| resume_callback_ = std::move(callback); |
| resume_return_code_ = num; |
| return ERR_IO_PENDING; |
| } |
| |
| CallbackLater(std::move(callback), num); |
| return ERR_IO_PENDING; |
| } |
| |
| void MockDiskEntry::ResumeDiskEntryOperation() { |
| DCHECK(!resume_callback_.is_null()); |
| CallbackLater(std::move(resume_callback_), resume_return_code_); |
| resume_return_code_ = 0; |
| } |
| |
| int MockDiskEntry::WriteData(int index, |
| int offset, |
| IOBuffer* buf, |
| int buf_len, |
| CompletionOnceCallback callback, |
| bool truncate) { |
| DCHECK(index >= 0 && index < kNumCacheEntryDataIndices); |
| DCHECK(!callback.is_null()); |
| DCHECK(truncate); |
| |
| if (fail_requests_) { |
| CallbackLater(std::move(callback), ERR_CACHE_READ_FAILURE); |
| return ERR_IO_PENDING; |
| } |
| |
| if (offset < 0 || offset > static_cast<int>(data_[index].size())) |
| return ERR_FAILED; |
| |
| DCHECK_LT(offset + buf_len, kMaxMockCacheEntrySize); |
| data_[index].resize(offset + buf_len); |
| if (buf_len) |
| memcpy(&data_[index][offset], buf->data(), buf_len); |
| |
| if (MockHttpCache::GetTestMode(test_mode_) & TEST_MODE_SYNC_CACHE_WRITE) |
| return buf_len; |
| |
| if (defer_op_ == DEFER_WRITE) { |
| defer_op_ = DEFER_NONE; |
| resume_callback_ = std::move(callback); |
| resume_return_code_ = buf_len; |
| return ERR_IO_PENDING; |
| } |
| |
| CallbackLater(std::move(callback), buf_len); |
| return ERR_IO_PENDING; |
| } |
| |
| int MockDiskEntry::ReadSparseData(int64_t offset, |
| IOBuffer* buf, |
| int buf_len, |
| CompletionOnceCallback callback) { |
| DCHECK(!callback.is_null()); |
| if (fail_sparse_requests_) |
| return ERR_NOT_IMPLEMENTED; |
| if (!sparse_ || busy_ || cancel_) |
| return ERR_CACHE_OPERATION_NOT_SUPPORTED; |
| if (offset < 0) |
| return ERR_FAILED; |
| |
| if (fail_requests_) |
| return ERR_CACHE_READ_FAILURE; |
| |
| DCHECK(offset < std::numeric_limits<int32_t>::max()); |
| int real_offset = static_cast<int>(offset); |
| if (!buf_len) |
| return 0; |
| |
| int num = std::min(static_cast<int>(data_[1].size()) - real_offset, |
| buf_len); |
| memcpy(buf->data(), &data_[1][real_offset], num); |
| |
| if (MockHttpCache::GetTestMode(test_mode_) & TEST_MODE_SYNC_CACHE_READ) |
| return num; |
| |
| CallbackLater(std::move(callback), num); |
| busy_ = true; |
| delayed_ = false; |
| return ERR_IO_PENDING; |
| } |
| |
| int MockDiskEntry::WriteSparseData(int64_t offset, |
| IOBuffer* buf, |
| int buf_len, |
| CompletionOnceCallback callback) { |
| DCHECK(!callback.is_null()); |
| if (fail_sparse_requests_) |
| return ERR_NOT_IMPLEMENTED; |
| if (busy_ || cancel_) |
| return ERR_CACHE_OPERATION_NOT_SUPPORTED; |
| if (!sparse_) { |
| if (data_[1].size()) |
| return ERR_CACHE_OPERATION_NOT_SUPPORTED; |
| sparse_ = true; |
| } |
| if (offset < 0) |
| return ERR_FAILED; |
| if (!buf_len) |
| return 0; |
| |
| if (fail_requests_) |
| return ERR_CACHE_READ_FAILURE; |
| |
| DCHECK(offset < std::numeric_limits<int32_t>::max()); |
| int real_offset = static_cast<int>(offset); |
| |
| if (static_cast<int>(data_[1].size()) < real_offset + buf_len) { |
| DCHECK_LT(real_offset + buf_len, kMaxMockCacheEntrySize); |
| data_[1].resize(real_offset + buf_len); |
| } |
| |
| memcpy(&data_[1][real_offset], buf->data(), buf_len); |
| if (MockHttpCache::GetTestMode(test_mode_) & TEST_MODE_SYNC_CACHE_WRITE) |
| return buf_len; |
| |
| CallbackLater(std::move(callback), buf_len); |
| return ERR_IO_PENDING; |
| } |
| |
| int MockDiskEntry::GetAvailableRange(int64_t offset, |
| int len, |
| int64_t* start, |
| CompletionOnceCallback callback) { |
| DCHECK(!callback.is_null()); |
| if (!sparse_ || busy_ || cancel_) |
| return ERR_CACHE_OPERATION_NOT_SUPPORTED; |
| if (offset < 0) |
| return ERR_FAILED; |
| |
| if (fail_requests_) |
| return ERR_CACHE_READ_FAILURE; |
| |
| *start = offset; |
| DCHECK(offset < std::numeric_limits<int32_t>::max()); |
| int real_offset = static_cast<int>(offset); |
| if (static_cast<int>(data_[1].size()) < real_offset) |
| return 0; |
| |
| int num = std::min(static_cast<int>(data_[1].size()) - real_offset, len); |
| int count = 0; |
| for (; num > 0; num--, real_offset++) { |
| if (!count) { |
| if (data_[1][real_offset]) { |
| count++; |
| *start = real_offset; |
| } |
| } else { |
| if (!data_[1][real_offset]) |
| break; |
| count++; |
| } |
| } |
| if (MockHttpCache::GetTestMode(test_mode_) & TEST_MODE_SYNC_CACHE_WRITE) |
| return count; |
| |
| CallbackLater(std::move(callback), count); |
| return ERR_IO_PENDING; |
| } |
| |
| bool MockDiskEntry::CouldBeSparse() const { |
| if (fail_sparse_requests_) |
| return false; |
| return sparse_; |
| } |
| |
| void MockDiskEntry::CancelSparseIO() { |
| cancel_ = true; |
| } |
| |
| net::Error MockDiskEntry::ReadyForSparseIO(CompletionOnceCallback callback) { |
| if (fail_sparse_requests_) |
| return ERR_NOT_IMPLEMENTED; |
| if (!cancel_) |
| return OK; |
| |
| cancel_ = false; |
| DCHECK(!callback.is_null()); |
| if (MockHttpCache::GetTestMode(test_mode_) & TEST_MODE_SYNC_CACHE_READ) |
| return OK; |
| |
| // The pending operation is already in the message loop (and hopefully |
| // already in the second pass). Just notify the caller that it finished. |
| CallbackLater(std::move(callback), 0); |
| return ERR_IO_PENDING; |
| } |
| |
| void MockDiskEntry::SetLastUsedTimeForTest(base::Time time) { |
| NOTREACHED(); |
| } |
| |
| // If |value| is true, don't deliver any completion callbacks until called |
| // again with |value| set to false. Caution: remember to enable callbacks |
| // again or all subsequent tests will fail. |
| // Static. |
| void MockDiskEntry::IgnoreCallbacks(bool value) { |
| if (ignore_callbacks_ == value) |
| return; |
| ignore_callbacks_ = value; |
| if (!value) |
| StoreAndDeliverCallbacks(false, NULL, CompletionOnceCallback(), 0); |
| } |
| |
| MockDiskEntry::~MockDiskEntry() = default; |
| |
| // Unlike the callbacks for MockHttpTransaction, we want this one to run even |
| // if the consumer called Close on the MockDiskEntry. We achieve that by |
| // leveraging the fact that this class is reference counted. |
| void MockDiskEntry::CallbackLater(CompletionOnceCallback callback, int result) { |
| if (ignore_callbacks_) |
| return StoreAndDeliverCallbacks(true, this, std::move(callback), result); |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::BindOnce(&MockDiskEntry::RunCallback, this, |
| std::move(callback), result)); |
| } |
| |
| void MockDiskEntry::RunCallback(CompletionOnceCallback callback, int result) { |
| if (busy_) { |
| // This is kind of hacky, but controlling the behavior of just this entry |
| // from a test is sort of complicated. What we really want to do is |
| // delay the delivery of a sparse IO operation a little more so that the |
| // request start operation (async) will finish without seeing the end of |
| // this operation (already posted to the message loop)... and without |
| // just delaying for n mS (which may cause trouble with slow bots). So |
| // we re-post this operation (all async sparse IO operations will take two |
| // trips through the message loop instead of one). |
| if (!delayed_) { |
| delayed_ = true; |
| return CallbackLater(std::move(callback), result); |
| } |
| } |
| busy_ = false; |
| std::move(callback).Run(result); |
| } |
| |
| // When |store| is true, stores the callback to be delivered later; otherwise |
| // delivers any callback previously stored. |
| // Static. |
| void MockDiskEntry::StoreAndDeliverCallbacks(bool store, |
| MockDiskEntry* entry, |
| CompletionOnceCallback callback, |
| int result) { |
| static std::vector<CallbackInfo> callback_list; |
| if (store) { |
| CallbackInfo c = {entry, std::move(callback), result}; |
| callback_list.push_back(std::move(c)); |
| } else { |
| for (size_t i = 0; i < callback_list.size(); i++) { |
| CallbackInfo& c = callback_list[i]; |
| c.entry->CallbackLater(std::move(c.callback), c.result); |
| } |
| callback_list.clear(); |
| } |
| } |
| |
| // Statics. |
| bool MockDiskEntry::ignore_callbacks_ = false; |
| |
| //----------------------------------------------------------------------------- |
| |
| MockDiskCache::MockDiskCache() |
| : open_count_(0), |
| create_count_(0), |
| doomed_count_(0), |
| fail_requests_(false), |
| soft_failures_(false), |
| double_create_check_(true), |
| fail_sparse_requests_(false), |
| support_in_memory_entry_data_(true), |
| defer_op_(MockDiskEntry::DEFER_NONE), |
| resume_return_code_(0) {} |
| |
| MockDiskCache::~MockDiskCache() { |
| ReleaseAll(); |
| } |
| |
| CacheType MockDiskCache::GetCacheType() const { |
| return DISK_CACHE; |
| } |
| |
| int32_t MockDiskCache::GetEntryCount() const { |
| return static_cast<int32_t>(entries_.size()); |
| } |
| |
| net::Error MockDiskCache::OpenEntry(const std::string& key, |
| net::RequestPriority request_priority, |
| disk_cache::Entry** entry, |
| CompletionOnceCallback callback) { |
| DCHECK(!callback.is_null()); |
| if (fail_requests_) |
| return ERR_CACHE_OPEN_FAILURE; |
| |
| auto it = entries_.find(key); |
| if (it == entries_.end()) |
| return ERR_CACHE_OPEN_FAILURE; |
| |
| if (it->second->is_doomed()) { |
| it->second->Release(); |
| entries_.erase(it); |
| return ERR_CACHE_OPEN_FAILURE; |
| } |
| |
| open_count_++; |
| |
| it->second->AddRef(); |
| *entry = it->second; |
| |
| if (soft_failures_) |
| it->second->set_fail_requests(); |
| |
| if (GetTestModeForEntry(key) & TEST_MODE_SYNC_CACHE_START) |
| return OK; |
| |
| CallbackLater(std::move(callback), OK); |
| return ERR_IO_PENDING; |
| } |
| |
| net::Error MockDiskCache::CreateEntry(const std::string& key, |
| net::RequestPriority request_priority, |
| disk_cache::Entry** entry, |
| CompletionOnceCallback callback) { |
| DCHECK(!callback.is_null()); |
| if (fail_requests_) |
| return ERR_CACHE_CREATE_FAILURE; |
| |
| auto it = entries_.find(key); |
| if (it != entries_.end()) { |
| if (!it->second->is_doomed()) { |
| if (double_create_check_) |
| NOTREACHED(); |
| else |
| return ERR_CACHE_CREATE_FAILURE; |
| } |
| it->second->Release(); |
| entries_.erase(it); |
| } |
| |
| create_count_++; |
| |
| MockDiskEntry* new_entry = new MockDiskEntry(key); |
| |
| new_entry->AddRef(); |
| entries_[key] = new_entry; |
| |
| new_entry->AddRef(); |
| *entry = new_entry; |
| |
| if (soft_failures_) |
| new_entry->set_fail_requests(); |
| |
| if (fail_sparse_requests_) |
| new_entry->set_fail_sparse_requests(); |
| |
| if (GetTestModeForEntry(key) & TEST_MODE_SYNC_CACHE_START) |
| return OK; |
| |
| // Pause and resume. |
| if (defer_op_ == MockDiskEntry::DEFER_CREATE) { |
| defer_op_ = MockDiskEntry::DEFER_NONE; |
| resume_callback_ = std::move(callback); |
| resume_return_code_ = OK; |
| return ERR_IO_PENDING; |
| } |
| |
| CallbackLater(std::move(callback), OK); |
| return ERR_IO_PENDING; |
| } |
| |
| net::Error MockDiskCache::DoomEntry(const std::string& key, |
| net::RequestPriority request_priority, |
| CompletionOnceCallback callback) { |
| DCHECK(!callback.is_null()); |
| auto it = entries_.find(key); |
| if (it != entries_.end()) { |
| it->second->Release(); |
| entries_.erase(it); |
| doomed_count_++; |
| } |
| |
| if (GetTestModeForEntry(key) & TEST_MODE_SYNC_CACHE_START) |
| return OK; |
| |
| CallbackLater(std::move(callback), OK); |
| return ERR_IO_PENDING; |
| } |
| |
| net::Error MockDiskCache::DoomAllEntries(CompletionOnceCallback callback) { |
| return ERR_NOT_IMPLEMENTED; |
| } |
| |
| net::Error MockDiskCache::DoomEntriesBetween(const base::Time initial_time, |
| const base::Time end_time, |
| CompletionOnceCallback callback) { |
| return ERR_NOT_IMPLEMENTED; |
| } |
| |
| net::Error MockDiskCache::DoomEntriesSince(const base::Time initial_time, |
| CompletionOnceCallback callback) { |
| return ERR_NOT_IMPLEMENTED; |
| } |
| |
| int64_t MockDiskCache::CalculateSizeOfAllEntries( |
| Int64CompletionOnceCallback callback) { |
| return ERR_NOT_IMPLEMENTED; |
| } |
| |
| class MockDiskCache::NotImplementedIterator : public Iterator { |
| public: |
| net::Error OpenNextEntry(disk_cache::Entry** next_entry, |
| CompletionOnceCallback callback) override { |
| return ERR_NOT_IMPLEMENTED; |
| } |
| }; |
| |
| std::unique_ptr<disk_cache::Backend::Iterator> MockDiskCache::CreateIterator() { |
| return std::unique_ptr<Iterator>(new NotImplementedIterator()); |
| } |
| |
| void MockDiskCache::GetStats(base::StringPairs* stats) { |
| } |
| |
| void MockDiskCache::OnExternalCacheHit(const std::string& key) { |
| } |
| |
| size_t MockDiskCache::DumpMemoryStats( |
| base::trace_event::ProcessMemoryDump* pmd, |
| const std::string& parent_absolute_name) const { |
| return 0u; |
| } |
| |
| uint8_t MockDiskCache::GetEntryInMemoryData(const std::string& key) { |
| if (!support_in_memory_entry_data_) |
| return 0; |
| |
| auto it = entries_.find(key); |
| if (it != entries_.end()) |
| return it->second->in_memory_data(); |
| return 0; |
| } |
| |
| void MockDiskCache::SetEntryInMemoryData(const std::string& key, uint8_t data) { |
| auto it = entries_.find(key); |
| if (it != entries_.end()) |
| it->second->set_in_memory_data(data); |
| } |
| |
| void MockDiskCache::ReleaseAll() { |
| for (auto entry : entries_) |
| entry.second->Release(); |
| entries_.clear(); |
| } |
| |
| void MockDiskCache::CallbackLater(CompletionOnceCallback callback, int result) { |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::BindOnce(std::move(callback), result)); |
| } |
| |
| bool MockDiskCache::IsDiskEntryDoomed(const std::string& key) { |
| auto it = entries_.find(key); |
| if (it != entries_.end()) |
| return it->second->is_doomed(); |
| |
| return false; |
| } |
| |
| void MockDiskCache::ResumeCacheOperation() { |
| DCHECK(!resume_callback_.is_null()); |
| CallbackLater(std::move(resume_callback_), resume_return_code_); |
| resume_return_code_ = 0; |
| } |
| |
| scoped_refptr<MockDiskEntry> MockDiskCache::GetDiskEntryRef( |
| const std::string& key) { |
| auto it = entries_.find(key); |
| if (it == entries_.end()) |
| return nullptr; |
| return it->second; |
| } |
| |
| //----------------------------------------------------------------------------- |
| |
| int MockBackendFactory::CreateBackend( |
| NetLog* net_log, |
| std::unique_ptr<disk_cache::Backend>* backend, |
| CompletionOnceCallback callback) { |
| backend->reset(new MockDiskCache()); |
| return OK; |
| } |
| |
| //----------------------------------------------------------------------------- |
| |
| MockHttpCache::MockHttpCache() : MockHttpCache(false) {} |
| |
| MockHttpCache::MockHttpCache( |
| std::unique_ptr<HttpCache::BackendFactory> disk_cache_factory) |
| : MockHttpCache(std::move(disk_cache_factory), false) {} |
| |
| MockHttpCache::MockHttpCache(bool is_main_cache) |
| : MockHttpCache(std::make_unique<MockBackendFactory>(), is_main_cache) {} |
| |
| MockHttpCache::MockHttpCache( |
| std::unique_ptr<HttpCache::BackendFactory> disk_cache_factory, |
| bool is_main_cache) |
| : http_cache_(std::make_unique<MockNetworkLayer>(), |
| std::move(disk_cache_factory), |
| is_main_cache) {} |
| |
| disk_cache::Backend* MockHttpCache::backend() { |
| TestCompletionCallback cb; |
| disk_cache::Backend* backend; |
| int rv = http_cache_.GetBackend(&backend, cb.callback()); |
| rv = cb.GetResult(rv); |
| return (rv == OK) ? backend : NULL; |
| } |
| |
| MockDiskCache* MockHttpCache::disk_cache() { |
| return static_cast<MockDiskCache*>(backend()); |
| } |
| |
| int MockHttpCache::CreateTransaction(std::unique_ptr<HttpTransaction>* trans) { |
| return http_cache_.CreateTransaction(DEFAULT_PRIORITY, trans); |
| } |
| |
| void MockHttpCache::SimulateCacheLockTimeout() { |
| http_cache_.SimulateCacheLockTimeoutForTesting(); |
| } |
| |
| void MockHttpCache::SimulateCacheLockTimeoutAfterHeaders() { |
| http_cache_.SimulateCacheLockTimeoutAfterHeadersForTesting(); |
| } |
| |
| void MockHttpCache::FailConditionalizations() { |
| http_cache_.FailConditionalizationForTest(); |
| } |
| |
| bool MockHttpCache::ReadResponseInfo(disk_cache::Entry* disk_entry, |
| HttpResponseInfo* response_info, |
| bool* response_truncated) { |
| int size = disk_entry->GetDataSize(0); |
| |
| TestCompletionCallback cb; |
| scoped_refptr<IOBuffer> buffer = base::MakeRefCounted<IOBuffer>(size); |
| int rv = disk_entry->ReadData(0, 0, buffer.get(), size, cb.callback()); |
| rv = cb.GetResult(rv); |
| EXPECT_EQ(size, rv); |
| |
| return HttpCache::ParseResponseInfo(buffer->data(), size, response_info, |
| response_truncated); |
| } |
| |
| bool MockHttpCache::WriteResponseInfo(disk_cache::Entry* disk_entry, |
| const HttpResponseInfo* response_info, |
| bool skip_transient_headers, |
| bool response_truncated) { |
| base::Pickle pickle; |
| response_info->Persist( |
| &pickle, skip_transient_headers, response_truncated); |
| |
| TestCompletionCallback cb; |
| scoped_refptr<WrappedIOBuffer> data = base::MakeRefCounted<WrappedIOBuffer>( |
| reinterpret_cast<const char*>(pickle.data())); |
| int len = static_cast<int>(pickle.size()); |
| |
| int rv = disk_entry->WriteData(0, 0, data.get(), len, cb.callback(), true); |
| rv = cb.GetResult(rv); |
| return (rv == len); |
| } |
| |
| bool MockHttpCache::OpenBackendEntry(const std::string& key, |
| disk_cache::Entry** entry) { |
| TestCompletionCallback cb; |
| int rv = backend()->OpenEntry(key, net::HIGHEST, entry, cb.callback()); |
| return (cb.GetResult(rv) == OK); |
| } |
| |
| bool MockHttpCache::CreateBackendEntry(const std::string& key, |
| disk_cache::Entry** entry, |
| NetLog* net_log) { |
| TestCompletionCallback cb; |
| int rv = backend()->CreateEntry(key, net::HIGHEST, entry, cb.callback()); |
| return (cb.GetResult(rv) == OK); |
| } |
| |
| // Static. |
| int MockHttpCache::GetTestMode(int test_mode) { |
| if (!g_test_mode) |
| return test_mode; |
| |
| return g_test_mode; |
| } |
| |
| // Static. |
| void MockHttpCache::SetTestMode(int test_mode) { |
| g_test_mode = test_mode; |
| } |
| |
| bool MockHttpCache::IsWriterPresent(const std::string& key) { |
| HttpCache::ActiveEntry* entry = http_cache_.FindActiveEntry(key); |
| return entry && entry->writers && !entry->writers->IsEmpty(); |
| } |
| |
| bool MockHttpCache::IsHeadersTransactionPresent(const std::string& key) { |
| HttpCache::ActiveEntry* entry = http_cache_.FindActiveEntry(key); |
| return entry && entry->headers_transaction; |
| } |
| |
| int MockHttpCache::GetCountReaders(const std::string& key) { |
| HttpCache::ActiveEntry* entry = http_cache_.FindActiveEntry(key); |
| return entry ? entry->readers.size() : 0; |
| } |
| |
| int MockHttpCache::GetCountAddToEntryQueue(const std::string& key) { |
| HttpCache::ActiveEntry* entry = http_cache_.FindActiveEntry(key); |
| return entry ? entry->add_to_entry_queue.size() : 0; |
| } |
| |
| int MockHttpCache::GetCountDoneHeadersQueue(const std::string& key) { |
| HttpCache::ActiveEntry* entry = http_cache_.FindActiveEntry(key); |
| return entry ? entry->done_headers_queue.size() : 0; |
| } |
| |
| int MockHttpCache::GetCountWriterTransactions(const std::string& key) { |
| HttpCache::ActiveEntry* entry = http_cache_.FindActiveEntry(key); |
| return entry && entry->writers ? entry->writers->GetTransactionsCount() : 0; |
| } |
| |
| //----------------------------------------------------------------------------- |
| |
| net::Error MockDiskCacheNoCB::CreateEntry(const std::string& key, |
| net::RequestPriority request_priority, |
| disk_cache::Entry** entry, |
| CompletionOnceCallback callback) { |
| return ERR_IO_PENDING; |
| } |
| |
| //----------------------------------------------------------------------------- |
| |
| int MockBackendNoCbFactory::CreateBackend( |
| NetLog* net_log, |
| std::unique_ptr<disk_cache::Backend>* backend, |
| CompletionOnceCallback callback) { |
| backend->reset(new MockDiskCacheNoCB()); |
| return OK; |
| } |
| |
| //----------------------------------------------------------------------------- |
| |
| MockBlockingBackendFactory::MockBlockingBackendFactory() |
| : backend_(NULL), |
| block_(true), |
| fail_(false) { |
| } |
| |
| MockBlockingBackendFactory::~MockBlockingBackendFactory() = default; |
| |
| int MockBlockingBackendFactory::CreateBackend( |
| NetLog* net_log, |
| std::unique_ptr<disk_cache::Backend>* backend, |
| CompletionOnceCallback callback) { |
| if (!block_) { |
| if (!fail_) |
| backend->reset(new MockDiskCache()); |
| return Result(); |
| } |
| |
| backend_ = backend; |
| callback_ = std::move(callback); |
| return ERR_IO_PENDING; |
| } |
| |
| void MockBlockingBackendFactory::FinishCreation() { |
| block_ = false; |
| if (!callback_.is_null()) { |
| if (!fail_) |
| backend_->reset(new MockDiskCache()); |
| // Running the callback might delete |this|. |
| base::ResetAndReturn(&callback_).Run(Result()); |
| } |
| } |
| |
| } // namespace net |