tor-browser

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

SDBConnection.cpp (9802B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=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 file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "SDBConnection.h"
      8 
      9 // Local includes
     10 #include "ActorsChild.h"
     11 #include "SDBRequest.h"
     12 #include "SimpleDBCommon.h"
     13 
     14 // Global includes
     15 #include <stdint.h>
     16 
     17 #include <utility>
     18 
     19 #include "MainThreadUtils.h"
     20 #include "js/ArrayBuffer.h"
     21 #include "js/RootingAPI.h"
     22 #include "js/TypeDecls.h"
     23 #include "mozilla/Assertions.h"
     24 #include "mozilla/Preferences.h"
     25 #include "mozilla/RefPtr.h"
     26 #include "mozilla/dom/PBackgroundSDBConnection.h"
     27 #include "mozilla/dom/TypedArray.h"
     28 #include "mozilla/dom/quota/PrincipalUtils.h"
     29 #include "mozilla/fallible.h"
     30 #include "mozilla/ipc/BackgroundChild.h"
     31 #include "mozilla/ipc/BackgroundUtils.h"
     32 #include "mozilla/ipc/PBackgroundChild.h"
     33 #include "mozilla/ipc/PBackgroundSharedTypes.h"
     34 #include "nsDebug.h"
     35 #include "nsError.h"
     36 #include "nsISDBCallbacks.h"
     37 #include "nsISupportsUtils.h"
     38 #include "nsStringFwd.h"
     39 #include "nscore.h"
     40 
     41 namespace mozilla::dom {
     42 
     43 using namespace mozilla::ipc;
     44 
     45 namespace {
     46 
     47 template <typename BufferT>
     48 nsresult AppendDataToString(const BufferT& aBuffer, nsCString& aData) {
     49  return aBuffer.ProcessData(
     50      [&aData](const mozilla::Span<const uint8_t>& aSrcData,
     51               JS::AutoCheckCannotGC&&) {
     52        if (aSrcData.LengthBytes() > INT32_MAX) {
     53          return NS_ERROR_ILLEGAL_VALUE;
     54        }
     55        if (NS_WARN_IF(!aData.Append(aSrcData, fallible))) {
     56          return NS_ERROR_OUT_OF_MEMORY;
     57        }
     58        return NS_OK;
     59      });
     60 }
     61 
     62 nsresult GetWriteData(JSContext* aCx, JS::Handle<JS::Value> aValue,
     63                      nsCString& aData) {
     64  MOZ_ASSERT(aData.IsEmpty());
     65 
     66  if (!aValue.isObject()) {
     67    return NS_ERROR_NOT_IMPLEMENTED;
     68  }
     69 
     70  mozilla::dom::ArrayBufferView view;
     71  if (view.Init(&aValue.toObject())) {
     72    return AppendDataToString(view, aData);
     73  }
     74 
     75  mozilla::dom::ArrayBuffer arrayBuffer;
     76  if (arrayBuffer.Init(&aValue.toObject())) {
     77    return AppendDataToString(arrayBuffer, aData);
     78  }
     79 
     80  return NS_ERROR_NOT_IMPLEMENTED;
     81 }
     82 
     83 }  // namespace
     84 
     85 SDBConnection::SDBConnection()
     86    : mBackgroundActor(nullptr),
     87      mPersistenceType(quota::PERSISTENCE_TYPE_INVALID),
     88      mRunningRequest(false),
     89      mOpen(false),
     90      mAllowedToClose(false) {
     91  AssertIsOnOwningThread();
     92 }
     93 
     94 SDBConnection::~SDBConnection() {
     95  AssertIsOnOwningThread();
     96 
     97  if (mBackgroundActor) {
     98    mBackgroundActor->SendDeleteMeInternal();
     99    MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!");
    100  }
    101 }
    102 
    103 // static
    104 nsresult SDBConnection::Create(REFNSIID aIID, void** aResult) {
    105  MOZ_ASSERT(aResult);
    106 
    107  if (NS_WARN_IF(!Preferences::GetBool(kPrefSimpleDBEnabled, false))) {
    108    return NS_ERROR_NOT_AVAILABLE;
    109  }
    110 
    111  RefPtr<SDBConnection> connection = new SDBConnection();
    112 
    113  nsresult rv = connection->QueryInterface(aIID, aResult);
    114  if (NS_WARN_IF(NS_FAILED(rv))) {
    115    return rv;
    116  }
    117 
    118  return NS_OK;
    119 }
    120 
    121 void SDBConnection::ClearBackgroundActor() {
    122  AssertIsOnOwningThread();
    123 
    124  mBackgroundActor = nullptr;
    125 }
    126 
    127 void SDBConnection::OnNewRequest() {
    128  AssertIsOnOwningThread();
    129  MOZ_ASSERT(!mRunningRequest);
    130 
    131  mRunningRequest = true;
    132 }
    133 
    134 void SDBConnection::OnRequestFinished() {
    135  AssertIsOnOwningThread();
    136  MOZ_ASSERT(mRunningRequest);
    137 
    138  mRunningRequest = false;
    139 }
    140 
    141 void SDBConnection::OnOpen() {
    142  AssertIsOnOwningThread();
    143  MOZ_ASSERT(!mOpen);
    144 
    145  mOpen = true;
    146 }
    147 
    148 void SDBConnection::OnClose(bool aAbnormal) {
    149  AssertIsOnOwningThread();
    150  MOZ_ASSERT(mOpen);
    151 
    152  mOpen = false;
    153 
    154  if (aAbnormal) {
    155    MOZ_ASSERT(mAllowedToClose);
    156 
    157    if (mCloseCallback) {
    158      mCloseCallback->OnClose(this);
    159    }
    160  }
    161 }
    162 
    163 bool SDBConnection::IsAllowedToClose() const {
    164  AssertIsOnOwningThread();
    165 
    166  return mAllowedToClose;
    167 }
    168 
    169 void SDBConnection::AllowToClose() {
    170  AssertIsOnOwningThread();
    171 
    172  mAllowedToClose = true;
    173 }
    174 
    175 nsresult SDBConnection::CheckState() {
    176  AssertIsOnOwningThread();
    177 
    178  if (mAllowedToClose) {
    179    return NS_ERROR_ABORT;
    180  }
    181 
    182  if (mRunningRequest) {
    183    return NS_ERROR_NOT_AVAILABLE;
    184  }
    185 
    186  return NS_OK;
    187 }
    188 
    189 nsresult SDBConnection::EnsureBackgroundActor() {
    190  AssertIsOnOwningThread();
    191 
    192  if (mBackgroundActor) {
    193    return NS_OK;
    194  }
    195 
    196  PBackgroundChild* backgroundActor =
    197      BackgroundChild::GetOrCreateForCurrentThread();
    198  if (NS_WARN_IF(!backgroundActor)) {
    199    return NS_ERROR_FAILURE;
    200  }
    201 
    202  RefPtr<SDBConnectionChild> actor = new SDBConnectionChild(this);
    203 
    204  mBackgroundActor = static_cast<SDBConnectionChild*>(
    205      backgroundActor->SendPBackgroundSDBConnectionConstructor(
    206          actor, mPersistenceType, *mPrincipalInfo));
    207  if (NS_WARN_IF(!mBackgroundActor)) {
    208    return NS_ERROR_FAILURE;
    209  }
    210 
    211  return NS_OK;
    212 }
    213 
    214 nsresult SDBConnection::InitiateRequest(SDBRequest* aRequest,
    215                                        const SDBRequestParams& aParams) {
    216  AssertIsOnOwningThread();
    217  MOZ_ASSERT(aRequest);
    218  MOZ_ASSERT(mBackgroundActor);
    219 
    220  auto actor = new SDBRequestChild(aRequest);
    221 
    222  if (!mBackgroundActor->SendPBackgroundSDBRequestConstructor(actor, aParams)) {
    223    return NS_ERROR_FAILURE;
    224  }
    225 
    226  // Balanced in SDBRequestChild::Recv__delete__().
    227  OnNewRequest();
    228 
    229  return NS_OK;
    230 }
    231 
    232 NS_IMPL_ISUPPORTS(SDBConnection, nsISDBConnection)
    233 
    234 NS_IMETHODIMP
    235 SDBConnection::Init(nsIPrincipal* aPrincipal,
    236                    const nsACString& aPersistenceType) {
    237  MOZ_ASSERT(NS_IsMainThread());
    238  MOZ_ASSERT(aPrincipal);
    239 
    240  UniquePtr<PrincipalInfo> principalInfo(new PrincipalInfo());
    241  nsresult rv = PrincipalToPrincipalInfo(aPrincipal, principalInfo.get());
    242  if (NS_WARN_IF(NS_FAILED(rv))) {
    243    return rv;
    244  }
    245 
    246  if (principalInfo->type() != PrincipalInfo::TContentPrincipalInfo &&
    247      principalInfo->type() != PrincipalInfo::TSystemPrincipalInfo) {
    248    NS_WARNING("Simpledb not allowed for this principal!");
    249    return NS_ERROR_INVALID_ARG;
    250  }
    251 
    252  if (NS_WARN_IF(!quota::IsPrincipalInfoValid(*principalInfo))) {
    253    return NS_ERROR_INVALID_ARG;
    254  }
    255 
    256  PersistenceType persistenceType;
    257  if (aPersistenceType.IsVoid()) {
    258    persistenceType = quota::PERSISTENCE_TYPE_DEFAULT;
    259  } else {
    260    const auto maybePersistenceType =
    261        quota::PersistenceTypeFromString(aPersistenceType, fallible);
    262    if (NS_WARN_IF(maybePersistenceType.isNothing())) {
    263      return NS_ERROR_INVALID_ARG;
    264    }
    265 
    266    persistenceType = maybePersistenceType.value();
    267  }
    268 
    269  mPrincipalInfo = std::move(principalInfo);
    270  mPersistenceType = persistenceType;
    271 
    272  return NS_OK;
    273 }
    274 
    275 NS_IMETHODIMP
    276 SDBConnection::Open(const nsAString& aName, nsISDBRequest** _retval) {
    277  AssertIsOnOwningThread();
    278 
    279  nsresult rv = CheckState();
    280  if (NS_WARN_IF(NS_FAILED(rv))) {
    281    return rv;
    282  }
    283 
    284  if (mOpen) {
    285    return NS_ERROR_ALREADY_INITIALIZED;
    286  }
    287 
    288  SDBRequestOpenParams params;
    289  params.name() = aName;
    290 
    291  RefPtr<SDBRequest> request = new SDBRequest(this);
    292 
    293  rv = EnsureBackgroundActor();
    294  if (NS_WARN_IF(NS_FAILED(rv))) {
    295    return rv;
    296  }
    297 
    298  rv = InitiateRequest(request, params);
    299  if (NS_WARN_IF(NS_FAILED(rv))) {
    300    return rv;
    301  }
    302 
    303  request.forget(_retval);
    304  return NS_OK;
    305 }
    306 
    307 NS_IMETHODIMP
    308 SDBConnection::Seek(uint64_t aOffset, nsISDBRequest** _retval) {
    309  AssertIsOnOwningThread();
    310 
    311  nsresult rv = CheckState();
    312  if (NS_WARN_IF(NS_FAILED(rv))) {
    313    return rv;
    314  }
    315 
    316  if (!mOpen) {
    317    return NS_BASE_STREAM_CLOSED;
    318  }
    319 
    320  SDBRequestSeekParams params;
    321  params.offset() = aOffset;
    322 
    323  RefPtr<SDBRequest> request = new SDBRequest(this);
    324 
    325  rv = InitiateRequest(request, params);
    326  if (NS_WARN_IF(NS_FAILED(rv))) {
    327    return rv;
    328  }
    329 
    330  request.forget(_retval);
    331  return NS_OK;
    332 }
    333 
    334 NS_IMETHODIMP
    335 SDBConnection::Read(uint64_t aSize, nsISDBRequest** _retval) {
    336  AssertIsOnOwningThread();
    337 
    338  nsresult rv = CheckState();
    339  if (NS_WARN_IF(NS_FAILED(rv))) {
    340    return rv;
    341  }
    342 
    343  if (!mOpen) {
    344    return NS_BASE_STREAM_CLOSED;
    345  }
    346 
    347  SDBRequestReadParams params;
    348  params.size() = aSize;
    349 
    350  RefPtr<SDBRequest> request = new SDBRequest(this);
    351 
    352  rv = InitiateRequest(request, params);
    353  if (NS_WARN_IF(NS_FAILED(rv))) {
    354    return rv;
    355  }
    356 
    357  request.forget(_retval);
    358  return NS_OK;
    359 }
    360 
    361 NS_IMETHODIMP
    362 SDBConnection::Write(JS::Handle<JS::Value> aValue, JSContext* aCx,
    363                     nsISDBRequest** _retval) {
    364  AssertIsOnOwningThread();
    365 
    366  nsresult rv = CheckState();
    367  if (NS_WARN_IF(NS_FAILED(rv))) {
    368    return rv;
    369  }
    370 
    371  if (!mOpen) {
    372    return NS_BASE_STREAM_CLOSED;
    373  }
    374 
    375  JS::Rooted<JS::Value> value(aCx, aValue);
    376 
    377  nsCString data;
    378  rv = GetWriteData(aCx, value, data);
    379  if (NS_WARN_IF(NS_FAILED(rv))) {
    380    return rv;
    381  }
    382 
    383  SDBRequestWriteParams params;
    384  params.data() = data;
    385 
    386  RefPtr<SDBRequest> request = new SDBRequest(this);
    387 
    388  rv = InitiateRequest(request, params);
    389  if (NS_WARN_IF(NS_FAILED(rv))) {
    390    return rv;
    391  }
    392 
    393  request.forget(_retval);
    394  return NS_OK;
    395 }
    396 
    397 NS_IMETHODIMP
    398 SDBConnection::Close(nsISDBRequest** _retval) {
    399  AssertIsOnOwningThread();
    400 
    401  nsresult rv = CheckState();
    402  if (NS_WARN_IF(NS_FAILED(rv))) {
    403    return rv;
    404  }
    405 
    406  if (!mOpen) {
    407    return NS_BASE_STREAM_CLOSED;
    408  }
    409 
    410  SDBRequestCloseParams params;
    411 
    412  RefPtr<SDBRequest> request = new SDBRequest(this);
    413 
    414  rv = InitiateRequest(request, params);
    415  if (NS_WARN_IF(NS_FAILED(rv))) {
    416    return rv;
    417  }
    418 
    419  request.forget(_retval);
    420  return NS_OK;
    421 }
    422 
    423 NS_IMETHODIMP
    424 SDBConnection::GetCloseCallback(nsISDBCloseCallback** aCloseCallback) {
    425  AssertIsOnOwningThread();
    426  MOZ_ASSERT(aCloseCallback);
    427 
    428  NS_IF_ADDREF(*aCloseCallback = mCloseCallback);
    429  return NS_OK;
    430 }
    431 
    432 NS_IMETHODIMP
    433 SDBConnection::SetCloseCallback(nsISDBCloseCallback* aCloseCallback) {
    434  AssertIsOnOwningThread();
    435 
    436  mCloseCallback = aCloseCallback;
    437  return NS_OK;
    438 }
    439 
    440 }  // namespace mozilla::dom