diff options
author | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-02 22:53:18 +0000 |
---|---|---|
committer | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-02 22:53:18 +0000 |
commit | e7f2964e84ca06d711d33723e7725d03ee2aa136 (patch) | |
tree | e2cc8f033863a972998fdd668dd698d222bea3aa /net/http | |
parent | e9e6b1c6d3870e9a1e9a8aa7e6c454cdcd354d0f (diff) | |
download | chromium_src-e7f2964e84ca06d711d33723e7725d03ee2aa136.zip chromium_src-e7f2964e84ca06d711d33723e7725d03ee2aa136.tar.gz chromium_src-e7f2964e84ca06d711d33723e7725d03ee2aa136.tar.bz2 |
Proposed change to support resource loading for media files.
Highlights of changes:
- Added methods to disk_cache::Entry:
- Entry::PrepareTargetAsExternalFile(int index)
Prepare a stream in an entry to use external file for storage.
- Entry::GetExternalFile(int index)
Get the external file backing the stream in the entry.
- Added a property "CacheType type_" to HttpCache, along with setter and getter.
There shall be two cache types, COMMON_CACHE and MEDIA_CACHE for distinguishing between different purpose of HttpCache. We have this property to trigger special behavior for caching needs of media files.
- Added static methods to ChromeURLRequestContext
- ChromeURLRequestContext::CreateOriginalForMedia
Create a URLRequestContext for media files for the original profile.
- ChromeURLRequestContext::CreateOffTheRecordForMedia
Create a URLRequestContext for media files for off the record profile.
- Added method to Profile interface.
- GetRequestContextForMedia
To get the request context for media files from the context.
Design decissions:
- Enforce writing to external file by calling methods to Entry rather than construct Backend by a different flag.
Since we only want a valid and full response to go into an external file rather than redirection response or erroneous response, we should let HttpCache::Transaction to decide when to have an external file for response data. We eliminate a lot of useless external cache files.
- Adding the CacheType enum and property to HttpCache, we could allow possible (?) future extensions to HttpCache to handle other different caching needs. And there's no need to add change constructors of HttpCache, but maybe we should add a specific constructor to accomodate a media HttpCache?
- Adding Profile::GetRequestContextForMedia()
Since we will need to use this new request context in ResourceDispatcherHost, I think the best place to keep it is in the profile. Also we will expose to user that there's a separate cache for media, so it's better to expose it in the Profile level to allow settings to the media cache, e.g. max file size, etc.
Review URL: http://codereview.chromium.org/19747
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@10745 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/http')
-rw-r--r-- | net/http/http_cache.cc | 49 | ||||
-rw-r--r-- | net/http/http_cache.h | 27 | ||||
-rw-r--r-- | net/http/http_cache_unittest.cc | 99 | ||||
-rw-r--r-- | net/http/http_network_layer.cc | 28 | ||||
-rw-r--r-- | net/http/http_network_layer.h | 12 | ||||
-rw-r--r-- | net/http/http_response_info.h | 5 |
6 files changed, 210 insertions, 10 deletions
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index c54b6d4..913dc00 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc @@ -286,6 +286,9 @@ class HttpCache::Transaction // Called to write response_ to the cache entry. void WriteResponseInfoToEntry(); + // Called to truncate response content in the entry. + void TruncateResponseData(); + // Called to append response data to the cache entry. void AppendResponseDataToEntry(IOBuffer* data, int data_len); @@ -790,6 +793,12 @@ int HttpCache::Transaction::ReadResponseInfoFromEntry() { if (!HttpCache::ReadResponseInfo(entry_->disk_entry, &response_)) return ERR_FAILED; + // If the cache object is used for media file, we want the file handle of + // response data. + if (cache_->type() == HttpCache::MEDIA) + response_.response_data_file = + entry_->disk_entry->GetPlatformFile(kResponseContentIndex); + return OK; } @@ -846,6 +855,27 @@ void HttpCache::Transaction::AppendResponseDataToEntry(IOBuffer* data, WriteToEntry(kResponseContentIndex, current_size, data, data_len); } +void HttpCache::Transaction::TruncateResponseData() { + if (!entry_) + return; + + // If the cache is for media files, we try to prepare the response data + // file as an external file and truncate it afterwards. + // Recipient of ResponseInfo should judge from |response_.response_data_file| + // to tell whether an external file of response data is available for reading + // or not. + // TODO(hclam): we should prepare the target stream as extern file only + // if we get a valid response from server, i.e. 200. We don't want empty + // cache files for redirection or external files for erroneous requests. + response_.response_data_file = base::kInvalidPlatformFileValue; + if (cache_->type() == HttpCache::MEDIA) + response_.response_data_file = + entry_->disk_entry->UseExternalFile(kResponseContentIndex); + + // Truncate the stream. + WriteToEntry(kResponseContentIndex, 0, NULL, 0); +} + void HttpCache::Transaction::DoneWritingToEntry(bool success) { if (!entry_) return; @@ -902,8 +932,8 @@ void HttpCache::Transaction::OnNetworkInfoAvailable(int result) { response_ = *new_response; WriteResponseInfoToEntry(); - // Truncate the response data - WriteToEntry(kResponseContentIndex, 0, NULL, 0); + // Truncate response data + TruncateResponseData(); // If this response is a redirect, then we can stop writing now. (We // don't need to cache the response body of a redirect.) @@ -958,14 +988,28 @@ HttpCache::HttpCache(ProxyService* proxy_service, int cache_size) : disk_cache_dir_(cache_dir), mode_(NORMAL), + type_(COMMON), network_layer_(HttpNetworkLayer::CreateFactory(proxy_service)), ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), in_memory_cache_(false), cache_size_(cache_size) { } +HttpCache::HttpCache(HttpNetworkSession* session, + const std::wstring& cache_dir, + int cache_size) + : disk_cache_dir_(cache_dir), + mode_(NORMAL), + type_(COMMON), + network_layer_(HttpNetworkLayer::CreateFactory(session)), + ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), + in_memory_cache_(false), + cache_size_(cache_size) { +} + HttpCache::HttpCache(ProxyService* proxy_service, int cache_size) : mode_(NORMAL), + type_(COMMON), network_layer_(HttpNetworkLayer::CreateFactory(proxy_service)), ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), in_memory_cache_(true), @@ -975,6 +1019,7 @@ HttpCache::HttpCache(ProxyService* proxy_service, int cache_size) HttpCache::HttpCache(HttpTransactionFactory* network_layer, disk_cache::Backend* disk_cache) : mode_(NORMAL), + type_(COMMON), network_layer_(network_layer), disk_cache_(disk_cache), ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), diff --git a/net/http/http_cache.h b/net/http/http_cache.h index 51991f5..528c964 100644 --- a/net/http/http_cache.h +++ b/net/http/http_cache.h @@ -29,6 +29,7 @@ class Entry; namespace net { +class HttpNetworkSession; class HttpRequestInfo; class HttpResponseInfo; class ProxyService; @@ -48,13 +49,33 @@ class HttpCache : public HttpTransactionFactory { PLAYBACK }; - // Initialize the cache from the directory where its data is stored. The + // The type of an HttpCache object, essentially describe what an HttpCache + // object is for. + enum Type { + // An HttpCache object for common objects, e.g. html pages, images, fonts, + // css files, js files and other common web resources. + COMMON = 0, + // A cache system for media file, e.g. video and audio files. These files + // are huge and has special requirement for access. + MEDIA + }; + + // Initialize the cache from the directory where its data is stored. The // disk cache is initialized lazily (by CreateTransaction) in this case. If // |cache_size| is zero, a default value will be calculated automatically. HttpCache(ProxyService* proxy_service, const std::wstring& cache_dir, int cache_size); + // Initialize the cache from the directory where its data is stored. The + // disk cache is initialized lazily (by CreateTransaction) in this case. If + // |cache_size| is zero, a default value will be calculated automatically. + // Provide an existing HttpNetworkSession, the cache can construct a + // network layer with a shared HttpNetworkSession in order for multiple + // network layers to share information (e.g. authenication data). + HttpCache(HttpNetworkSession* session, const std::wstring& cache_dir, + int cache_size); + // Initialize using an in-memory cache. The cache is initialized lazily // (by CreateTransaction) in this case. If |cache_size| is zero, a default // value will be calculated automatically. @@ -91,6 +112,9 @@ class HttpCache : public HttpTransactionFactory { void set_mode(Mode value) { mode_ = value; } Mode mode() { return mode_; } + void set_type(Type type) { type_ = type; } + Type type() { return type_; } + private: // Types -------------------------------------------------------------------- @@ -146,6 +170,7 @@ class HttpCache : public HttpTransactionFactory { std::wstring disk_cache_dir_; Mode mode_; + Type type_; scoped_ptr<HttpTransactionFactory> network_layer_; scoped_ptr<disk_cache::Backend> disk_cache_; diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc index b52f2a4..5db229b 100644 --- a/net/http/http_cache_unittest.cc +++ b/net/http/http_cache_unittest.cc @@ -6,6 +6,7 @@ #include "base/hash_tables.h" #include "base/message_loop.h" +#include "base/platform_file.h" #include "base/string_util.h" #include "net/base/net_errors.h" #include "net/base/load_flags.h" @@ -26,10 +27,12 @@ namespace { class MockDiskEntry : public disk_cache::Entry, public base::RefCounted<MockDiskEntry> { public: - MockDiskEntry() : test_mode_(0), doomed_(false) { + MockDiskEntry() + : test_mode_(0), doomed_(false), platform_file_(global_platform_file_) { } - MockDiskEntry(const std::string& key) : key_(key), doomed_(false) { + MockDiskEntry(const std::string& key) + : key_(key), doomed_(false), platform_file_(global_platform_file_) { const MockTransaction* t = FindMockTransaction(GURL(key)); DCHECK(t); test_mode_ = t->test_mode; @@ -98,6 +101,18 @@ class MockDiskEntry : public disk_cache::Entry, return buf_len; } + base::PlatformFile UseExternalFile(int index) { + return platform_file_; + } + + base::PlatformFile GetPlatformFile(int index) { + return platform_file_; + } + + static void set_global_platform_file(base::PlatformFile platform_file) { + global_platform_file_ = platform_file; + } + private: // Unlike the callbacks for MockHttpTransaction, we want this one to run even // if the consumer called Close on the MockDiskEntry. We achieve that by @@ -114,8 +129,13 @@ class MockDiskEntry : public disk_cache::Entry, std::vector<char> data_[2]; int test_mode_; bool doomed_; + base::PlatformFile platform_file_; + static base::PlatformFile global_platform_file_; }; +base::PlatformFile MockDiskEntry::global_platform_file_ = + base::kInvalidPlatformFileValue; + class MockDiskCache : public disk_cache::Backend { public: MockDiskCache() : open_count_(0), create_count_(0), fail_requests_(0) { @@ -1184,3 +1204,78 @@ TEST(HttpCache, OutlivedTransactions) { delete cache; delete trans; } + +// Make sure Entry::UseExternalFile is called when a new entry is created in +// a HttpCache with MEDIA type. Also make sure Entry::GetPlatformFile is called +// when an entry is loaded from a HttpCache with MEDIA type. Also confirm we +// will receive a file handle in ResponseInfo from a media cache. +TEST(HttpCache, SimpleGET_MediaCache) { + // Initialize the HttpCache with MEDIA type. + MockHttpCache cache; + cache.http_cache()->set_type(net::HttpCache::MEDIA); + + // Define some fake file handles for testing. + base::PlatformFile kFakePlatformFile1, kFakePlatformFile2; +#if defined(OS_WIN) + kFakePlatformFile1 = reinterpret_cast<base::PlatformFile>(1); + kFakePlatformFile2 = reinterpret_cast<base::PlatformFile>(2); +#else + kFakePlatformFile1 = 1; + kFakePlatformFile2 = 2; +#endif + + ScopedMockTransaction trans_info(kSimpleGET_Transaction); + TestCompletionCallback callback; + + { + // Set the fake file handle to MockDiskEntry so cache is written with an + // entry created with our fake file handle. + MockDiskEntry::set_global_platform_file(kFakePlatformFile1); + + scoped_ptr<net::HttpTransaction> trans( + cache.http_cache()->CreateTransaction()); + ASSERT_TRUE(trans.get()); + + MockHttpRequest request(trans_info); + + int rv = trans->Start(&request, &callback); + if (rv == net::ERR_IO_PENDING) + rv = callback.WaitForResult(); + ASSERT_EQ(net::OK, rv); + + const net::HttpResponseInfo* response = trans->GetResponseInfo(); + ASSERT_TRUE(response); + + ASSERT_EQ(kFakePlatformFile1, response->response_data_file); + + ReadAndVerifyTransaction(trans.get(), trans_info); + } + + // Load only from cache so we would get the same file handle. + trans_info.load_flags |= net::LOAD_ONLY_FROM_CACHE; + + { + // Set a different file handle value to MockDiskEntry so any new entry + // created in the cache won't have the same file handle value. + MockDiskEntry::set_global_platform_file(kFakePlatformFile2); + + scoped_ptr<net::HttpTransaction> trans( + cache.http_cache()->CreateTransaction()); + ASSERT_TRUE(trans.get()); + + MockHttpRequest request(trans_info); + + int rv = trans->Start(&request, &callback); + if (rv == net::ERR_IO_PENDING) + rv = callback.WaitForResult(); + ASSERT_EQ(net::OK, rv); + + const net::HttpResponseInfo* response = trans->GetResponseInfo(); + ASSERT_TRUE(response); + + // Make sure we get the same file handle as in the first request. + ASSERT_EQ(kFakePlatformFile1, response->response_data_file); + + ReadAndVerifyTransaction(trans.get(), trans_info); + } +} diff --git a/net/http/http_network_layer.cc b/net/http/http_network_layer.cc index 23f53f7..8ba6bfc 100644 --- a/net/http/http_network_layer.cc +++ b/net/http/http_network_layer.cc @@ -21,13 +21,26 @@ HttpTransactionFactory* HttpNetworkLayer::CreateFactory( return new HttpNetworkLayer(proxy_service); } +// static +HttpTransactionFactory* HttpNetworkLayer::CreateFactory( + HttpNetworkSession* session) { + DCHECK(session); + + return new HttpNetworkLayer(session); +} + //----------------------------------------------------------------------------- HttpNetworkLayer::HttpNetworkLayer(ProxyService* proxy_service) - : proxy_service_(proxy_service), suspended_(false) { + : proxy_service_(proxy_service), session_(NULL), suspended_(false) { DCHECK(proxy_service_); } +HttpNetworkLayer::HttpNetworkLayer(HttpNetworkSession* session) + : proxy_service_(NULL), session_(session), suspended_(false) { + DCHECK(session_.get()); +} + HttpNetworkLayer::~HttpNetworkLayer() { } @@ -35,11 +48,8 @@ HttpTransaction* HttpNetworkLayer::CreateTransaction() { if (suspended_) return NULL; - if (!session_) - session_ = new HttpNetworkSession(proxy_service_); - return new HttpNetworkTransaction( - session_, ClientSocketFactory::GetDefaultFactory()); + GetSession(), ClientSocketFactory::GetDefaultFactory()); } HttpCache* HttpNetworkLayer::GetCache() { @@ -53,5 +63,13 @@ void HttpNetworkLayer::Suspend(bool suspend) { session_->connection_pool()->CloseIdleSockets(); } +HttpNetworkSession* HttpNetworkLayer::GetSession() { + if (!session_) { + DCHECK(proxy_service_); + session_ = new HttpNetworkSession(proxy_service_); + } + return session_; +} + } // namespace net diff --git a/net/http/http_network_layer.h b/net/http/http_network_layer.h index 8424b2f..a2bb491 100644 --- a/net/http/http_network_layer.h +++ b/net/http/http_network_layer.h @@ -19,17 +19,29 @@ class HttpNetworkLayer : public HttpTransactionFactory { public: // |proxy_service| must remain valid for the lifetime of HttpNetworkLayer. explicit HttpNetworkLayer(ProxyService* proxy_service); + // Construct a HttpNetworkLayer with an existing HttpNetworkSession which + // contains a valid ProxyService. + explicit HttpNetworkLayer(HttpNetworkSession* session); ~HttpNetworkLayer(); // This function hides the details of how a network layer gets instantiated // and allows other implementations to be substituted. static HttpTransactionFactory* CreateFactory(ProxyService* proxy_service); + // Create a transaction factory that instantiate a network layer over an + // existing network session. Network session contains some valuable + // information (e.g. authentication data) that we want to share across + // multiple network layers. This method exposes the implementation details + // of a network layer, use this method with an existing network layer only + // when network session is shared. + static HttpTransactionFactory* CreateFactory(HttpNetworkSession* session); // HttpTransactionFactory methods: virtual HttpTransaction* CreateTransaction(); virtual HttpCache* GetCache(); virtual void Suspend(bool suspend); + HttpNetworkSession* GetSession(); + private: // The proxy service being used for the session. ProxyService* proxy_service_; diff --git a/net/http/http_response_info.h b/net/http/http_response_info.h index 671a390..caa49df 100644 --- a/net/http/http_response_info.h +++ b/net/http/http_response_info.h @@ -5,6 +5,7 @@ #ifndef NET_HTTP_HTTP_RESPONSE_INFO_H_ #define NET_HTTP_HTTP_RESPONSE_INFO_H_ +#include "base/platform_file.h" #include "base/time.h" #include "net/base/auth.h" #include "net/base/ssl_info.h" @@ -48,6 +49,10 @@ class HttpResponseInfo { // The "Vary" header data for this response. HttpVaryData vary_data; + + // Platform specific file handle to the response data, if response data is + // not in a standalone file, its value is base::kInvalidPlatformFileValue. + base::PlatformFile response_data_file; }; } // namespace net |