diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-28 03:57:02 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-28 03:57:02 +0000 |
commit | 5bf1646f545afaf67cd08c8992a255287cb74046 (patch) | |
tree | a4dbf2d2ff023815b7d09a80b795460c178985ed /content/browser/webui | |
parent | 24ea7a17338ce6ed2621aeaeb5542edf5b07d098 (diff) | |
download | chromium_src-5bf1646f545afaf67cd08c8992a255287cb74046.zip chromium_src-5bf1646f545afaf67cd08c8992a255287cb74046.tar.gz chromium_src-5bf1646f545afaf67cd08c8992a255287cb74046.tar.bz2 |
Clean up of url data manager classes in content: move URLDataSourceImpl to its own file, move all the code to the content namespace, and remove the "Chrome" prefix from classes.
TBR=scottmg
BUG=169170
Review URL: https://codereview.chromium.org/12093012
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@179096 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/webui')
-rw-r--r-- | content/browser/webui/url_data_manager.cc | 94 | ||||
-rw-r--r-- | content/browser/webui/url_data_manager.h | 115 | ||||
-rw-r--r-- | content/browser/webui/url_data_manager_backend.cc | 53 | ||||
-rw-r--r-- | content/browser/webui/url_data_manager_backend.h | 31 | ||||
-rw-r--r-- | content/browser/webui/url_data_source_impl.cc | 59 | ||||
-rw-r--r-- | content/browser/webui/url_data_source_impl.h | 97 | ||||
-rw-r--r-- | content/browser/webui/web_ui_data_source_impl.cc (renamed from content/browser/webui/web_ui_data_source.cc) | 91 | ||||
-rw-r--r-- | content/browser/webui/web_ui_data_source_impl.h (renamed from content/browser/webui/web_ui_data_source.h) | 40 | ||||
-rw-r--r-- | content/browser/webui/web_ui_data_source_unittest.cc | 10 |
9 files changed, 306 insertions, 284 deletions
diff --git a/content/browser/webui/url_data_manager.cc b/content/browser/webui/url_data_manager.cc index 6a4406b..3e8d4b2 100644 --- a/content/browser/webui/url_data_manager.cc +++ b/content/browser/webui/url_data_manager.cc @@ -9,38 +9,35 @@ #include "base/bind.h" #include "base/lazy_instance.h" #include "base/memory/ref_counted_memory.h" -#include "base/memory/scoped_ptr.h" #include "base/message_loop.h" #include "base/string_util.h" #include "base/synchronization/lock.h" -#include "content/browser/webui/url_data_manager_backend.h" -#include "content/browser/webui/web_ui_data_source.h" #include "content/browser/resource_context_impl.h" +#include "content/browser/webui/url_data_manager_backend.h" +#include "content/browser/webui/url_data_source_impl.h" +#include "content/browser/webui/web_ui_data_source_impl.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/url_data_source.h" -using content::BrowserContext; -using content::BrowserThread; - +namespace content { namespace { const char kURLDataManagerKeyName[] = "url_data_manager"; base::LazyInstance<base::Lock>::Leaky g_delete_lock = LAZY_INSTANCE_INITIALIZER; -ChromeURLDataManager* GetFromBrowserContext(BrowserContext* context) { +URLDataManager* GetFromBrowserContext(BrowserContext* context) { if (!context->GetUserData(kURLDataManagerKeyName)) { - context->SetUserData(kURLDataManagerKeyName, - new ChromeURLDataManager(context)); + context->SetUserData(kURLDataManagerKeyName, new URLDataManager(context)); } - return static_cast<ChromeURLDataManager*>( + return static_cast<URLDataManager*>( context->GetUserData(kURLDataManagerKeyName)); } // Invoked on the IO thread to do the actual adding of the DataSource. static void AddDataSourceOnIOThread( - content::ResourceContext* resource_context, + ResourceContext* resource_context, scoped_refptr<URLDataSourceImpl> data_source) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); GetURLDataManagerForResourceContext(resource_context)->AddDataSource( @@ -49,20 +46,17 @@ static void AddDataSourceOnIOThread( } // namespace - // static -ChromeURLDataManager::URLDataSources* ChromeURLDataManager::data_sources_ = - NULL; +URLDataManager::URLDataSources* URLDataManager::data_sources_ = NULL; -ChromeURLDataManager::ChromeURLDataManager( - content::BrowserContext* browser_context) +URLDataManager::URLDataManager(BrowserContext* browser_context) : browser_context_(browser_context) { } -ChromeURLDataManager::~ChromeURLDataManager() { +URLDataManager::~URLDataManager() { } -void ChromeURLDataManager::AddDataSource(URLDataSourceImpl* source) { +void URLDataManager::AddDataSource(URLDataSourceImpl* source) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, @@ -72,7 +66,7 @@ void ChromeURLDataManager::AddDataSource(URLDataSourceImpl* source) { } // static -void ChromeURLDataManager::DeleteDataSources() { +void URLDataManager::DeleteDataSources() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); URLDataSources sources; { @@ -86,8 +80,7 @@ void ChromeURLDataManager::DeleteDataSources() { } // static -void ChromeURLDataManager::DeleteDataSource( - const URLDataSourceImpl* data_source) { +void URLDataManager::DeleteDataSource(const URLDataSourceImpl* data_source) { // Invoked when a DataSource is no longer referenced and needs to be deleted. if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { // We're on the UI thread, delete right away. @@ -109,28 +102,26 @@ void ChromeURLDataManager::DeleteDataSource( // Schedule a task to delete the DataSource back on the UI thread. BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, - base::Bind(&ChromeURLDataManager::DeleteDataSources)); + base::Bind(&URLDataManager::DeleteDataSources)); } } // static -void ChromeURLDataManager::AddDataSource( - content::BrowserContext* browser_context, - content::URLDataSource* source) { +void URLDataManager::AddDataSource(BrowserContext* browser_context, + URLDataSource* source) { GetFromBrowserContext(browser_context)-> AddDataSource(new URLDataSourceImpl(source->GetSource(), source)); } // static -void ChromeURLDataManager::AddWebUIDataSource( - content::BrowserContext* browser_context, - content::WebUIDataSource* source) { - ChromeWebUIDataSource* impl = static_cast<ChromeWebUIDataSource*>(source); +void URLDataManager::AddWebUIDataSource(BrowserContext* browser_context, + WebUIDataSource* source) { + WebUIDataSourceImpl* impl = static_cast<WebUIDataSourceImpl*>(source); GetFromBrowserContext(browser_context)->AddDataSource(impl); } // static -bool ChromeURLDataManager::IsScheduledForDeletion( +bool URLDataManager::IsScheduledForDeletion( const URLDataSourceImpl* data_source) { base::AutoLock lock(g_delete_lock.Get()); if (!data_sources_) @@ -139,45 +130,4 @@ bool ChromeURLDataManager::IsScheduledForDeletion( data_sources_->end(); } -URLDataSourceImpl::URLDataSourceImpl(const std::string& source_name, - content::URLDataSource* source) - : source_name_(source_name), - backend_(NULL), - source_(source) { -} - -URLDataSourceImpl::~URLDataSourceImpl() { -} - -void URLDataSourceImpl::SendResponse( - int request_id, - base::RefCountedMemory* bytes) { - // Take a ref-pointer on entry so byte->Release() will always get called. - scoped_refptr<base::RefCountedMemory> bytes_ptr(bytes); - if (ChromeURLDataManager::IsScheduledForDeletion(this)) { - // We're scheduled for deletion. Servicing the request would result in - // this->AddRef being invoked, even though the ref count is 0 and 'this' is - // about to be deleted. If the AddRef were allowed through, when 'this' is - // released it would be deleted again. - // - // This scenario occurs with DataSources that make history requests. Such - // DataSources do a history query in |StartDataRequest| and the request is - // live until the object is deleted (history requests don't up the ref - // count). This means it's entirely possible for the DataSource to invoke - // |SendResponse| between the time when there are no more refs and the time - // when the object is deleted. - return; - } - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&URLDataSourceImpl::SendResponseOnIOThread, this, request_id, - bytes_ptr)); -} - -void URLDataSourceImpl::SendResponseOnIOThread( - int request_id, - scoped_refptr<base::RefCountedMemory> bytes) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - if (backend_) - backend_->DataAvailable(request_id, bytes); -} +} // namespace content diff --git a/content/browser/webui/url_data_manager.h b/content/browser/webui/url_data_manager.h index bb4c7a2..e94568d 100644 --- a/content/browser/webui/url_data_manager.h +++ b/content/browser/webui/url_data_manager.h @@ -9,37 +9,24 @@ #include <vector> #include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/sequenced_task_runner_helpers.h" #include "base/supports_user_data.h" -#include "base/synchronization/lock.h" #include "content/common/content_export.h" -class ChromeURLDataManagerBackend; -class MessageLoop; - -namespace base { -class RefCountedMemory; -} - namespace content { class BrowserContext; class URLDataSource; -class WebUIDataSource; -} - class URLDataSourceImpl; +class WebUIDataSource; // To serve dynamic data off of chrome: URLs, implement the -// ChromeURLDataManager::DataSource interface and register your handler +// URLDataManager::DataSource interface and register your handler // with AddDataSource. DataSources must be added on the UI thread (they are also // deleted on the UI thread). Internally the DataSources are maintained by -// ChromeURLDataManagerBackend, see it for details. -class CONTENT_EXPORT ChromeURLDataManager - : public base::SupportsUserData::Data { +// URLDataManagerBackend, see it for details. +class CONTENT_EXPORT URLDataManager : public base::SupportsUserData::Data { public: - explicit ChromeURLDataManager(content::BrowserContext* browser_context); - virtual ~ChromeURLDataManager(); + explicit URLDataManager(BrowserContext* browser_context); + virtual ~URLDataManager(); // Adds a DataSource to the collection of data sources. This *must* be invoked // on the UI thread. @@ -58,16 +45,14 @@ class CONTENT_EXPORT ChromeURLDataManager static void DeleteDataSources(); // Convenience wrapper function to add |source| to |browser_context|'s - // |ChromeURLDataManager|. Creates a URLDataSourceImpl to wrap the given + // |URLDataManager|. Creates a URLDataSourceImpl to wrap the given // source. - static void AddDataSource( - content::BrowserContext* browser_context, - content::URLDataSource* source); + static void AddDataSource(BrowserContext* browser_context, + URLDataSource* source); - // Adds a WebUI data source to |browser_context|'s |ChromeURLDataManager|. - static void AddWebUIDataSource( - content::BrowserContext* browser_context, - content::WebUIDataSource* source); + // Adds a WebUI data source to |browser_context|'s |URLDataManager|. + static void AddWebUIDataSource(BrowserContext* browser_context, + WebUIDataSource* source); private: friend class URLDataSourceImpl; @@ -83,85 +68,15 @@ class CONTENT_EXPORT ChromeURLDataManager // was invoked). static bool IsScheduledForDeletion(const URLDataSourceImpl* data_source); - content::BrowserContext* browser_context_; + BrowserContext* browser_context_; // |data_sources_| that are no longer referenced and scheduled for deletion. // Protected by g_delete_lock in the .cc file. static URLDataSources* data_sources_; - DISALLOW_COPY_AND_ASSIGN(ChromeURLDataManager); -}; - -// Trait used to handle deleting a URLDataSource. Deletion happens on the UI -// thread. -// -// Implementation note: the normal shutdown sequence is for the UI loop to -// stop pumping events then the IO loop and thread are stopped. When the -// URLDataSources are no longer referenced (which happens when IO thread stops) -// they get added to the UI message loop for deletion. But because the UI loop -// has stopped by the time this happens the URLDataSources would be leaked. -// -// To make sure URLDataSources are properly deleted ChromeURLDataManager manages -// deletion of the URLDataSources. When a URLDataSource is no longer referenced -// it is added to |data_sources_| and a task is posted to the UI thread to -// handle the actual deletion. During shutdown |DeleteDataSources| is invoked so -// that all pending URLDataSources are properly deleted. -struct DeleteURLDataSource { - static void Destruct(const URLDataSourceImpl* data_source) { - ChromeURLDataManager::DeleteDataSource(data_source); - } + DISALLOW_COPY_AND_ASSIGN(URLDataManager); }; -// A URLDataSource is an object that can answer requests for data -// asynchronously. URLDataSources are collectively owned with refcounting smart -// pointers and should never be deleted on the IO thread, since their calls -// are handled almost always on the UI thread and there's a possibility of a -// data race. The |DeleteDataSource| trait above is used to enforce this. -class URLDataSourceImpl : public base::RefCountedThreadSafe< - URLDataSourceImpl, DeleteURLDataSource> { - public: - // See source_name_ below for docs on that parameter. Takes ownership of - // |source|. - URLDataSourceImpl(const std::string& source_name, - content::URLDataSource* source); - - // Report that a request has resulted in the data |bytes|. - // If the request can't be satisfied, pass NULL for |bytes| to indicate - // the request is over. - virtual void SendResponse(int request_id, base::RefCountedMemory* bytes); - - const std::string& source_name() const { return source_name_; } - content::URLDataSource* source() const { return source_.get(); } - - protected: - virtual ~URLDataSourceImpl(); - - private: - friend class ChromeURLDataManagerBackend; - friend class ChromeURLDataManager; - friend class base::DeleteHelper<URLDataSourceImpl>; - - // SendResponse invokes this on the IO thread. Notifies the backend to - // handle the actual work of sending the data. - virtual void SendResponseOnIOThread( - int request_id, - scoped_refptr<base::RefCountedMemory> bytes); - - // The name of this source. - // E.g., for favicons, this could be "favicon", which results in paths for - // specific resources like "favicon/34" getting sent to this source. - const std::string source_name_; - - // This field is set and maintained by ChromeURLDataManagerBackend. It is - // set when the DataSource is added, and unset if the DataSource is removed. - // A DataSource can be removed in two ways: the ChromeURLDataManagerBackend - // is deleted, or another DataSource is registered with the same - // name. backend_ should only be accessed on the IO thread. - // This reference can't be via a scoped_refptr else there would be a cycle - // between the backend and data source. - ChromeURLDataManagerBackend* backend_; - - scoped_ptr<content::URLDataSource> source_; -}; +} // namespace content #endif // CONTENT_BROWSER_WEBUI_URL_DATA_MANAGER_H_ diff --git a/content/browser/webui/url_data_manager_backend.cc b/content/browser/webui/url_data_manager_backend.cc index 45f7d4a..f5fdd6b 100644 --- a/content/browser/webui/url_data_manager_backend.cc +++ b/content/browser/webui/url_data_manager_backend.cc @@ -19,6 +19,7 @@ #include "base/message_loop.h" #include "base/string_util.h" #include "content/browser/webui/shared_resources_data_source.h" +#include "content/browser/webui/url_data_source_impl.h" #include "content/public/browser/browser_thread.h" #include "content/public/common/url_constants.h" #include "googleurl/src/url_util.h" @@ -30,7 +31,7 @@ #include "net/url_request/url_request_job.h" #include "net/url_request/url_request_job_factory.h" -using content::BrowserThread; +namespace content { namespace { @@ -79,7 +80,7 @@ class URLRequestChromeJob : public net::URLRequestJob, // |is_incognito| set when job is generated from an incognito profile. URLRequestChromeJob(net::URLRequest* request, net::NetworkDelegate* network_delegate, - ChromeURLDataManagerBackend* backend, + URLDataManagerBackend* backend, bool is_incognito); // net::URLRequestJob implementation. @@ -169,7 +170,7 @@ class URLRequestChromeJob : public net::URLRequestJob, const bool is_incognito_; // The backend is owned by ChromeURLRequestContext and always outlives us. - ChromeURLDataManagerBackend* backend_; + URLDataManagerBackend* backend_; base::WeakPtrFactory<URLRequestChromeJob> weak_factory_; @@ -178,7 +179,7 @@ class URLRequestChromeJob : public net::URLRequestJob, URLRequestChromeJob::URLRequestChromeJob(net::URLRequest* request, net::NetworkDelegate* network_delegate, - ChromeURLDataManagerBackend* backend, + URLDataManagerBackend* backend, bool is_incognito) : net::URLRequestJob(request, network_delegate), data_offset_(0), @@ -332,7 +333,7 @@ class ChromeProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler { public: // |is_incognito| should be set for incognito profiles. - explicit ChromeProtocolHandler(ChromeURLDataManagerBackend* backend, + explicit ChromeProtocolHandler(URLDataManagerBackend* backend, bool is_incognito); ~ChromeProtocolHandler(); @@ -342,7 +343,7 @@ class ChromeProtocolHandler private: // These members are owned by ProfileIOData, which owns this ProtocolHandler. - ChromeURLDataManagerBackend* const backend_; + URLDataManagerBackend* const backend_; // True when generated from an incognito profile. const bool is_incognito_; @@ -351,7 +352,7 @@ class ChromeProtocolHandler }; ChromeProtocolHandler::ChromeProtocolHandler( - ChromeURLDataManagerBackend* backend, bool is_incognito) + URLDataManagerBackend* backend, bool is_incognito) : backend_(backend), is_incognito_(is_incognito) {} ChromeProtocolHandler::~ChromeProtocolHandler() {} @@ -367,15 +368,15 @@ net::URLRequestJob* ChromeProtocolHandler::MaybeCreateJob( } // namespace -ChromeURLDataManagerBackend::ChromeURLDataManagerBackend() +URLDataManagerBackend::URLDataManagerBackend() : next_request_id_(0) { - content::URLDataSource* shared_source = new SharedResourcesDataSource(); + URLDataSource* shared_source = new SharedResourcesDataSource(); URLDataSourceImpl* source_impl = new URLDataSourceImpl(shared_source->GetSource(), shared_source); AddDataSource(source_impl); } -ChromeURLDataManagerBackend::~ChromeURLDataManagerBackend() { +URLDataManagerBackend::~URLDataManagerBackend() { for (DataSourceMap::iterator i = data_sources_.begin(); i != data_sources_.end(); ++i) { i->second->backend_ = NULL; @@ -385,13 +386,13 @@ ChromeURLDataManagerBackend::~ChromeURLDataManagerBackend() { // static net::URLRequestJobFactory::ProtocolHandler* -ChromeURLDataManagerBackend::CreateProtocolHandler( - ChromeURLDataManagerBackend* backend, bool is_incognito) { +URLDataManagerBackend::CreateProtocolHandler( + URLDataManagerBackend* backend, bool is_incognito) { DCHECK(backend); return new ChromeProtocolHandler(backend, is_incognito); } -void ChromeURLDataManagerBackend::AddDataSource( +void URLDataManagerBackend::AddDataSource( URLDataSourceImpl* source) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DataSourceMap::iterator i = data_sources_.find(source->source_name()); @@ -404,7 +405,7 @@ void ChromeURLDataManagerBackend::AddDataSource( source->backend_ = this; } -bool ChromeURLDataManagerBackend::HasPendingJob( +bool URLDataManagerBackend::HasPendingJob( URLRequestChromeJob* job) const { for (PendingRequestMap::const_iterator i = pending_requests_.begin(); i != pending_requests_.end(); ++i) { @@ -414,8 +415,8 @@ bool ChromeURLDataManagerBackend::HasPendingJob( return false; } -bool ChromeURLDataManagerBackend::StartRequest(const GURL& url, - URLRequestChromeJob* job) { +bool URLDataManagerBackend::StartRequest(const GURL& url, + URLRequestChromeJob* job) { // Parse the URL into a request for a source and path. std::string source_name; std::string path; @@ -472,14 +473,14 @@ bool ChromeURLDataManagerBackend::StartRequest(const GURL& url, // usually the UI thread, for this path. target_message_loop->PostTask( FROM_HERE, - base::Bind(&ChromeURLDataManagerBackend::CallStartRequest, + base::Bind(&URLDataManagerBackend::CallStartRequest, make_scoped_refptr(source), path, job->is_incognito(), request_id)); } return true; } -void ChromeURLDataManagerBackend::CallStartRequest( +void URLDataManagerBackend::CallStartRequest( scoped_refptr<URLDataSourceImpl> source, const std::string& path, bool is_incognito, @@ -490,7 +491,7 @@ void ChromeURLDataManagerBackend::CallStartRequest( base::Bind(&URLDataSourceImpl::SendResponse, source, request_id)); } -void ChromeURLDataManagerBackend::RemoveRequest(URLRequestChromeJob* job) { +void URLDataManagerBackend::RemoveRequest(URLRequestChromeJob* job) { // Remove the request from our list of pending requests. // If/when the source sends the data that was requested, the data will just // be thrown away. @@ -503,8 +504,8 @@ void ChromeURLDataManagerBackend::RemoveRequest(URLRequestChromeJob* job) { } } -void ChromeURLDataManagerBackend::DataAvailable(RequestID request_id, - base::RefCountedMemory* bytes) { +void URLDataManagerBackend::DataAvailable(RequestID request_id, + base::RefCountedMemory* bytes) { // Forward this data on to the pending net::URLRequest, if it exists. PendingRequestMap::iterator i = pending_requests_.find(request_id); if (i != pending_requests_.end()) { @@ -520,7 +521,7 @@ class DevToolsJobFactory : public net::URLRequestJobFactory::ProtocolHandler { public: // |is_incognito| should be set for incognito profiles. - DevToolsJobFactory(ChromeURLDataManagerBackend* backend, + DevToolsJobFactory(URLDataManagerBackend* backend, bool is_incognito); virtual ~DevToolsJobFactory(); @@ -531,7 +532,7 @@ class DevToolsJobFactory private: // |backend_| and |network_delegate_| are owned by ProfileIOData, which owns // this ProtocolHandler. - ChromeURLDataManagerBackend* const backend_; + URLDataManagerBackend* const backend_; // True when generated from an incognito profile. const bool is_incognito_; @@ -539,7 +540,7 @@ class DevToolsJobFactory DISALLOW_COPY_AND_ASSIGN(DevToolsJobFactory); }; -DevToolsJobFactory::DevToolsJobFactory(ChromeURLDataManagerBackend* backend, +DevToolsJobFactory::DevToolsJobFactory(URLDataManagerBackend* backend, bool is_incognito) : backend_(backend), is_incognito_(is_incognito) { @@ -558,7 +559,9 @@ DevToolsJobFactory::MaybeCreateJob( } // namespace net::URLRequestJobFactory::ProtocolHandler* -CreateDevToolsProtocolHandler(ChromeURLDataManagerBackend* backend, +CreateDevToolsProtocolHandler(URLDataManagerBackend* backend, bool is_incognito) { return new DevToolsJobFactory(backend, is_incognito); } + +} // namespace content diff --git a/content/browser/webui/url_data_manager_backend.h b/content/browser/webui/url_data_manager_backend.h index 4c26ba6..a6c6fa2 100644 --- a/content/browser/webui/url_data_manager_backend.h +++ b/content/browser/webui/url_data_manager_backend.h @@ -15,34 +15,31 @@ #include "content/browser/webui/url_data_manager.h" #include "net/url_request/url_request_job_factory.h" -class ChromeURLDataManagerBackend; class GURL; -class URLRequestChromeJob; namespace base { class RefCountedMemory; } -namespace net { -class URLRequest; -class URLRequestJob; -} +namespace content { +class URLDataManagerBackend; +class URLDataSourceImpl; +class URLRequestChromeJob; -// ChromeURLDataManagerBackend is used internally by ChromeURLDataManager on the -// IO thread. In most cases you can use the API in ChromeURLDataManager and -// ignore this class. ChromeURLDataManagerBackend is owned by -// ChromeURLRequestContext. -class ChromeURLDataManagerBackend : public base::SupportsUserData::Data { +// URLDataManagerBackend is used internally by ChromeURLDataManager on the IO +// thread. In most cases you can use the API in ChromeURLDataManager and ignore +// this class. URLDataManagerBackend is owned by ResourceContext. +class URLDataManagerBackend : public base::SupportsUserData::Data { public: typedef int RequestID; - ChromeURLDataManagerBackend(); - virtual ~ChromeURLDataManagerBackend(); + URLDataManagerBackend(); + virtual ~URLDataManagerBackend(); // Invoked to create the protocol handler for chrome://. |is_incognito| should // be set for incognito profiles. static net::URLRequestJobFactory::ProtocolHandler* CreateProtocolHandler( - ChromeURLDataManagerBackend* backend, + URLDataManagerBackend* backend, bool is_incognito); // Adds a DataSource to the collection of data sources. @@ -92,13 +89,15 @@ class ChromeURLDataManagerBackend : public base::SupportsUserData::Data { // The ID we'll use for the next request we receive. RequestID next_request_id_; - DISALLOW_COPY_AND_ASSIGN(ChromeURLDataManagerBackend); + DISALLOW_COPY_AND_ASSIGN(URLDataManagerBackend); }; // Creates protocol handler for chrome-devtools://. |is_incognito| should be // set for incognito profiles. net::URLRequestJobFactory::ProtocolHandler* -CreateDevToolsProtocolHandler(ChromeURLDataManagerBackend* backend, +CreateDevToolsProtocolHandler(URLDataManagerBackend* backend, bool is_incognito); +} // namespace content + #endif // CONTENT_BROWSER_WEBUI_URL_DATA_MANAGER_BACKEND_H_ diff --git a/content/browser/webui/url_data_source_impl.cc b/content/browser/webui/url_data_source_impl.cc new file mode 100644 index 0000000..d206207 --- /dev/null +++ b/content/browser/webui/url_data_source_impl.cc @@ -0,0 +1,59 @@ +// 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 "content/browser/webui/url_data_source_impl.h" + +#include "base/bind.h" +#include "base/memory/ref_counted_memory.h" +#include "base/string_util.h" +#include "content/browser/webui/url_data_manager_backend.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/url_data_source.h" + +namespace content { + +URLDataSourceImpl::URLDataSourceImpl(const std::string& source_name, + URLDataSource* source) + : source_name_(source_name), + backend_(NULL), + source_(source) { +} + +URLDataSourceImpl::~URLDataSourceImpl() { +} + +void URLDataSourceImpl::SendResponse( + int request_id, + base::RefCountedMemory* bytes) { + // Take a ref-pointer on entry so byte->Release() will always get called. + scoped_refptr<base::RefCountedMemory> bytes_ptr(bytes); + if (URLDataManager::IsScheduledForDeletion(this)) { + // We're scheduled for deletion. Servicing the request would result in + // this->AddRef being invoked, even though the ref count is 0 and 'this' is + // about to be deleted. If the AddRef were allowed through, when 'this' is + // released it would be deleted again. + // + // This scenario occurs with DataSources that make history requests. Such + // DataSources do a history query in |StartDataRequest| and the request is + // live until the object is deleted (history requests don't up the ref + // count). This means it's entirely possible for the DataSource to invoke + // |SendResponse| between the time when there are no more refs and the time + // when the object is deleted. + return; + } + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&URLDataSourceImpl::SendResponseOnIOThread, this, request_id, + bytes_ptr)); +} + +void URLDataSourceImpl::SendResponseOnIOThread( + int request_id, + scoped_refptr<base::RefCountedMemory> bytes) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + if (backend_) + backend_->DataAvailable(request_id, bytes); +} + +} // namespace content diff --git a/content/browser/webui/url_data_source_impl.h b/content/browser/webui/url_data_source_impl.h new file mode 100644 index 0000000..4785b37 --- /dev/null +++ b/content/browser/webui/url_data_source_impl.h @@ -0,0 +1,97 @@ +// Copyright (c) 2013 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. + +#ifndef CONTENT_BROWSER_WEBUI_URL_DATA_SOURCE_IMPL_H_ +#define CONTENT_BROWSER_WEBUI_URL_DATA_SOURCE_IMPL_H_ + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/sequenced_task_runner_helpers.h" +#include "content/browser/webui/url_data_manager.h" +#include "content/common/content_export.h" + +namespace base { +class RefCountedMemory; +} + +namespace content { +class URLDataManagerBackend; +class URLDataSource; +class URLDataSourceImpl; + +// Trait used to handle deleting a URLDataSource. Deletion happens on the UI +// thread. +// +// Implementation note: the normal shutdown sequence is for the UI loop to +// stop pumping events then the IO loop and thread are stopped. When the +// URLDataSources are no longer referenced (which happens when IO thread stops) +// they get added to the UI message loop for deletion. But because the UI loop +// has stopped by the time this happens the URLDataSources would be leaked. +// +// To make sure URLDataSources are properly deleted URLDataManager manages +// deletion of the URLDataSources. When a URLDataSource is no longer referenced +// it is added to |data_sources_| and a task is posted to the UI thread to +// handle the actual deletion. During shutdown |DeleteDataSources| is invoked so +// that all pending URLDataSources are properly deleted. +struct DeleteURLDataSource { + static void Destruct(const URLDataSourceImpl* data_source) { + URLDataManager::DeleteDataSource(data_source); + } +}; + +// A URLDataSource is an object that can answer requests for data +// asynchronously. URLDataSources are collectively owned with refcounting smart +// pointers and should never be deleted on the IO thread, since their calls +// are handled almost always on the UI thread and there's a possibility of a +// data race. The |DeleteDataSource| trait above is used to enforce this. +class URLDataSourceImpl : public base::RefCountedThreadSafe< + URLDataSourceImpl, DeleteURLDataSource> { + public: + // See source_name_ below for docs on that parameter. Takes ownership of + // |source|. + URLDataSourceImpl(const std::string& source_name, + URLDataSource* source); + + // Report that a request has resulted in the data |bytes|. + // If the request can't be satisfied, pass NULL for |bytes| to indicate + // the request is over. + virtual void SendResponse(int request_id, base::RefCountedMemory* bytes); + + const std::string& source_name() const { return source_name_; } + URLDataSource* source() const { return source_.get(); } + + protected: + virtual ~URLDataSourceImpl(); + + private: + friend class URLDataManager; + friend class URLDataManagerBackend; + friend class base::DeleteHelper<URLDataSourceImpl>; + + // SendResponse invokes this on the IO thread. Notifies the backend to + // handle the actual work of sending the data. + virtual void SendResponseOnIOThread( + int request_id, + scoped_refptr<base::RefCountedMemory> bytes); + + // The name of this source. + // E.g., for favicons, this could be "favicon", which results in paths for + // specific resources like "favicon/34" getting sent to this source. + const std::string source_name_; + + // This field is set and maintained by URLDataManagerBackend. It is set when + // the DataSource is added, and unset if the DataSource is removed. A + // DataSource can be removed in two ways: the URLDataManagerBackend is + // deleted, or another DataSource is registered with the same name. backend_ + // should only be accessed on the IO thread. This reference can't be via a + // scoped_refptr else there would be a cycle between the backend and data + // source. + URLDataManagerBackend* backend_; + + scoped_ptr<URLDataSource> source_; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_WEBUI_URL_DATA_SOURCE_IMPL_H_ diff --git a/content/browser/webui/web_ui_data_source.cc b/content/browser/webui/web_ui_data_source_impl.cc index 5f580f2..c1ec030 100644 --- a/content/browser/webui/web_ui_data_source.cc +++ b/content/browser/webui/web_ui_data_source_impl.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/browser/webui/web_ui_data_source.h" +#include "content/browser/webui/web_ui_data_source_impl.h" #include <string> @@ -16,28 +16,25 @@ namespace content { WebUIDataSource* WebUIDataSource::Create(const std::string& source_name) { - return new ChromeWebUIDataSource(source_name); + return new WebUIDataSourceImpl(source_name); } void WebUIDataSource::Add(BrowserContext* browser_context, WebUIDataSource* source) { - ChromeURLDataManager::AddWebUIDataSource(browser_context, source); + URLDataManager::AddWebUIDataSource(browser_context, source); } -} // namespace content - -// Internal class to hide the fact that ChromeWebUIDataSource implements -// content::URLDataSource. -class ChromeWebUIDataSource::InternalDataSource - : public content::URLDataSource { +// Internal class to hide the fact that WebUIDataSourceImpl implements +// URLDataSource. +class WebUIDataSourceImpl::InternalDataSource : public URLDataSource { public: - InternalDataSource(ChromeWebUIDataSource* parent) : parent_(parent) { + InternalDataSource(WebUIDataSourceImpl* parent) : parent_(parent) { } ~InternalDataSource() { } - // content::URLDataSource implementation. + // URLDataSource implementation. virtual std::string GetSource() OVERRIDE { return parent_->GetSource(); } @@ -47,7 +44,7 @@ class ChromeWebUIDataSource::InternalDataSource virtual void StartDataRequest( const std::string& path, bool is_incognito, - const content::URLDataSource::GotDataCallback& callback) OVERRIDE { + const URLDataSource::GotDataCallback& callback) OVERRIDE { return parent_->StartDataRequest(path, is_incognito, callback); } virtual bool ShouldAddContentSecurityPolicy() const OVERRIDE { @@ -56,22 +53,22 @@ class ChromeWebUIDataSource::InternalDataSource virtual std::string GetContentSecurityPolicyObjectSrc() const OVERRIDE { if (parent_->object_src_set_) return parent_->object_src_; - return content::URLDataSource::GetContentSecurityPolicyObjectSrc(); + return URLDataSource::GetContentSecurityPolicyObjectSrc(); } virtual std::string GetContentSecurityPolicyFrameSrc() const OVERRIDE { if (parent_->frame_src_set_) return parent_->frame_src_; - return content::URLDataSource::GetContentSecurityPolicyFrameSrc(); + return URLDataSource::GetContentSecurityPolicyFrameSrc(); } virtual bool ShouldDenyXFrameOptions() const OVERRIDE { return parent_->deny_xframe_options_; } private: - ChromeWebUIDataSource* parent_; + WebUIDataSourceImpl* parent_; }; -ChromeWebUIDataSource::ChromeWebUIDataSource(const std::string& source_name) +WebUIDataSourceImpl::WebUIDataSourceImpl(const std::string& source_name) : URLDataSourceImpl( source_name, new InternalDataSource(ALLOW_THIS_IN_INITIALIZER_LIST(this))), @@ -85,81 +82,81 @@ ChromeWebUIDataSource::ChromeWebUIDataSource(const std::string& source_name) disable_set_font_strings_(false) { } -ChromeWebUIDataSource::~ChromeWebUIDataSource() { +WebUIDataSourceImpl::~WebUIDataSourceImpl() { } -void ChromeWebUIDataSource::AddString(const std::string& name, - const string16& value) { +void WebUIDataSourceImpl::AddString(const std::string& name, + const string16& value) { localized_strings_.SetString(name, value); } -void ChromeWebUIDataSource::AddString(const std::string& name, - const std::string& value) { +void WebUIDataSourceImpl::AddString(const std::string& name, + const std::string& value) { localized_strings_.SetString(name, value); } -void ChromeWebUIDataSource::AddLocalizedString(const std::string& name, - int ids) { +void WebUIDataSourceImpl::AddLocalizedString(const std::string& name, + int ids) { localized_strings_.SetString( - name, content::GetContentClient()->GetLocalizedString(ids)); + name, GetContentClient()->GetLocalizedString(ids)); } -void ChromeWebUIDataSource::AddLocalizedStrings( +void WebUIDataSourceImpl::AddLocalizedStrings( const DictionaryValue& localized_strings) { localized_strings_.MergeDictionary(&localized_strings); } -void ChromeWebUIDataSource::AddBoolean(const std::string& name, bool value) { +void WebUIDataSourceImpl::AddBoolean(const std::string& name, bool value) { localized_strings_.SetBoolean(name, value); } -void ChromeWebUIDataSource::SetJsonPath(const std::string& path) { +void WebUIDataSourceImpl::SetJsonPath(const std::string& path) { json_path_ = path; } -void ChromeWebUIDataSource::SetUseJsonJSFormatV2() { +void WebUIDataSourceImpl::SetUseJsonJSFormatV2() { json_js_format_v2_ = true; } -void ChromeWebUIDataSource::AddResourcePath(const std::string &path, - int resource_id) { +void WebUIDataSourceImpl::AddResourcePath(const std::string &path, + int resource_id) { path_to_idr_map_[path] = resource_id; } -void ChromeWebUIDataSource::SetDefaultResource(int resource_id) { +void WebUIDataSourceImpl::SetDefaultResource(int resource_id) { default_resource_ = resource_id; } -void ChromeWebUIDataSource::SetRequestFilter( - const content::WebUIDataSource::HandleRequestCallback& callback) { +void WebUIDataSourceImpl::SetRequestFilter( + const WebUIDataSource::HandleRequestCallback& callback) { filter_callback_ = callback; } -void ChromeWebUIDataSource::DisableContentSecurityPolicy() { +void WebUIDataSourceImpl::DisableContentSecurityPolicy() { add_csp_ = false; } -void ChromeWebUIDataSource::OverrideContentSecurityPolicyObjectSrc( +void WebUIDataSourceImpl::OverrideContentSecurityPolicyObjectSrc( const std::string& data) { object_src_set_ = true; object_src_ = data; } -void ChromeWebUIDataSource::OverrideContentSecurityPolicyFrameSrc( +void WebUIDataSourceImpl::OverrideContentSecurityPolicyFrameSrc( const std::string& data) { frame_src_set_ = true; frame_src_ = data; } -void ChromeWebUIDataSource::DisableDenyXFrameOptions() { +void WebUIDataSourceImpl::DisableDenyXFrameOptions() { deny_xframe_options_ = false; } -std::string ChromeWebUIDataSource::GetSource() { +std::string WebUIDataSourceImpl::GetSource() { return source_name_; } -std::string ChromeWebUIDataSource::GetMimeType(const std::string& path) const { +std::string WebUIDataSourceImpl::GetMimeType(const std::string& path) const { if (EndsWith(path, ".js", false)) return "application/javascript"; @@ -172,10 +169,10 @@ std::string ChromeWebUIDataSource::GetMimeType(const std::string& path) const { return "text/html"; } -void ChromeWebUIDataSource::StartDataRequest( +void WebUIDataSourceImpl::StartDataRequest( const std::string& path, bool is_incognito, - const content::URLDataSource::GotDataCallback& callback) { + const URLDataSource::GotDataCallback& callback) { if (!filter_callback_.is_null() && filter_callback_.Run(path, callback)) { return; @@ -195,8 +192,8 @@ void ChromeWebUIDataSource::StartDataRequest( SendFromResourceBundle(callback, resource_id); } -void ChromeWebUIDataSource::SendLocalizedStringsAsJSON( - const content::URLDataSource::GotDataCallback& callback) { +void WebUIDataSourceImpl::SendLocalizedStringsAsJSON( + const URLDataSource::GotDataCallback& callback) { std::string template_data; if (!disable_set_font_strings_) webui::SetFontAndTextDirection(&localized_strings_); @@ -209,9 +206,11 @@ void ChromeWebUIDataSource::SendLocalizedStringsAsJSON( callback.Run(base::RefCountedString::TakeString(&template_data)); } -void ChromeWebUIDataSource::SendFromResourceBundle( - const content::URLDataSource::GotDataCallback& callback, int idr) { +void WebUIDataSourceImpl::SendFromResourceBundle( + const URLDataSource::GotDataCallback& callback, int idr) { scoped_refptr<base::RefCountedStaticMemory> response( - content::GetContentClient()->GetDataResourceBytes(idr)); + GetContentClient()->GetDataResourceBytes(idr)); callback.Run(response); } + +} // namespace content diff --git a/content/browser/webui/web_ui_data_source.h b/content/browser/webui/web_ui_data_source_impl.h index 587eb9b..9553a03 100644 --- a/content/browser/webui/web_ui_data_source.h +++ b/content/browser/webui/web_ui_data_source_impl.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_BROWSER_WEBUI_WEB_UI_DATA_SOURCE_H_ -#define CONTENT_BROWSER_WEBUI_WEB_UI_DATA_SOURCE_H_ +#ifndef CONTENT_BROWSER_WEBUI_WEB_UI_DATA_SOURCE_IMPL_H_ +#define CONTENT_BROWSER_WEBUI_WEB_UI_DATA_SOURCE_IMPL_H_ #include <map> #include <string> @@ -13,22 +13,20 @@ #include "base/compiler_specific.h" #include "base/values.h" #include "content/browser/webui/url_data_manager.h" +#include "content/browser/webui/url_data_source_impl.h" #include "content/common/content_export.h" #include "content/public/browser/url_data_source.h" #include "content/public/browser/web_ui_data_source.h" namespace content { -class WebUIDataSource; -class WebUIDataSourceTest; -} // A data source that can help with implementing the common operations // needed by the chrome WEBUI settings/history/downloads pages. -class CONTENT_EXPORT ChromeWebUIDataSource +class CONTENT_EXPORT WebUIDataSourceImpl : public NON_EXPORTED_BASE(URLDataSourceImpl), - public NON_EXPORTED_BASE(content::WebUIDataSource) { + public NON_EXPORTED_BASE(WebUIDataSource) { public: - // content::WebUIDataSource implementation: + // WebUIDataSource implementation: virtual void AddString(const std::string& name, const string16& value) OVERRIDE; virtual void AddString(const std::string& name, @@ -43,7 +41,7 @@ class CONTENT_EXPORT ChromeWebUIDataSource int resource_id) OVERRIDE; virtual void SetDefaultResource(int resource_id) OVERRIDE; virtual void SetRequestFilter( - const content::WebUIDataSource::HandleRequestCallback& callback) OVERRIDE; + const WebUIDataSource::HandleRequestCallback& callback) OVERRIDE; virtual void DisableContentSecurityPolicy() OVERRIDE; virtual void OverrideContentSecurityPolicyObjectSrc( const std::string& data) OVERRIDE; @@ -52,32 +50,32 @@ class CONTENT_EXPORT ChromeWebUIDataSource virtual void DisableDenyXFrameOptions() OVERRIDE; protected: - virtual ~ChromeWebUIDataSource(); + virtual ~WebUIDataSourceImpl(); // Completes a request by sending our dictionary of localized strings. void SendLocalizedStringsAsJSON( - const content::URLDataSource::GotDataCallback& callback); + const URLDataSource::GotDataCallback& callback); // Completes a request by sending the file specified by |idr|. void SendFromResourceBundle( - const content::URLDataSource::GotDataCallback& callback, int idr); + const URLDataSource::GotDataCallback& callback, int idr); private: class InternalDataSource; friend class InternalDataSource; - friend class content::WebUIDataSource; - friend class content::WebUIDataSourceTest; + friend class WebUIDataSource; + friend class WebUIDataSourceTest; - explicit ChromeWebUIDataSource(const std::string& source_name); + explicit WebUIDataSourceImpl(const std::string& source_name); - // Methods that match content::URLDataSource which are called by + // Methods that match URLDataSource which are called by // InternalDataSource. std::string GetSource(); std::string GetMimeType(const std::string& path) const; void StartDataRequest( const std::string& path, bool is_incognito, - const content::URLDataSource::GotDataCallback& callback); + const URLDataSource::GotDataCallback& callback); void disable_set_font_strings_for_testing() { disable_set_font_strings_ = true; @@ -92,7 +90,7 @@ class CONTENT_EXPORT ChromeWebUIDataSource std::string json_path_; std::map<std::string, int> path_to_idr_map_; DictionaryValue localized_strings_; - content::WebUIDataSource::HandleRequestCallback filter_callback_; + WebUIDataSource::HandleRequestCallback filter_callback_; bool add_csp_; bool object_src_set_; std::string object_src_; @@ -101,7 +99,9 @@ class CONTENT_EXPORT ChromeWebUIDataSource bool deny_xframe_options_; bool disable_set_font_strings_; - DISALLOW_COPY_AND_ASSIGN(ChromeWebUIDataSource); + DISALLOW_COPY_AND_ASSIGN(WebUIDataSourceImpl); }; -#endif // CONTENT_BROWSER_WEBUI_WEB_UI_DATA_SOURCE_H_ +} // content + +#endif // CONTENT_BROWSER_WEBUI_WEB_UI_DATA_SOURCE_IMPL_H_ diff --git a/content/browser/webui/web_ui_data_source_unittest.cc b/content/browser/webui/web_ui_data_source_unittest.cc index a4429ef..b58161c 100644 --- a/content/browser/webui/web_ui_data_source_unittest.cc +++ b/content/browser/webui/web_ui_data_source_unittest.cc @@ -5,7 +5,7 @@ #include "base/bind.h" #include "base/memory/ref_counted_memory.h" #include "base/utf_string_conversions.h" -#include "content/browser/webui/web_ui_data_source.h" +#include "content/browser/webui/web_ui_data_source_impl.h" #include "content/test/test_content_client.h" #include "testing/gtest/include/gtest/gtest.h" @@ -54,7 +54,7 @@ class WebUIDataSourceTest : public testing::Test { public: WebUIDataSourceTest() : result_data_(NULL), old_client_(NULL) {} virtual ~WebUIDataSourceTest() {} - ChromeWebUIDataSource* source() { return source_.get(); } + WebUIDataSourceImpl* source() { return source_.get(); } void StartDataRequest(const std::string& path) { source_->StartDataRequest( @@ -74,8 +74,8 @@ class WebUIDataSourceTest : public testing::Test { virtual void SetUp() { old_client_ = GetContentClient(); SetContentClient(&client_); - WebUIDataSource* source = ChromeWebUIDataSource::Create("host"); - ChromeWebUIDataSource* source_impl = static_cast<ChromeWebUIDataSource*>( + WebUIDataSource* source = WebUIDataSourceImpl::Create("host"); + WebUIDataSourceImpl* source_impl = static_cast<WebUIDataSourceImpl*>( source); source_impl->disable_set_font_strings_for_testing(); source_ = make_scoped_refptr(source_impl); @@ -90,7 +90,7 @@ class WebUIDataSourceTest : public testing::Test { result_data_ = data; } - scoped_refptr<ChromeWebUIDataSource> source_; + scoped_refptr<WebUIDataSourceImpl> source_; TestClient client_; ContentClient* old_client_; }; |