Back to index

lightning-sunbird  0.9+nobinonly
nsDOMStorageDB.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Mozilla Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2006
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Neil Deakin <enndeakin@sympatico.ca>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsCOMPtr.h"
00040 #include "nsDOMError.h"
00041 #include "nsDOMStorage.h"
00042 #include "nsDOMStorageDB.h"
00043 #include "nsIFile.h"
00044 #include "nsAppDirectoryServiceDefs.h"
00045 #include "mozStorageCID.h"
00046 #include "mozStorageHelper.h"
00047 #include "mozIStorageService.h"
00048 #include "mozIStorageValueArray.h"
00049 
00050 nsresult
00051 nsDOMStorageDB::Init()
00052 {
00053   nsresult rv;
00054 
00055   nsCOMPtr<nsIFile> storageFile;
00056   rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
00057                               getter_AddRefs(storageFile));
00058   NS_ENSURE_SUCCESS(rv, rv);
00059   rv = storageFile->Append(NS_LITERAL_STRING("webappsstore.sqlite"));
00060   NS_ENSURE_SUCCESS(rv, rv);
00061 
00062   nsCOMPtr<mozIStorageService> service;
00063 
00064   service = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
00065   NS_ENSURE_SUCCESS(rv, rv);
00066   rv = service->OpenDatabase(storageFile, getter_AddRefs(mConnection));
00067   if (rv == NS_ERROR_FILE_CORRUPTED) {
00068     // delete the db and try opening again
00069     rv = storageFile->Remove(PR_FALSE);
00070     NS_ENSURE_SUCCESS(rv, rv);
00071     rv = service->OpenDatabase(storageFile, getter_AddRefs(mConnection));
00072   }
00073   NS_ENSURE_SUCCESS(rv, rv);
00074 
00075   PRBool exists;
00076   rv = mConnection->TableExists(NS_LITERAL_CSTRING("webappsstore"), &exists);
00077   NS_ENSURE_SUCCESS(rv, rv);
00078   if (! exists) {
00079     rv = mConnection->ExecuteSimpleSQL(
00080            NS_LITERAL_CSTRING("CREATE TABLE webappsstore ("
00081                               "domain TEXT, "
00082                               "key TEXT, "
00083                               "value TEXT, "
00084                               "secure INTEGER, "
00085                               "owner TEXT)"));
00086     NS_ENSURE_SUCCESS(rv, rv);
00087   }
00088   
00089   rv = mConnection->TableExists(NS_LITERAL_CSTRING("moz_webappsstore"),
00090                                 &exists);
00091   NS_ENSURE_SUCCESS(rv, rv);
00092 
00093   if (exists) {
00094       // upgrade an old store
00095       
00096       // create a temporary index to handle dup checking
00097        rv = mConnection->ExecuteSimpleSQL(
00098               NS_LITERAL_CSTRING("CREATE UNIQUE INDEX webappsstore_tmp "
00099                                  " ON webappsstore(domain, key)"));
00100 
00101       // if the index can't be created, there are dup domain/key combos
00102       // in moz_webappstore2, which indicates a bug elsewhere.  Fail to upgrade
00103       // in this case
00104       if (NS_SUCCEEDED(rv)) {
00105           rv = mConnection->ExecuteSimpleSQL(
00106                  NS_LITERAL_CSTRING("INSERT OR IGNORE INTO "
00107                                     "webappsstore(domain, key, value, secure, owner) "
00108                                     "SELECT domain, key, value, secure, domain "
00109                                     "FROM moz_webappsstore"));
00110 
00111           // try to drop the index even in case of an error
00112           mConnection->ExecuteSimpleSQL(
00113             NS_LITERAL_CSTRING("DROP INDEX webappsstore_tmp"));
00114 
00115           NS_ENSURE_SUCCESS(rv, rv);
00116 
00117           rv = mConnection->ExecuteSimpleSQL(
00118                  NS_LITERAL_CSTRING("DROP TABLE moz_webappsstore"));
00119           NS_ENSURE_SUCCESS(rv, rv);
00120       }
00121   }
00122   
00123   // retrieve all keys associated with a domain
00124   rv = mConnection->CreateStatement(
00125          NS_LITERAL_CSTRING("SELECT key, secure FROM webappsstore "
00126                             "WHERE domain = ?1"),
00127          getter_AddRefs(mGetAllKeysStatement));
00128   NS_ENSURE_SUCCESS(rv, rv);
00129 
00130   // retrieve a value given a domain and a key
00131   rv = mConnection->CreateStatement(
00132          NS_LITERAL_CSTRING("SELECT value, secure, owner FROM webappsstore "
00133                             "WHERE domain = ?1 "
00134                             "AND key = ?2"),
00135          getter_AddRefs(mGetKeyValueStatement));
00136   NS_ENSURE_SUCCESS(rv, rv);
00137 
00138   // insert a new key
00139   rv = mConnection->CreateStatement(
00140     NS_LITERAL_CSTRING("INSERT INTO "
00141                        "webappsstore(domain, key, value, secure, owner) "
00142                        "VALUES (?1, ?2, ?3, ?4, ?5)"),
00143          getter_AddRefs(mInsertKeyStatement));
00144   NS_ENSURE_SUCCESS(rv, rv);
00145 
00146   // update an existing key
00147   rv = mConnection->CreateStatement(
00148          NS_LITERAL_CSTRING("UPDATE webappsstore "
00149                             "SET value = ?1, secure = ?2, owner = ?3"
00150                             "WHERE domain = ?4 "
00151                             "AND key = ?5 "),
00152          getter_AddRefs(mUpdateKeyStatement));
00153   NS_ENSURE_SUCCESS(rv, rv);
00154 
00155   // update the secure status of an existing key
00156   rv = mConnection->CreateStatement(
00157          NS_LITERAL_CSTRING("UPDATE webappsstore "
00158                             "SET secure = ?1 "
00159                             "WHERE domain = ?2 "
00160                             "AND key = ?3 "),
00161          getter_AddRefs(mSetSecureStatement));
00162   NS_ENSURE_SUCCESS(rv, rv);
00163 
00164   // remove a key
00165   rv = mConnection->CreateStatement(
00166          NS_LITERAL_CSTRING("DELETE FROM webappsstore "
00167                             "WHERE domain = ?1 "
00168                             "AND key = ?2"),
00169          getter_AddRefs(mRemoveKeyStatement));
00170   NS_ENSURE_SUCCESS(rv, rv);
00171 
00172   // remove all keys
00173   rv = mConnection->CreateStatement(
00174          NS_LITERAL_CSTRING("DELETE FROM webappsstore"),
00175          getter_AddRefs(mRemoveAllStatement));
00176   NS_ENSURE_SUCCESS(rv, rv);
00177   
00178   // check the usage for a given owner
00179   rv = mConnection->CreateStatement(
00180          NS_LITERAL_CSTRING("SELECT SUM(LENGTH(key) + LENGTH(value)) "
00181                             "FROM webappsstore "
00182                             "WHERE owner = ?1"),
00183          getter_AddRefs(mGetUsageStatement));
00184 
00185   return rv;
00186 }
00187 
00188 nsresult
00189 nsDOMStorageDB::GetAllKeys(const nsAString& aDomain,
00190                            nsDOMStorage* aStorage,
00191                            nsTHashtable<nsSessionStorageEntry>* aKeys)
00192 {
00193   mozStorageStatementScoper scope(mGetAllKeysStatement);
00194 
00195   nsresult rv = mGetAllKeysStatement->BindStringParameter(0, aDomain);
00196   NS_ENSURE_SUCCESS(rv, rv);
00197 
00198   PRBool exists;
00199   while (NS_SUCCEEDED(rv = mGetAllKeysStatement->ExecuteStep(&exists)) &&
00200          exists) {
00201 
00202     nsAutoString key;
00203     rv = mGetAllKeysStatement->GetString(0, key);
00204     NS_ENSURE_SUCCESS(rv, rv);
00205 
00206     PRInt32 secureInt = 0;
00207     rv = mGetAllKeysStatement->GetInt32(1, &secureInt);
00208     NS_ENSURE_SUCCESS(rv, rv);
00209 
00210     nsSessionStorageEntry* entry = aKeys->PutEntry(key);
00211     NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
00212  
00213     entry->mItem = new nsDOMStorageItem(aStorage, key, EmptyString(), secureInt);
00214     if (!entry->mItem) {
00215       aKeys->RawRemoveEntry(entry);
00216       return NS_ERROR_OUT_OF_MEMORY;
00217     }
00218   }
00219 
00220   return NS_OK;
00221 }
00222 
00223 nsresult
00224 nsDOMStorageDB::GetKeyValue(const nsAString& aDomain,
00225                             const nsAString& aKey,
00226                             nsAString& aValue,
00227                             PRBool* aSecure,
00228                             nsAString& aOwner)
00229 {
00230   mozStorageStatementScoper scope(mGetKeyValueStatement);
00231 
00232   nsresult rv = mGetKeyValueStatement->BindStringParameter(0, aDomain);
00233   NS_ENSURE_SUCCESS(rv, rv);
00234   rv = mGetKeyValueStatement->BindStringParameter(1, aKey);
00235   NS_ENSURE_SUCCESS(rv, rv);
00236 
00237   PRBool exists;
00238   rv = mGetKeyValueStatement->ExecuteStep(&exists);
00239   NS_ENSURE_SUCCESS(rv, rv);
00240 
00241   PRInt32 secureInt = 0;
00242   if (exists) {
00243     rv = mGetKeyValueStatement->GetString(0, aValue);
00244     NS_ENSURE_SUCCESS(rv, rv);
00245 
00246     rv = mGetKeyValueStatement->GetInt32(1, &secureInt);
00247     NS_ENSURE_SUCCESS(rv, rv);
00248 
00249     rv = mGetKeyValueStatement->GetString(2, aOwner);
00250     NS_ENSURE_SUCCESS(rv, rv);
00251   }
00252   else {
00253     rv = NS_ERROR_DOM_NOT_FOUND_ERR;
00254   }
00255 
00256   *aSecure = (PRBool)secureInt;
00257 
00258   return rv;
00259 }
00260 
00261 nsresult
00262 nsDOMStorageDB::SetKey(const nsAString& aDomain,
00263                        const nsAString& aKey,
00264                        const nsAString& aValue,
00265                        PRBool aSecure,
00266                        const nsAString& aOwner,
00267                        PRInt32 aQuota)
00268 {
00269   mozStorageStatementScoper scope(mGetKeyValueStatement);
00270  
00271   PRInt32 usage = 0;
00272   nsresult rv;
00273   if (!aOwner.IsEmpty()) {
00274     if (aOwner == mCachedOwner) {
00275       usage = mCachedUsage;
00276     } else {
00277       rv = GetUsage(aOwner, &usage);
00278       NS_ENSURE_SUCCESS(rv, rv);
00279     }
00280   }
00281 
00282   usage += aKey.Length() + aValue.Length();
00283 
00284   rv = mGetKeyValueStatement->BindStringParameter(0, aDomain);
00285   NS_ENSURE_SUCCESS(rv, rv);
00286   rv = mGetKeyValueStatement->BindStringParameter(1, aKey);
00287   NS_ENSURE_SUCCESS(rv, rv);
00288 
00289   PRBool exists;
00290   rv = mGetKeyValueStatement->ExecuteStep(&exists);
00291   NS_ENSURE_SUCCESS(rv, rv);
00292 
00293   if (exists) {
00294     if (!aSecure) {
00295       PRInt32 secureInt = 0;
00296       rv = mGetKeyValueStatement->GetInt32(1, &secureInt);
00297       NS_ENSURE_SUCCESS(rv, rv);
00298       if (secureInt)
00299         return NS_ERROR_DOM_SECURITY_ERR;
00300     }
00301 
00302     nsAutoString previousOwner;
00303     rv = mGetKeyValueStatement->GetString(2, previousOwner);
00304     NS_ENSURE_SUCCESS(rv, rv);
00305     
00306     if (previousOwner == aOwner) {
00307       nsAutoString previousValue;
00308       rv = mGetKeyValueStatement->GetString(0, previousValue);
00309       NS_ENSURE_SUCCESS(rv, rv);
00310       usage -= aKey.Length() + previousValue.Length();
00311     }
00312 
00313     mGetKeyValueStatement->Reset();
00314 
00315     if (usage > aQuota) {
00316       return NS_ERROR_DOM_QUOTA_REACHED;
00317     }
00318 
00319     mozStorageStatementScoper scopeupdate(mUpdateKeyStatement);
00320 
00321     rv = mUpdateKeyStatement->BindStringParameter(0, aValue);
00322     NS_ENSURE_SUCCESS(rv, rv);
00323     rv = mUpdateKeyStatement->BindInt32Parameter(1, aSecure);
00324     NS_ENSURE_SUCCESS(rv, rv);
00325     rv = mUpdateKeyStatement->BindStringParameter(2, aOwner);
00326     NS_ENSURE_SUCCESS(rv, rv);
00327     rv = mUpdateKeyStatement->BindStringParameter(3, aDomain);
00328     NS_ENSURE_SUCCESS(rv, rv);
00329     rv = mUpdateKeyStatement->BindStringParameter(4, aKey);
00330     NS_ENSURE_SUCCESS(rv, rv);
00331 
00332     rv = mUpdateKeyStatement->Execute();
00333     NS_ENSURE_SUCCESS(rv, rv);
00334   }
00335   else {
00336     if (usage > aQuota) {
00337       return NS_ERROR_DOM_QUOTA_REACHED;
00338     }
00339     
00340     mozStorageStatementScoper scopeinsert(mInsertKeyStatement);
00341     
00342     rv = mInsertKeyStatement->BindStringParameter(0, aDomain);
00343     NS_ENSURE_SUCCESS(rv, rv);
00344     rv = mInsertKeyStatement->BindStringParameter(1, aKey);
00345     NS_ENSURE_SUCCESS(rv, rv);
00346     rv = mInsertKeyStatement->BindStringParameter(2, aValue);
00347     NS_ENSURE_SUCCESS(rv, rv);
00348     rv = mInsertKeyStatement->BindInt32Parameter(3, aSecure);
00349     NS_ENSURE_SUCCESS(rv, rv);
00350     rv = mInsertKeyStatement->BindStringParameter(4, aOwner);
00351     NS_ENSURE_SUCCESS(rv, rv);
00352     
00353     rv = mInsertKeyStatement->Execute();
00354     NS_ENSURE_SUCCESS(rv, rv);
00355   }
00356 
00357   if (!aOwner.IsEmpty()) {
00358     mCachedOwner = aOwner;
00359     mCachedUsage = usage;
00360   }
00361 
00362   return NS_OK;
00363 }
00364 
00365 nsresult
00366 nsDOMStorageDB::SetSecure(const nsAString& aDomain,
00367                           const nsAString& aKey,
00368                           const PRBool aSecure)
00369 {
00370   mozStorageStatementScoper scope(mGetKeyValueStatement);
00371 
00372   nsresult rv = mGetKeyValueStatement->BindStringParameter(0, aDomain);
00373   NS_ENSURE_SUCCESS(rv, rv);
00374   rv = mGetKeyValueStatement->BindStringParameter(1, aKey);
00375   NS_ENSURE_SUCCESS(rv, rv);
00376 
00377   PRBool exists;
00378   rv = mGetKeyValueStatement->ExecuteStep(&exists);
00379   NS_ENSURE_SUCCESS(rv, rv);
00380 
00381   if (exists) {
00382     mGetKeyValueStatement->Reset();
00383     
00384     mozStorageStatementScoper scopeupdate(mUpdateKeyStatement);
00385 
00386     rv = mSetSecureStatement->BindInt32Parameter(0, aSecure ? 1 : 0);
00387     NS_ENSURE_SUCCESS(rv, rv);
00388     rv = mSetSecureStatement->BindStringParameter(1, aDomain);
00389     NS_ENSURE_SUCCESS(rv, rv);
00390     rv = mSetSecureStatement->BindStringParameter(2, aKey);
00391     NS_ENSURE_SUCCESS(rv, rv);
00392 
00393     return mSetSecureStatement->Execute();
00394   }
00395 
00396   return NS_OK;
00397 }
00398 
00399 nsresult
00400 nsDOMStorageDB::RemoveKey(const nsAString& aDomain,
00401                           const nsAString& aKey,
00402                           const nsAString& aOwner,
00403                           PRInt32 aKeyUsage)
00404 {
00405   mozStorageStatementScoper scope(mRemoveKeyStatement);
00406 
00407   if (aOwner == mCachedOwner) {
00408     mCachedUsage -= aKeyUsage;
00409   }
00410 
00411   nsresult rv = mRemoveKeyStatement->BindStringParameter(0, aDomain);
00412   NS_ENSURE_SUCCESS(rv, rv);
00413   rv = mRemoveKeyStatement->BindStringParameter(1, aKey);
00414   NS_ENSURE_SUCCESS(rv, rv);
00415 
00416   return mRemoveKeyStatement->Execute();
00417 }
00418 
00419 nsresult
00420 nsDOMStorageDB::RemoveAll()
00421 {
00422   mozStorageStatementScoper scope(mRemoveAllStatement);
00423   return mRemoveAllStatement->Execute();
00424 }
00425 
00426 nsresult
00427 nsDOMStorageDB::GetUsage(const nsAString &aOwner, PRInt32 *aUsage)
00428 {
00429   mozStorageStatementScoper scope(mGetUsageStatement);
00430 
00431   nsresult rv = mGetUsageStatement->BindStringParameter(0, aOwner);
00432   NS_ENSURE_SUCCESS(rv, rv);
00433   
00434   PRBool exists;
00435   rv = mGetUsageStatement->ExecuteStep(&exists);
00436   NS_ENSURE_SUCCESS(rv, rv);
00437 
00438   if (!exists) {
00439     *aUsage = 0;
00440     return NS_OK;
00441   }
00442   
00443   return mGetUsageStatement->GetInt32(0, aUsage);
00444 }