// Copyright (c) 2011 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 CHROME_BROWSER_UI_WEBUI_CHROME_URL_DATA_MANAGER_H_
#define CHROME_BROWSER_UI_WEBUI_CHROME_URL_DATA_MANAGER_H_
#pragma once
#include <string>
#include "base/memory/ref_counted.h"
#include "base/task.h"
#include "content/browser/browser_thread.h"
class ChromeURLDataManagerBackend;
class DictionaryValue;
class FilePath;
class MessageLoop;
class Profile;
class RefCountedMemory;
// To serve dynamic data off of chrome: URLs, implement the
// ChromeURLDataManager::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 ChromeURLDataManager {
public:
class DataSource;
// Trait used to handle deleting a DataSource. 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
// DataSources 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 DataSources would be leaked.
//
// To make sure DataSources are properly deleted ChromeURLDataManager manages
// deletion of the DataSources. When a DataSource 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 DataSources are properly deleted.
struct DeleteDataSource {
static void Destruct(const DataSource* data_source) {
ChromeURLDataManager::DeleteDataSource(data_source);
}
};
// A DataSource is an object that can answer requests for data
// asynchronously. DataSources 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.
//
// An implementation of DataSource should handle calls to
// StartDataRequest() by starting its (implementation-specific) asynchronous
// request for the data, then call SendResponse() to notify.
class DataSource : public base::RefCountedThreadSafe<
DataSource, DeleteDataSource> {
public:
// See source_name_ and message_loop_ below for docs on these parameters.
DataSource(const std::string& source_name, MessageLoop* message_loop);
// Sent by the DataManager to request data at |path|. The source should
// call SendResponse() when the data is available or if the request could
// not be satisfied.
virtual void StartDataRequest(const std::string& path,
bool is_incognito,
int request_id) = 0;
// Return the mimetype that should be sent with this response, or empty
// string to specify no mime type.
virtual std::string GetMimeType(const std::string& path) const = 0;
// 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, RefCountedMemory* bytes);
// Returns the MessageLoop on which the DataSource wishes to have
// StartDataRequest called to handle the request for |path|. If the
// DataSource does not care which thread StartDataRequest is called on,
// this should return NULL. The default implementation always returns
// message_loop_, which generally results in processing on the UI thread.
// It may be beneficial to return NULL for requests that are safe to handle
// directly on the IO thread. This can improve performance by satisfying
// such requests more rapidly when there is a large amount of UI thread
// contention.
virtual MessageLoop* MessageLoopForRequestPath(const std::string& path)
const;
const std::string& source_name() const { return source_name_; }
// Returns true if this DataSource should replace an existing DataSource
// with the same name that has already been registered. The default is
// true.
//
// WARNING: this is invoked on the IO thread.
//
// TODO: nuke this and convert all callers to not replace.
virtual bool ShouldReplaceExistingSource() const;
static void SetFontAndTextDirection(DictionaryValue* localized_strings);
protected:
virtual ~DataSource();
private:
friend class ChromeURLDataManagerBackend;
friend class ChromeURLDataManager;
friend class DeleteTask<DataSource>;
// 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<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_;
// The MessageLoop for the thread where this DataSource lives.
// Used to send messages to the DataSource.
MessageLoop* message_loop_;
// 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_;
};
explicit ChromeURLDataManager(Profile* profile);
~ChromeURLDataManager();
// Adds a DataSource to the collection of data sources. This *must* be invoked
// on the UI thread.
//
// If |AddDataSource| is called more than once for a particular name it will
// release the old |DataSource|, most likely resulting in it getting deleted
// as there are no other references to it. |DataSource| uses the
// |DeleteOnUIThread| trait to insure that the destructor is called on the UI
// thread. This is necessary as some |DataSource|s notably |FileIconSource|
// and |FaviconSource|, have members that will DCHECK if they are not
// destructed in the same thread as they are constructed (the UI thread).
void AddDataSource(DataSource* source);
// Deletes any data sources no longer referenced. This is normally invoked
// for you, but can be invoked to force deletion (such as during shutdown).
static void DeleteDataSources();
private:
typedef std::vector<const ChromeURLDataManager::DataSource*> DataSources;
// If invoked on the UI thread the DataSource is deleted immediatlye,
// otherwise it is added to |data_sources_| and a task is scheduled to handle
// deletion on the UI thread. See note abouve DeleteDataSource for more info.
static void DeleteDataSource(const DataSource* data_source);
// Returns true if |data_source| is scheduled for deletion (|DeleteDataSource|
// was invoked).
static bool IsScheduledForDeletion(const DataSource* data_source);
Profile* profile_;
// Lock used when accessing |data_sources_|.
static base::Lock delete_lock_;
// |data_sources_| that are no longer referenced and scheduled for deletion.
static DataSources* data_sources_;
DISALLOW_COPY_AND_ASSIGN(ChromeURLDataManager);
};
#endif // CHROME_BROWSER_UI_WEBUI_CHROME_URL_DATA_MANAGER_H_