tor-browser

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

mozStoragePrivateHelpers.cpp (8226B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
      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 #include "sqlite3.h"
      8 
      9 #include "jsfriendapi.h"
     10 
     11 #include "nsPrintfCString.h"
     12 #include "nsString.h"
     13 #include "nsError.h"
     14 #include "mozilla/Mutex.h"
     15 #include "mozilla/CondVar.h"
     16 #include "nsThreadUtils.h"
     17 #include "nsJSUtils.h"
     18 #include "nsIInterfaceRequestorUtils.h"
     19 
     20 #include "Variant.h"
     21 #include "mozStoragePrivateHelpers.h"
     22 #include "mozIStorageCompletionCallback.h"
     23 
     24 #include "mozilla/Logging.h"
     25 extern mozilla::LazyLogModule gStorageLog;
     26 
     27 namespace mozilla {
     28 namespace storage {
     29 
     30 bool isErrorCode(int aSQLiteResultCode) {
     31  // Drop off the extended result bits of the result code.
     32  int rc = aSQLiteResultCode & 0xFF;
     33 
     34  return rc != SQLITE_OK && rc != SQLITE_ROW && rc != SQLITE_DONE;
     35 }
     36 
     37 nsresult convertResultCode(int aSQLiteResultCode) {
     38  // Drop off the extended result bits of the result code.
     39  int rc = aSQLiteResultCode & 0xFF;
     40 
     41  switch (rc) {
     42    case SQLITE_OK:
     43    case SQLITE_ROW:
     44    case SQLITE_DONE:
     45      return NS_OK;
     46    case SQLITE_CORRUPT:
     47    case SQLITE_NOTADB:
     48      return NS_ERROR_FILE_CORRUPTED;
     49    case SQLITE_PERM:
     50    case SQLITE_CANTOPEN:
     51      return NS_ERROR_FILE_ACCESS_DENIED;
     52    case SQLITE_BUSY:
     53      return NS_ERROR_STORAGE_BUSY;
     54    case SQLITE_LOCKED:
     55      return NS_ERROR_FILE_IS_LOCKED;
     56    case SQLITE_READONLY:
     57      return NS_ERROR_FILE_READ_ONLY;
     58    case SQLITE_IOERR:
     59      return NS_ERROR_STORAGE_IOERR;
     60    case SQLITE_FULL:
     61    case SQLITE_TOOBIG:
     62      return NS_ERROR_FILE_NO_DEVICE_SPACE;
     63    case SQLITE_NOMEM:
     64      return NS_ERROR_OUT_OF_MEMORY;
     65    case SQLITE_MISUSE:
     66      return NS_ERROR_UNEXPECTED;
     67    case SQLITE_ABORT:
     68    case SQLITE_INTERRUPT:
     69      return NS_ERROR_ABORT;
     70    case SQLITE_CONSTRAINT:
     71      return NS_ERROR_STORAGE_CONSTRAINT;
     72  }
     73 
     74    // generic error
     75 #ifdef DEBUG
     76  nsAutoCString message;
     77  message.AppendLiteral("SQLite returned error code ");
     78  message.AppendInt(rc);
     79  message.AppendLiteral(" , Storage will convert it to NS_ERROR_FAILURE");
     80  NS_WARNING_ASSERTION(rc == SQLITE_ERROR, message.get());
     81 #endif
     82  return NS_ERROR_FAILURE;
     83 }
     84 
     85 void checkAndLogStatementPerformance(sqlite3_stmt* aStatement) {
     86  // Check to see if the query performed sorting operations or not.  If it
     87  // did, it may need to be optimized!
     88  int count = ::sqlite3_stmt_status(aStatement, SQLITE_STMTSTATUS_SORT, 1);
     89  if (count <= 0) return;
     90 
     91  const char* sql = ::sqlite3_sql(aStatement);
     92 
     93  // Check to see if this is marked to not warn
     94  if (::strstr(sql, "/* do not warn (bug ")) return;
     95 
     96  // CREATE INDEX always sorts (sorting is a necessary step in creating
     97  // an index).  So ignore the warning there.
     98  if (::strstr(sql, "CREATE INDEX") || ::strstr(sql, "CREATE UNIQUE INDEX")) {
     99    return;
    100  }
    101 
    102  nsAutoCString message("Suboptimal indexes for the SQL statement ");
    103 #ifdef MOZ_STORAGE_SORTWARNING_SQL_DUMP
    104  message.Append('`');
    105  message.Append(sql);
    106  message.AppendLiteral("` [");
    107  message.AppendInt(count);
    108  message.AppendLiteral(" sort operation(s)]");
    109 #else
    110  nsPrintfCString address("0x%p", aStatement);
    111  message.Append(address);
    112 #endif
    113  message.AppendLiteral(" (http://mzl.la/1FuID0j).");
    114  NS_WARNING(message.get());
    115 }
    116 
    117 nsIVariant* convertJSValToVariant(JSContext* aCtx, const JS::Value& aValue) {
    118  if (aValue.isInt32()) return new IntegerVariant(aValue.toInt32());
    119 
    120  if (aValue.isDouble()) return new FloatVariant(aValue.toDouble());
    121 
    122  if (aValue.isString()) {
    123    nsAutoJSString value;
    124    if (!value.init(aCtx, aValue.toString())) return nullptr;
    125    return new TextVariant(value);
    126  }
    127 
    128  if (aValue.isBoolean()) return new IntegerVariant(aValue.isTrue() ? 1 : 0);
    129 
    130  if (aValue.isNull()) return new NullVariant();
    131 
    132  if (aValue.isObject()) {
    133    JS::Rooted<JSObject*> obj(aCtx, &aValue.toObject());
    134    // We only support Date instances, all others fail.
    135    bool valid;
    136    if (!js::DateIsValid(aCtx, obj, &valid) || !valid) return nullptr;
    137 
    138    double msecd;
    139    if (!js::DateGetMsecSinceEpoch(aCtx, obj, &msecd)) return nullptr;
    140 
    141    msecd *= 1000.0;
    142    int64_t msec = msecd;
    143 
    144    return new IntegerVariant(msec);
    145  }
    146 
    147  return nullptr;
    148 }
    149 
    150 Variant_base* convertVariantToStorageVariant(nsIVariant* aVariant) {
    151  nsCOMPtr<nsIInterfaceRequestor> variant = do_QueryInterface(aVariant);
    152  if (variant) {
    153    // JS helpers already convert the JS representation to a Storage Variant,
    154    // in such a case there's nothing left to do here, so just pass-through.
    155    RefPtr<Variant_base> variantObj = do_GetInterface(variant);
    156    if (variantObj) {
    157      return variantObj;
    158    }
    159  }
    160 
    161  if (!aVariant) return new NullVariant();
    162 
    163  uint16_t dataType = aVariant->GetDataType();
    164 
    165  switch (dataType) {
    166    case nsIDataType::VTYPE_BOOL:
    167    case nsIDataType::VTYPE_INT8:
    168    case nsIDataType::VTYPE_INT16:
    169    case nsIDataType::VTYPE_INT32:
    170    case nsIDataType::VTYPE_UINT8:
    171    case nsIDataType::VTYPE_UINT16:
    172    case nsIDataType::VTYPE_UINT32:
    173    case nsIDataType::VTYPE_INT64:
    174    case nsIDataType::VTYPE_UINT64: {
    175      int64_t v;
    176      nsresult rv = aVariant->GetAsInt64(&v);
    177      NS_ENSURE_SUCCESS(rv, nullptr);
    178      return new IntegerVariant(v);
    179    }
    180    case nsIDataType::VTYPE_FLOAT:
    181    case nsIDataType::VTYPE_DOUBLE: {
    182      double v;
    183      nsresult rv = aVariant->GetAsDouble(&v);
    184      NS_ENSURE_SUCCESS(rv, nullptr);
    185      return new FloatVariant(v);
    186    }
    187    case nsIDataType::VTYPE_CHAR:
    188    case nsIDataType::VTYPE_CHAR_STR:
    189    case nsIDataType::VTYPE_STRING_SIZE_IS:
    190    case nsIDataType::VTYPE_UTF8STRING:
    191    case nsIDataType::VTYPE_CSTRING: {
    192      nsCString v;
    193      nsresult rv = aVariant->GetAsAUTF8String(v);
    194      NS_ENSURE_SUCCESS(rv, nullptr);
    195      return new UTF8TextVariant(v);
    196    }
    197    case nsIDataType::VTYPE_WCHAR:
    198    case nsIDataType::VTYPE_WCHAR_STR:
    199    case nsIDataType::VTYPE_WSTRING_SIZE_IS:
    200    case nsIDataType::VTYPE_ASTRING: {
    201      nsString v;
    202      nsresult rv = aVariant->GetAsAString(v);
    203      NS_ENSURE_SUCCESS(rv, nullptr);
    204      return new TextVariant(v);
    205    }
    206    case nsIDataType::VTYPE_EMPTY:
    207    case nsIDataType::VTYPE_EMPTY_ARRAY:
    208    case nsIDataType::VTYPE_VOID:
    209      return new NullVariant();
    210    case nsIDataType::VTYPE_ARRAY: {
    211      uint16_t type;
    212      nsIID iid;
    213      uint32_t len;
    214      void* rawArray;
    215      // Note this copies the array data.
    216      nsresult rv = aVariant->GetAsArray(&type, &iid, &len, &rawArray);
    217      NS_ENSURE_SUCCESS(rv, nullptr);
    218      if (type == nsIDataType::VTYPE_UINT8) {
    219        std::pair<uint8_t*, int> v(static_cast<uint8_t*>(rawArray), len);
    220        // Take ownership of the data avoiding a further copy.
    221        return new AdoptedBlobVariant(v);
    222      }
    223      // We don't convert other kind of arrays because it makes the API more
    224      // error prone, especially on the javascript side where it may not be
    225      // so uncommon to mistakenly pass an array instead of a primitive.
    226      // Consumers should instead use the dedicated `BindArrayOf` methods.
    227      [[fallthrough]];
    228    }
    229    case nsIDataType::VTYPE_ID:
    230    case nsIDataType::VTYPE_INTERFACE:
    231    case nsIDataType::VTYPE_INTERFACE_IS:
    232    default:
    233      NS_WARNING(
    234          nsPrintfCString("Unsupported variant type: %d", dataType).get());
    235      MOZ_ASSERT_UNREACHABLE("Tried to bind an unsupported Variant type");
    236      return nullptr;
    237  }
    238 }
    239 
    240 namespace {
    241 class CallbackEvent : public Runnable {
    242 public:
    243  explicit CallbackEvent(mozIStorageCompletionCallback* aCallback)
    244      : Runnable("storage::CallbackEvent"), mCallback(aCallback) {}
    245 
    246  NS_IMETHOD Run() override {
    247    (void)mCallback->Complete(NS_OK, nullptr);
    248    return NS_OK;
    249  }
    250 
    251 private:
    252  nsCOMPtr<mozIStorageCompletionCallback> mCallback;
    253 };
    254 }  // namespace
    255 already_AddRefed<nsIRunnable> newCompletionEvent(
    256    mozIStorageCompletionCallback* aCallback) {
    257  NS_ASSERTION(aCallback, "Passing a null callback is a no-no!");
    258  nsCOMPtr<nsIRunnable> event = new CallbackEvent(aCallback);
    259  return event.forget();
    260 }
    261 
    262 }  // namespace storage
    263 }  // namespace mozilla