tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

LocalStorageCommon.h (11624B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_dom_localstorage_LocalStorageCommon_h
      8 #define mozilla_dom_localstorage_LocalStorageCommon_h
      9 
     10 #include "ErrorList.h"
     11 #include "mozilla/Attributes.h"
     12 #include "mozilla/dom/quota/QuotaCommon.h"
     13 #include "nsLiteralString.h"
     14 #include "nsStringFwd.h"
     15 
     16 /*
     17 * Local storage
     18 * ~~~~~~~~~~~~~
     19 *
     20 * Implementation overview
     21 * ~~~~~~~~~~~~~~~~~~~~~~~
     22 *
     23 * The implementation is based on a per principal/origin cache (datastore)
     24 * living in the main process and synchronous calls initiated from content
     25 * processes.
     26 * The IPC communication is managed by database actors which link to the
     27 * datastore.
     28 * The synchronous blocking of the main thread is done by using a special
     29 * technique or by using standard synchronous IPC calls.
     30 *
     31 * General architecture
     32 * ~~~~~~~~~~~~~~~~~~~~
     33 * The current browser architecture consists of one main process and multiple
     34 * content processes (there are other processes but for simplicity's sake, they
     35 * are not mentioned here). The processes use the IPC communication to talk to
     36 * each other. Local storage implementation uses the client-server model, so
     37 * the main process manages all the data and content processes then request
     38 * particular data from the main process. The main process is also called the
     39 * parent or the parent side, the content process is then called the child or
     40 * the child side.
     41 *
     42 * Datastores
     43 * ~~~~~~~~~~
     44 *
     45 * A datastore provides a convenient way to access data for given origin. The
     46 * data is always preloaded into memory and indexed using a hash table. This
     47 * enables very fast access to particular stored items. There can be only one
     48 * datastore per origin and exists solely on the parent side. It is represented
     49 * by the "Datastore" class. A datastore instance is a ref counted object and
     50 * lives on the PBackground thread, it is kept alive by database objects. When
     51 * the last database object for given origin is destroyed, the associated
     52 * datastore object is destroyed too.
     53 *
     54 * Databases
     55 * ~~~~~~~~~
     56 *
     57 * A database allows direct access to a datastore from a content process. There
     58 * can be multiple databases for the same origin, but they all share the same
     59 * datastore.
     60 * Databases use the PBackgroundLSDatabase IPDL protocol for IPC communication.
     61 * Given the nature of local storage, most of PBackgroundLSDatabase messages
     62 * are synchronous.
     63 *
     64 * On the parent side, the database is represented by the "Database" class that
     65 * is a parent actor as well (implements the "PBackgroundLSDatabaseParent"
     66 * interface). A database instance is a ref counted object and lives on the
     67 * PBackground thread.
     68 * All live database actors are tracked in an array.
     69 *
     70 * On the child side, the database is represented by the "LSDatabase" class
     71 * that provides indirect access to a child actor. An LSDatabase instance is a
     72 * ref counted object and lives on the main thread.
     73 * The actual child actor is represented by the "LSDatabaseChild" class that
     74 * implements the "PBackgroundLSDatabaseChild" interface. An "LSDatabaseChild"
     75 * instance is not ref counted and lives on the main thread too.
     76 *
     77 * Synchronous blocking
     78 * ~~~~~~~~~~~~~~~~~~~~
     79 *
     80 * Local storage is synchronous in nature which means the execution can't move
     81 * forward until there's a reply for given method call.
     82 * Since we have to use IPC anyway, we could just always use synchronous IPC
     83 * messages for all local storage method calls. Well, there's a problem with
     84 * that approach.
     85 * If the main process needs to do some off PBackground thread stuff like
     86 * getting info from principals on the main thread or some asynchronous stuff
     87 * like directory locking before sending a reply to a synchronous message, then
     88 * we would have to block the thread or spin the event loop which is usually a
     89 * bad idea, especially in the main process.
     90 * Instead, we can use a special thread in the content process called
     91 * RemoteLazyInputStream thread for communication with the main process using
     92 * asynchronous messages and synchronously block the main thread until the DOM
     93 * File thread is done (the main thread blocking is a bit more complicated, see
     94 * the comment in RequestHelper::StartAndReturnResponse for more details).
     95 * Anyway, the extra hop to the RemoteLazyInputStream thread brings another
     96 * overhead and latency. The final solution is to use a combination of the
     97 * special thread for complex stuff like datastore preparation and synchronous
     98 * IPC messages sent directly from the main thread for database access when data
     99 * is already loaded from disk into memory.
    100 *
    101 * Requests
    102 * ~~~~~~~~
    103 *
    104 * Requests are used to handle asynchronous high level datastore operations
    105 * which are initiated in a content process and then processed in the parent
    106 * process (for example, preparation of a datastore).
    107 * Requests use the "PBackgroundLSRequest" IPDL protocol for IPC communication.
    108 *
    109 * On the parent side, the request is represented by the "LSRequestBase" class
    110 * that is a parent actor as well (implements the "PBackgroundLSRequestParent"
    111 * interface). It's an abstract class (contains pure virtual functions) so it
    112 * can't be used to create instances.
    113 * It also inherits from the "DatastoreOperationBase" class which is a generic
    114 * base class for all datastore operations. The "DatastoreOperationsBase" class
    115 * inherits from the "Runnable" class, so derived class instances are ref
    116 * counted, can be dispatched to multiple threads and thus they are used on
    117 * multiple threads. However, derived class instances can be created on the
    118 * PBackground thread only.
    119 *
    120 * On the child side, the request is represented by the "RequestHelper" class
    121 * that covers all the complexity needed to start a new request, handle
    122 * responses and do safe main thread blocking at the same time.
    123 * It inherits from the "Runnable" class, so instances are ref counted and
    124 * they are internally used on multiple threads (specifically on the main
    125 * thread and on the RemoteLazyInputStream thread). Anyway, users should create
    126 * and use instances of this class only on the main thread.
    127 * The actual child actor is represented by the "LSRequestChild" class that
    128 * implements the "PBackgroundLSRequestChild" interface. An "LSRequestChild"
    129 * instance is not ref counted and lives on the RemoteLazyInputStream thread.
    130 * Request responses are passed using the "LSRequestChildCallback" interface.
    131 *
    132 * Preparation of a datastore
    133 * ~~~~~~~~~~~~~~~~~~~~~~~~~~
    134 *
    135 * The datastore preparation is needed to make sure a datastore is fully loaded
    136 * into memory. Every datastore preparation produces a unique id (even if the
    137 * datastore for given origin already exists).
    138 * On the parent side, the preparation is handled by the "PrepareDatastoreOp"
    139 * class which inherits from the "LSRequestBase" class. The preparation process
    140 * on the parent side is quite complicated, it happens sequentially on multiple
    141 * threads and is managed by a state machine.
    142 * On the child side, the preparation is done in the LSObject::EnsureDatabase
    143 * method using the "RequestHelper" class. The method starts a new preparation
    144 * request and obtains a unique id produced by the parent (or an error code if
    145 * the requested failed to complete).
    146 *
    147 * Linking databases to a datastore
    148 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    149 *
    150 * A datastore exists only on the parent side, but it can be accessed from the
    151 * content via database actors. Database actors are initiated on the child side
    152 * and they need to be linked to a datastore on the parent side via an id. The
    153 * datastore preparation process gives us the required id.
    154 * The linking is initiated on the child side in the LSObject::EnsureDatabase
    155 * method by calling SendPBackgroundLSDatabaseConstructor and finished in
    156 * RecvPBackgroundLSDatabaseConstructor on the parent side.
    157 *
    158 * Actor migration
    159 * ~~~~~~~~~~~~~~~
    160 *
    161 * In theory, the datastore preparation request could return a database actor
    162 * directly (instead of returning an id intended for database linking to a
    163 * datastore). However, as it was explained above, the preparation must be done
    164 * on the RemoteLazyInputStream thread and database objects are used on the main
    165 * thread. The returned actor would have to be migrated from the
    166 * RemoteLazyInputStream thread to the main thread and that's something which
    167 * our IPDL doesn't support yet.
    168 *
    169 * Exposing local storage
    170 * ~~~~~~~~~~~~~~~~~~~~~~
    171 *
    172 * The implementation is exposed to the DOM via window.localStorage attribute.
    173 * Local storage's sibling, session storage shares the same WebIDL interface
    174 * for exposing it to web content, therefore there's an abstract class called
    175 * "Storage" that handles some of the common DOM bindings stuff. Local storage
    176 * specific functionality is defined in the "LSObject" derived class.
    177 * The "LSObject" class is also a starting point for the datastore preparation
    178 * and database linking.
    179 *
    180 * Local storage manager
    181 * ~~~~~~~~~~~~~~~~~~~~~
    182 *
    183 * The local storage manager exposes some of the features that need to be
    184 * available only in the chrome code or tests. The manager is represented by
    185 * the "LocalStorageManager2" class that implements the "nsIDOMStorageManager"
    186 * interface.
    187 */
    188 
    189 namespace mozilla {
    190 
    191 class LogModule;
    192 
    193 namespace ipc {
    194 
    195 class PrincipalInfo;
    196 
    197 }  // namespace ipc
    198 
    199 namespace dom {
    200 
    201 extern const char16_t* kLocalStorageType;
    202 
    203 /**
    204 * Convenience data-structure to make it easier to track whether a value has
    205 * changed and what its previous value was for notification purposes.  Instances
    206 * are created on the stack by LSObject and passed to LSDatabase which in turn
    207 * passes them onto LSSnapshot for final updating/population.  LSObject then
    208 * generates an event, if appropriate.
    209 */
    210 class MOZ_STACK_CLASS LSNotifyInfo {
    211  bool mChanged;
    212  nsString mOldValue;
    213 
    214 public:
    215  LSNotifyInfo() : mChanged(false) {}
    216 
    217  bool changed() const { return mChanged; }
    218 
    219  bool& changed() { return mChanged; }
    220 
    221  const nsString& oldValue() const { return mOldValue; }
    222 
    223  nsString& oldValue() { return mOldValue; }
    224 };
    225 
    226 /**
    227 * A check of LSNG being enabled, the value is latched once initialized so
    228 * changing the preference during runtime has no effect. May be called on any
    229 * thread in the parent process, but you should call
    230 * CachedNextGenLocalStorageEnabled if you know that NextGenLocalStorageEnabled
    231 * was already called because it is faster. May be called on any thread in
    232 * content processes, but you should call CachedNextGenLocalStorageEnabled
    233 * directly if you know you are in a content process because it is slightly
    234 * faster.
    235 */
    236 bool NextGenLocalStorageEnabled();
    237 
    238 /**
    239 * Called by ContentChild during content process initialization to initialize
    240 * the global variable in the content process with the latched value in the
    241 * parent process."
    242 */
    243 void RecvInitNextGenLocalStorageEnabled(const bool aEnabled);
    244 
    245 /**
    246 * Cached any-thread version of NextGenLocalStorageEnabled().
    247 */
    248 bool CachedNextGenLocalStorageEnabled();
    249 
    250 /**
    251 * Returns a success value containing a pair of origin attribute suffix and
    252 * origin key.
    253 */
    254 Result<std::pair<nsCString, nsCString>, nsresult> GenerateOriginKey2(
    255    const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
    256 
    257 LogModule* GetLocalStorageLogger();
    258 
    259 }  // namespace dom
    260 }  // namespace mozilla
    261 
    262 #endif  // mozilla_dom_localstorage_LocalStorageCommon_h