1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_localstorage_LSObject_h
#define mozilla_dom_localstorage_LSObject_h
#include <cstdint>
#include "ErrorList.h"
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/Assertions.h"
#include "mozilla/Maybe.h"
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/dom/Storage.h"
#include "nsCycleCollectionParticipant.h"
#include "nsID.h"
#include "nsISupports.h"
#include "nsStringFwd.h"
#include "nsTArrayForwardDeclare.h"
class nsGlobalWindowInner;
class nsIEventTarget;
class nsIPrincipal;
class nsISerialEventTarget;
class nsPIDOMWindowInner;
namespace mozilla {
class ErrorResult;
namespace ipc {
class PrincipalInfo;
} // namespace ipc
namespace dom {
class LSDatabase;
class LSObjectChild;
class LSObserver;
class LSRequestChild;
class LSRequestChildCallback;
class LSRequestParams;
class LSRequestResponse;
/**
* Backs the WebIDL `Storage` binding; all content LocalStorage calls are
* handled by this class.
*
* ## Semantics under e10s / multi-process ##
*
* A snapshot mechanism used in conjuction with stable points ensures that JS
* run-to-completion semantics are experienced even if the same origin is
* concurrently accessing LocalStorage across multiple content processes.
*
* ### Snapshot Consistency ###
*
* An LSSnapshot is created locally whenever the contents of LocalStorage are
* about to be read or written (including length). This synchronously
* establishes a corresponding Snapshot in PBackground in the parent process.
* An effort is made to send as much data from the parent process as possible,
* so sites using a small/reasonable amount of LocalStorage data will have it
* sent to the content process for immediate access. Sites with greater
* LocalStorage usage may only have some of the information relayed. In that
* case, the parent Snapshot will ensure that it retains the exact state of the
* parent Datastore at the moment the Snapshot was created.
*/
class LSObject final : public Storage {
typedef mozilla::ipc::PrincipalInfo PrincipalInfo;
friend nsGlobalWindowInner;
UniquePtr<PrincipalInfo> mPrincipalInfo;
UniquePtr<PrincipalInfo> mStoragePrincipalInfo;
RefPtr<LSDatabase> mDatabase;
RefPtr<LSObserver> mObserver;
uint32_t mPrivateBrowsingId;
Maybe<nsID> mClientId;
nsCString mOrigin;
nsCString mOriginKey;
nsString mDocumentURI;
bool mInExplicitSnapshot;
public:
static void Initialize();
/**
* The normal creation path invoked by nsGlobalWindowInner.
*/
static nsresult CreateForWindow(nsPIDOMWindowInner* aWindow,
Storage** aStorage);
/**
* nsIDOMStorageManager creation path for use in testing logic. Supports the
* system principal where CreateForWindow does not. This is also why aPrivate
* exists separate from the principal; because the system principal can never
* be mutated to have a private browsing id even though it can be used in a
* window/document marked as private browsing. That's a legacy issue that is
* being dealt with, but it's why it exists here.
*/
static nsresult CreateForPrincipal(nsPIDOMWindowInner* aWindow,
nsIPrincipal* aPrincipal,
nsIPrincipal* aStoragePrincipal,
const nsAString& aDocumentURI,
bool aPrivate, LSObject** aObject);
/**
* Used for requests from the parent process to the parent process; in that
* case we want ActorsParent to know our event-target and this is better than
* trying to tunnel the pointer through IPC.
*/
static already_AddRefed<nsISerialEventTarget> GetSyncLoopEventTarget();
/**
* Helper invoked by ContentChild::OnChannelReceivedMessage when a sync IPC
* message is received. This will be invoked on the IPC I/O thread and it
* will set the gPendingSyncMessage flag to true. It will also force the sync
* loop (if it's active) to check the gPendingSyncMessage flag which will
* result in premature finish of the loop.
*
* This is necessary to unblock the main thread when a sync IPC message is
* received to avoid the potential for browser deadlock. This should only
* occur in (ugly) testing scenarios where CPOWs are in use.
*
* Aborted sync loop will result in the underlying LSRequest being explicitly
* canceled, resulting in the parent sending an NS_ERROR_FAILURE result.
*/
static void OnSyncMessageReceived();
/*
* Helper invoked by ContentChild::OnMessageReceived when a sync IPC message
* has been handled. This will be invoked on the main thread and it will
* set the gPendingSyncMessage flag to false.
*/
static void OnSyncMessageHandled();
void AssertIsOnOwningThread() const { NS_ASSERT_OWNINGTHREAD(LSObject); }
const nsString& DocumentURI() const { return mDocumentURI; }
LSRequestChild* StartRequest(nsIEventTarget* aMainEventTarget,
const LSRequestParams& aParams,
LSRequestChildCallback* aCallback);
// Storage overrides.
StorageType Type() const override;
bool IsForkOf(const Storage* aStorage) const override;
int64_t GetOriginQuotaUsage() const override;
uint32_t GetLength(nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
void Key(uint32_t aIndex, nsAString& aResult, nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
void GetItem(const nsAString& aKey, nsAString& aResult,
nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) override;
void GetSupportedNames(nsTArray<nsString>& aNames) override;
void SetItem(const nsAString& aKey, const nsAString& aValue,
nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) override;
void RemoveItem(const nsAString& aKey, nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
void Clear(nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) override;
//////////////////////////////////////////////////////////////////////////////
// Testing Methods: See Storage.h
void Open(nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) override;
void Close(nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) override;
void BeginExplicitSnapshot(nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
void EndExplicitSnapshot(nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
bool GetHasActiveSnapshot(nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
//////////////////////////////////////////////////////////////////////////////
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(LSObject, Storage)
private:
LSObject(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal,
nsIPrincipal* aStoragePrincipal);
~LSObject();
nsresult DoRequestSynchronously(const LSRequestParams& aParams,
LSRequestResponse& aResponse);
nsresult EnsureDatabase();
void DropDatabase();
/**
* Invoked by nsGlobalWindowInner whenever a new "storage" event listener is
* added to the window in order to ensure that "storage" events are received
* from other processes. (`LSObject::OnChange` directly invokes
* `Storage::NotifyChange` to notify in-process listeners.)
*
* If this is the first request in the process for an observer for this
* origin, this will trigger a RequestHelper-mediated synchronous LSRequest
* to prepare a new observer in the parent process and also construction of
* corresponding actors, which will result in the observer being fully
* registered in the parent process.
*/
nsresult EnsureObserver();
/**
* Invoked by nsGlobalWindowInner whenever its last "storage" event listener
* is removed.
*/
void DropObserver();
/**
* Internal helper method used by mutation methods that wraps the call to
* Storage::NotifyChange to generate same-process "storage" events.
*/
void OnChange(const nsAString& aKey, const nsAString& aOldValue,
const nsAString& aNewValue);
nsresult EndExplicitSnapshotInternal();
// Storage overrides.
void LastRelease() override;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_localstorage_LSObject_h
|