1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_UI_WEBUI_CHROME_URL_DATA_MANAGER_H_
6#define CHROME_BROWSER_UI_WEBUI_CHROME_URL_DATA_MANAGER_H_
7#pragma once
8
9#include <string>
10
11#include "base/memory/ref_counted.h"
12#include "base/task.h"
13#include "content/browser/browser_thread.h"
14
15class ChromeURLDataManagerBackend;
16class DictionaryValue;
17class FilePath;
18class MessageLoop;
19class Profile;
20class RefCountedMemory;
21
22// To serve dynamic data off of chrome: URLs, implement the
23// ChromeURLDataManager::DataSource interface and register your handler
24// with AddDataSource. DataSources must be added on the UI thread (they are also
25// deleted on the UI thread). Internally the DataSources are maintained by
26// ChromeURLDataManagerBackend, see it for details.
27class ChromeURLDataManager {
28 public:
29  class DataSource;
30
31  // Trait used to handle deleting a DataSource. Deletion happens on the UI
32  // thread.
33  //
34  // Implementation note: the normal shutdown sequence is for the UI loop to
35  // stop pumping events then the IO loop and thread are stopped. When the
36  // DataSources are no longer referenced (which happens when IO thread stops)
37  // they get added to the UI message loop for deletion. But because the UI loop
38  // has stopped by the time this happens the DataSources would be leaked.
39  //
40  // To make sure DataSources are properly deleted ChromeURLDataManager manages
41  // deletion of the DataSources.  When a DataSource is no longer referenced it
42  // is added to |data_sources_| and a task is posted to the UI thread to handle
43  // the actual deletion. During shutdown |DeleteDataSources| is invoked so that
44  // all pending DataSources are properly deleted.
45  struct DeleteDataSource {
46    static void Destruct(const DataSource* data_source) {
47      ChromeURLDataManager::DeleteDataSource(data_source);
48    }
49  };
50
51  // A DataSource is an object that can answer requests for data
52  // asynchronously. DataSources are collectively owned with refcounting smart
53  // pointers and should never be deleted on the IO thread, since their calls
54  // are handled almost always on the UI thread and there's a possibility of a
55  // data race.  The |DeleteDataSource| trait above is used to enforce this.
56  //
57  // An implementation of DataSource should handle calls to
58  // StartDataRequest() by starting its (implementation-specific) asynchronous
59  // request for the data, then call SendResponse() to notify.
60  class DataSource : public base::RefCountedThreadSafe<
61      DataSource, DeleteDataSource> {
62   public:
63    // See source_name_ and message_loop_ below for docs on these parameters.
64    DataSource(const std::string& source_name, MessageLoop* message_loop);
65
66    // Sent by the DataManager to request data at |path|.  The source should
67    // call SendResponse() when the data is available or if the request could
68    // not be satisfied.
69    virtual void StartDataRequest(const std::string& path,
70                                  bool is_incognito,
71                                  int request_id) = 0;
72
73    // Return the mimetype that should be sent with this response, or empty
74    // string to specify no mime type.
75    virtual std::string GetMimeType(const std::string& path) const = 0;
76
77    // Report that a request has resulted in the data |bytes|.
78    // If the request can't be satisfied, pass NULL for |bytes| to indicate
79    // the request is over.
80    virtual void SendResponse(int request_id, RefCountedMemory* bytes);
81
82    // Returns the MessageLoop on which the DataSource wishes to have
83    // StartDataRequest called to handle the request for |path|.  If the
84    // DataSource does not care which thread StartDataRequest is called on,
85    // this should return NULL.  The default implementation always returns
86    // message_loop_, which generally results in processing on the UI thread.
87    // It may be beneficial to return NULL for requests that are safe to handle
88    // directly on the IO thread.  This can improve performance by satisfying
89    // such requests more rapidly when there is a large amount of UI thread
90    // contention.
91    virtual MessageLoop* MessageLoopForRequestPath(const std::string& path)
92        const;
93
94    const std::string& source_name() const { return source_name_; }
95
96    // Returns true if this DataSource should replace an existing DataSource
97    // with the same name that has already been registered. The default is
98    // true.
99    //
100    // WARNING: this is invoked on the IO thread.
101    //
102    // TODO: nuke this and convert all callers to not replace.
103    virtual bool ShouldReplaceExistingSource() const;
104
105    static void SetFontAndTextDirection(DictionaryValue* localized_strings);
106
107   protected:
108    virtual ~DataSource();
109
110   private:
111    friend class ChromeURLDataManagerBackend;
112    friend class ChromeURLDataManager;
113    friend class DeleteTask<DataSource>;
114
115    // SendResponse invokes this on the IO thread. Notifies the backend to
116    // handle the actual work of sending the data.
117    virtual void SendResponseOnIOThread(int request_id,
118                                        scoped_refptr<RefCountedMemory> bytes);
119
120    // The name of this source.
121    // E.g., for favicons, this could be "favicon", which results in paths for
122    // specific resources like "favicon/34" getting sent to this source.
123    const std::string source_name_;
124
125    // The MessageLoop for the thread where this DataSource lives.
126    // Used to send messages to the DataSource.
127    MessageLoop* message_loop_;
128
129    // This field is set and maintained by ChromeURLDataManagerBackend. It is
130    // set when the DataSource is added, and unset if the DataSource is removed.
131    // A DataSource can be removed in two ways: the ChromeURLDataManagerBackend
132    // is deleted, or another DataSource is registered with the same
133    // name. backend_ should only be accessed on the IO thread.
134    // This reference can't be via a scoped_refptr else there would be a cycle
135    // between the backend and data source.
136    ChromeURLDataManagerBackend* backend_;
137  };
138
139  explicit ChromeURLDataManager(Profile* profile);
140  ~ChromeURLDataManager();
141
142  // Adds a DataSource to the collection of data sources. This *must* be invoked
143  // on the UI thread.
144  //
145  // If |AddDataSource| is called more than once for a particular name it will
146  // release the old |DataSource|, most likely resulting in it getting deleted
147  // as there are no other references to it. |DataSource| uses the
148  // |DeleteOnUIThread| trait to insure that the destructor is called on the UI
149  // thread. This is necessary as some |DataSource|s notably |FileIconSource|
150  // and |FaviconSource|, have members that will DCHECK if they are not
151  // destructed in the same thread as they are constructed (the UI thread).
152  void AddDataSource(DataSource* source);
153
154  // Deletes any data sources no longer referenced. This is normally invoked
155  // for you, but can be invoked to force deletion (such as during shutdown).
156  static void DeleteDataSources();
157
158 private:
159  typedef std::vector<const ChromeURLDataManager::DataSource*> DataSources;
160
161  // If invoked on the UI thread the DataSource is deleted immediatlye,
162  // otherwise it is added to |data_sources_| and a task is scheduled to handle
163  // deletion on the UI thread. See note abouve DeleteDataSource for more info.
164  static void DeleteDataSource(const DataSource* data_source);
165
166  // Returns true if |data_source| is scheduled for deletion (|DeleteDataSource|
167  // was invoked).
168  static bool IsScheduledForDeletion(const DataSource* data_source);
169
170  Profile* profile_;
171
172  // Lock used when accessing |data_sources_|.
173  static base::Lock delete_lock_;
174
175  // |data_sources_| that are no longer referenced and scheduled for deletion.
176  static DataSources* data_sources_;
177
178  DISALLOW_COPY_AND_ASSIGN(ChromeURLDataManager);
179};
180
181#endif  // CHROME_BROWSER_UI_WEBUI_CHROME_URL_DATA_MANAGER_H_
182