1// Copyright (c) 2012 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 CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_CONTEXT_IMPL_H_
6#define CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_CONTEXT_IMPL_H_
7
8#include <map>
9#include <set>
10#include <vector>
11
12#include "base/atomic_sequence_num.h"
13#include "base/basictypes.h"
14#include "base/files/file_path.h"
15#include "base/gtest_prod_util.h"
16#include "base/memory/ref_counted.h"
17#include "base/observer_list.h"
18#include "base/time/time.h"
19#include "content/browser/dom_storage/dom_storage_namespace.h"
20#include "content/common/content_export.h"
21#include "content/public/browser/session_storage_namespace.h"
22#include "url/gurl.h"
23
24namespace base {
25class FilePath;
26class NullableString16;
27class Time;
28}
29
30namespace storage {
31class SpecialStoragePolicy;
32}
33
34namespace content {
35
36class DOMStorageArea;
37class DOMStorageSession;
38class DOMStorageTaskRunner;
39class SessionStorageDatabase;
40struct LocalStorageUsageInfo;
41struct SessionStorageUsageInfo;
42
43// The Context is the root of an object containment hierachy for
44// Namespaces and Areas related to the owning profile.
45// One instance is allocated in the main process for each profile,
46// instance methods should be called serially in the background as
47// determined by the task_runner. Specifcally not on chrome's non-blocking
48// IO thread since these methods can result in blocking file io.
49//
50// In general terms, the DOMStorage object relationships are...
51//   Contexts (per-profile) own Namespaces which own Areas which share Maps.
52//   Hosts(per-renderer) refer to Namespaces and Areas open in its renderer.
53//   Sessions (per-tab) cause the creation and deletion of session Namespaces.
54//
55// Session Namespaces are cloned by initially making a shallow copy of
56// all contained Areas, the shallow copies refer to the same refcounted Map,
57// and does a deep copy-on-write if needed.
58//
59// Classes intended to be used by an embedder are DOMStorageContextImpl,
60// DOMStorageHost, and DOMStorageSession. The other classes are for
61// internal consumption.
62class CONTENT_EXPORT DOMStorageContextImpl
63    : public base::RefCountedThreadSafe<DOMStorageContextImpl> {
64 public:
65  // An interface for observing Local and Session Storage events on the
66  // background thread.
67  class EventObserver {
68   public:
69    // |old_value| may be null on initial insert.
70    virtual void OnDOMStorageItemSet(
71        const DOMStorageArea* area,
72        const base::string16& key,
73        const base::string16& new_value,
74        const base::NullableString16& old_value,
75        const GURL& page_url) = 0;
76    virtual void OnDOMStorageItemRemoved(
77        const DOMStorageArea* area,
78        const base::string16& key,
79        const base::string16& old_value,
80        const GURL& page_url) = 0;
81    virtual void OnDOMStorageAreaCleared(
82        const DOMStorageArea* area,
83        const GURL& page_url) = 0;
84    // Indicates that cached values of the DOM Storage provided must be
85    // cleared and retrieved again.
86    virtual void OnDOMSessionStorageReset(int64 namespace_id) = 0;
87
88   protected:
89    virtual ~EventObserver() {}
90  };
91
92  // |localstorage_directory| and |sessionstorage_directory| may be empty
93  // for incognito browser contexts.
94  DOMStorageContextImpl(const base::FilePath& localstorage_directory,
95                        const base::FilePath& sessionstorage_directory,
96                        storage::SpecialStoragePolicy* special_storage_policy,
97                        DOMStorageTaskRunner* task_runner);
98
99  // Returns the directory path for localStorage, or an empty directory, if
100  // there is no backing on disk.
101  const base::FilePath& localstorage_directory() {
102    return localstorage_directory_;
103  }
104
105  // Returns the directory path for sessionStorage, or an empty directory, if
106  // there is no backing on disk.
107  const base::FilePath& sessionstorage_directory() {
108    return sessionstorage_directory_;
109  }
110
111  DOMStorageTaskRunner* task_runner() const { return task_runner_.get(); }
112  DOMStorageNamespace* GetStorageNamespace(int64 namespace_id);
113
114  void GetLocalStorageUsage(std::vector<LocalStorageUsageInfo>* infos,
115                            bool include_file_info);
116  void GetSessionStorageUsage(std::vector<SessionStorageUsageInfo>* infos);
117  void DeleteLocalStorage(const GURL& origin);
118  void DeleteSessionStorage(const SessionStorageUsageInfo& usage_info);
119
120  // Used by content settings to alter the behavior around
121  // what data to keep and what data to discard at shutdown.
122  // The policy is not so straight forward to describe, see
123  // the implementation for details.
124  void SetForceKeepSessionState() {
125    force_keep_session_state_ = true;
126  }
127
128  // Called when the owning BrowserContext is ending.
129  // Schedules the commit of any unsaved changes and will delete
130  // and keep data on disk per the content settings and special storage
131  // policies. Contained areas and namespaces will stop functioning after
132  // this method has been called.
133  void Shutdown();
134
135  // Methods to add, remove, and notify EventObservers.
136  void AddEventObserver(EventObserver* observer);
137  void RemoveEventObserver(EventObserver* observer);
138
139  void NotifyItemSet(
140      const DOMStorageArea* area,
141      const base::string16& key,
142      const base::string16& new_value,
143      const base::NullableString16& old_value,
144      const GURL& page_url);
145  void NotifyItemRemoved(
146      const DOMStorageArea* area,
147      const base::string16& key,
148      const base::string16& old_value,
149      const GURL& page_url);
150  void NotifyAreaCleared(
151      const DOMStorageArea* area,
152      const GURL& page_url);
153  void NotifyAliasSessionMerged(
154      int64 namespace_id,
155      DOMStorageNamespace* old_alias_master_namespace);
156
157  // May be called on any thread.
158  int64 AllocateSessionId() {
159    return session_id_sequence_.GetNext();
160  }
161
162  std::string AllocatePersistentSessionId();
163
164  // Must be called on the background thread.
165  void CreateSessionNamespace(int64 namespace_id,
166                              const std::string& persistent_namespace_id);
167  void DeleteSessionNamespace(int64 namespace_id, bool should_persist_data);
168  void CloneSessionNamespace(int64 existing_id, int64 new_id,
169                             const std::string& new_persistent_id);
170  void CreateAliasSessionNamespace(int64 existing_id, int64 new_id,
171                                   const std::string& persistent_id);
172
173  // Starts backing sessionStorage on disk. This function must be called right
174  // after DOMStorageContextImpl is created, before it's used.
175  void SetSaveSessionStorageOnDisk();
176
177  // Deletes all namespaces which don't have an associated DOMStorageNamespace
178  // alive. This function is used for deleting possible leftover data after an
179  // unclean exit.
180  void StartScavengingUnusedSessionStorage();
181
182  void AddTransactionLogProcessId(int64 namespace_id, int process_id);
183  void RemoveTransactionLogProcessId(int64 namespace_id, int process_id);
184
185  SessionStorageNamespace::MergeResult MergeSessionStorage(
186      int64 namespace1_id, bool actually_merge, int process_id,
187      int64 namespace2_id);
188
189 private:
190  friend class DOMStorageContextImplTest;
191  FRIEND_TEST_ALL_PREFIXES(DOMStorageContextImplTest, Basics);
192  friend class base::RefCountedThreadSafe<DOMStorageContextImpl>;
193  typedef std::map<int64, scoped_refptr<DOMStorageNamespace> >
194      StorageNamespaceMap;
195
196  virtual ~DOMStorageContextImpl();
197
198  void ClearSessionOnlyOrigins();
199
200  void MaybeShutdownSessionNamespace(DOMStorageNamespace* ns);
201
202  // For scavenging unused sessionStorages.
203  void FindUnusedNamespaces();
204  void FindUnusedNamespacesInCommitSequence(
205      const std::set<std::string>& namespace_ids_in_use,
206      const std::set<std::string>& protected_persistent_session_ids);
207  void DeleteNextUnusedNamespace();
208  void DeleteNextUnusedNamespaceInCommitSequence();
209
210  // Collection of namespaces keyed by id.
211  StorageNamespaceMap namespaces_;
212
213  // Where localstorage data is stored, maybe empty for the incognito use case.
214  base::FilePath localstorage_directory_;
215
216  // Where sessionstorage data is stored, maybe empty for the incognito use
217  // case. Always empty until the file-backed session storage feature is
218  // implemented.
219  base::FilePath sessionstorage_directory_;
220
221  // Used to schedule sequenced background tasks.
222  scoped_refptr<DOMStorageTaskRunner> task_runner_;
223
224  // List of objects observing local storage events.
225  ObserverList<EventObserver> event_observers_;
226
227  // We use a 32 bit identifier for per tab storage sessions.
228  // At a tab per second, this range is large enough for 68 years.
229  base::AtomicSequenceNumber session_id_sequence_;
230
231  bool is_shutdown_;
232  bool force_keep_session_state_;
233  scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_;
234  scoped_refptr<SessionStorageDatabase> session_storage_database_;
235
236  // For cleaning up unused namespaces gradually.
237  bool scavenging_started_;
238  std::vector<std::string> deletable_persistent_namespace_ids_;
239
240  // Persistent namespace IDs to protect from gradual deletion (they will
241  // be needed for session restore).
242  std::set<std::string> protected_persistent_session_ids_;
243
244  // Mapping between persistent namespace IDs and namespace IDs for
245  // sessionStorage.
246  std::map<std::string, int64> persistent_namespace_id_to_namespace_id_;
247};
248
249}  // namespace content
250
251#endif  // CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_CONTEXT_IMPL_H_
252