mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 628071 - 'Crash inspecting IDBRequest(mozIndexedDB.open)'. r=sicking, a=blocking.
This commit is contained in:
parent
48dca18bc6
commit
c96b568869
@ -221,6 +221,7 @@
|
||||
#include "nsXPCOMCID.h"
|
||||
|
||||
#include "mozilla/FunctionTimer.h"
|
||||
#include "mozIThirdPartyUtil.h"
|
||||
|
||||
#ifdef MOZ_LOGGING
|
||||
// so we can get logging even in release builds
|
||||
@ -8036,8 +8037,23 @@ NS_IMETHODIMP
|
||||
nsGlobalWindow::GetMozIndexedDB(nsIIDBFactory** _retval)
|
||||
{
|
||||
if (!mIndexedDB) {
|
||||
mIndexedDB = indexedDB::IDBFactory::Create();
|
||||
NS_ENSURE_TRUE(mIndexedDB, NS_ERROR_FAILURE);
|
||||
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
|
||||
do_GetService(THIRDPARTYUTIL_CONTRACTID);
|
||||
NS_ENSURE_TRUE(thirdPartyUtil, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
PRBool isThirdParty;
|
||||
nsresult rv = thirdPartyUtil->IsThirdPartyWindow(this, nsnull,
|
||||
&isThirdParty);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
if (isThirdParty) {
|
||||
NS_WARNING("IndexedDB is not permitted in a third-party window.");
|
||||
*_retval = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mIndexedDB = indexedDB::IDBFactory::Create(this);
|
||||
NS_ENSURE_TRUE(mIndexedDB, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIIDBFactory> request(mIndexedDB);
|
||||
|
@ -196,7 +196,10 @@ AsyncConnectionHelper::Run()
|
||||
gCurrentTransaction = mTransaction;
|
||||
|
||||
if (mRequest) {
|
||||
mRequest->SetDone(this);
|
||||
nsresult rv = mRequest->SetDone(this);
|
||||
if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) {
|
||||
mResultCode = rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Call OnError if the database had an error or if the OnSuccess handler
|
||||
@ -382,6 +385,7 @@ nsresult
|
||||
AsyncConnectionHelper::OnSuccess()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(mRequest, "Null request!");
|
||||
|
||||
nsRefPtr<nsDOMEvent> event =
|
||||
CreateGenericEvent(NS_LITERAL_STRING(SUCCESS_EVT_STR));
|
||||
@ -416,6 +420,7 @@ void
|
||||
AsyncConnectionHelper::OnError()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(mRequest, "Null request!");
|
||||
|
||||
// Make an error event and fire it at the target.
|
||||
nsRefPtr<nsDOMEvent> event =
|
||||
@ -465,19 +470,22 @@ AsyncConnectionHelper::ReleaseMainThreadObjects()
|
||||
mRequest = nsnull;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
AsyncConnectionHelper::WrapNative(JSContext* aCx,
|
||||
nsISupports* aNative,
|
||||
jsval* aResult)
|
||||
{
|
||||
JSObject* global = JS_GetGlobalForObject(aCx, JS_GetScopeChain(aCx));
|
||||
NS_ASSERTION(aCx, "Null context!");
|
||||
NS_ASSERTION(aNative, "Null pointer!");
|
||||
NS_ASSERTION(aResult, "Null pointer!");
|
||||
NS_ASSERTION(mRequest, "Null request!");
|
||||
|
||||
JSObject* global =
|
||||
static_cast<JSObject*>(mRequest->ScriptContext()->GetNativeGlobal());
|
||||
NS_ENSURE_TRUE(global, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsresult rv =
|
||||
nsContentUtils::WrapNative(aCx, global,
|
||||
static_cast<nsPIDOMEventTarget*>(aNative),
|
||||
aResult);
|
||||
nsContentUtils::WrapNative(aCx, global, aNative, aResult);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
return NS_OK;
|
||||
@ -490,6 +498,9 @@ AsyncConnectionHelper::ConvertCloneBufferToJSVal(
|
||||
JSAutoStructuredCloneBuffer& aBuffer,
|
||||
jsval* aResult)
|
||||
{
|
||||
NS_ASSERTION(aCx, "Null context!");
|
||||
NS_ASSERTION(aResult, "Null pointer!");
|
||||
|
||||
JSAutoRequest ar(aCx);
|
||||
|
||||
if (aBuffer.data()) {
|
||||
@ -516,6 +527,9 @@ AsyncConnectionHelper::ConvertCloneBuffersToArray(
|
||||
nsTArray<JSAutoStructuredCloneBuffer>& aBuffers,
|
||||
jsval* aResult)
|
||||
{
|
||||
NS_ASSERTION(aCx, "Null context!");
|
||||
NS_ASSERTION(aResult, "Null pointer!");
|
||||
|
||||
JSAutoRequest ar(aCx);
|
||||
|
||||
nsresult rv = ConvertCloneBuffersToArrayInternal(aCx, aBuffers, aResult);
|
||||
|
@ -158,12 +158,12 @@ protected:
|
||||
virtual void ReleaseMainThreadObjects();
|
||||
|
||||
/**
|
||||
* Helper to wrap a native into a jsval. Uses the global object of the given
|
||||
* context.
|
||||
* Helper to wrap a native into a jsval. Uses the global object of the request
|
||||
* to parent the native.
|
||||
*/
|
||||
static nsresult WrapNative(JSContext* aCx,
|
||||
nsISupports* aNative,
|
||||
jsval* aResult);
|
||||
nsresult WrapNative(JSContext* aCx,
|
||||
nsISupports* aNative,
|
||||
jsval* aResult);
|
||||
|
||||
/**
|
||||
* Helper to decode a clone buffer to a jsval.
|
||||
|
@ -84,15 +84,18 @@ public:
|
||||
mCursor(aCursor)
|
||||
{ }
|
||||
|
||||
~ContinueHelper()
|
||||
{
|
||||
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
|
||||
}
|
||||
|
||||
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
|
||||
nsresult OnSuccess();
|
||||
nsresult GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal);
|
||||
|
||||
void ReleaseMainThreadObjects()
|
||||
{
|
||||
mCursor = nsnull;
|
||||
mCloneBuffer.clear();
|
||||
AsyncConnectionHelper::ReleaseMainThreadObjects();
|
||||
}
|
||||
|
||||
@ -655,7 +658,8 @@ ContinueHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
}
|
||||
|
||||
nsresult
|
||||
ContinueHelper::OnSuccess()
|
||||
ContinueHelper::GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal)
|
||||
{
|
||||
// Remove cached stuff from last time.
|
||||
mCursor->mCachedKey = nsnull;
|
||||
@ -666,38 +670,25 @@ ContinueHelper::OnSuccess()
|
||||
|
||||
if (mKey.IsUnset()) {
|
||||
mCursor->mHaveValue = false;
|
||||
*aVal = JSVAL_VOID;
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(mCursor->mType == IDBCursor::OBJECTSTORE ||
|
||||
!mObjectKey.IsUnset(), "Bad key!");
|
||||
|
||||
// Set new values.
|
||||
mCursor->mKey = mKey;
|
||||
mCursor->mObjectKey = mObjectKey;
|
||||
mCursor->mCloneBuffer.clear();
|
||||
mCursor->mCloneBuffer.swap(mCloneBuffer);
|
||||
mCursor->mContinueToKey = Key::UNSETKEY;
|
||||
|
||||
mCursor->mCloneBuffer.swap(mCloneBuffer);
|
||||
mCloneBuffer.clear(aCx);
|
||||
|
||||
nsresult rv = WrapNative(aCx, mCursor, aVal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// We want an event, with a result, etc. Call the base class method.
|
||||
return AsyncConnectionHelper::OnSuccess();
|
||||
}
|
||||
|
||||
nsresult
|
||||
ContinueHelper::GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal)
|
||||
{
|
||||
if (mKey.IsUnset()) {
|
||||
NS_ASSERTION(!mCursor->mHaveValue, "Should have unset this!");
|
||||
*aVal = JSVAL_VOID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (mCursor->mType != IDBCursor::OBJECTSTORE) {
|
||||
NS_ASSERTION(!mObjectKey.IsUnset(), "Bad key!");
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_ASSERTION(mCursor->mHaveValue, "This should still be set to true!");
|
||||
return WrapNative(aCx, mCursor, aVal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -82,7 +82,6 @@ public:
|
||||
{ }
|
||||
|
||||
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
|
||||
nsresult OnSuccess();
|
||||
nsresult GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal);
|
||||
|
||||
@ -957,7 +956,8 @@ SetVersionHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
}
|
||||
|
||||
nsresult
|
||||
SetVersionHelper::OnSuccess()
|
||||
SetVersionHelper::GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal)
|
||||
{
|
||||
DatabaseInfo* info;
|
||||
if (!DatabaseInfo::Get(mDatabase->Id(), &info)) {
|
||||
@ -966,15 +966,12 @@ SetVersionHelper::OnSuccess()
|
||||
}
|
||||
info->version = mVersion;
|
||||
|
||||
// We want an event, with a result, etc. Call the base class method.
|
||||
return AsyncConnectionHelper::OnSuccess();
|
||||
}
|
||||
nsresult rv = WrapNative(aCx, NS_ISUPPORTS_CAST(nsPIDOMEventTarget*,
|
||||
mTransaction),
|
||||
aVal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsresult
|
||||
SetVersionHelper::GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal)
|
||||
{
|
||||
return WrapNative(aCx, static_cast<nsPIDOMEventTarget*>(mTransaction), aVal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -41,7 +41,6 @@
|
||||
|
||||
#include "nsILocalFile.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "mozIThirdPartyUtil.h"
|
||||
|
||||
#include "mozilla/storage.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
@ -512,11 +511,34 @@ CreateDatabaseConnection(const nsACString& aASCIIOrigin,
|
||||
|
||||
// static
|
||||
already_AddRefed<nsIIDBFactory>
|
||||
IDBFactory::Create()
|
||||
IDBFactory::Create(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
nsCOMPtr<nsIIDBFactory> request(new IDBFactory());
|
||||
return request.forget();
|
||||
NS_ASSERTION(aWindow, "Must have a window!");
|
||||
|
||||
if (aWindow->IsOuterWindow()) {
|
||||
aWindow = aWindow->GetCurrentInnerWindow();
|
||||
}
|
||||
NS_ENSURE_TRUE(aWindow, nsnull);
|
||||
|
||||
if (gCurrentDatabaseIndex == BAD_TLS_INDEX) {
|
||||
// First time we're creating a database.
|
||||
if (PR_NewThreadPrivateIndex(&gCurrentDatabaseIndex, NULL) != PR_SUCCESS) {
|
||||
NS_ERROR("PR_NewThreadPrivateIndex failed!");
|
||||
gCurrentDatabaseIndex = BAD_TLS_INDEX;
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsContentUtils::AddIntPrefVarCache(PREF_INDEXEDDB_QUOTA, &gIndexedDBQuota,
|
||||
DEFAULT_QUOTA);
|
||||
}
|
||||
|
||||
nsRefPtr<IDBFactory> factory = new IDBFactory();
|
||||
|
||||
factory->mWindow = do_GetWeakReference(aWindow);
|
||||
NS_ENSURE_TRUE(factory->mWindow, nsnull);
|
||||
|
||||
return factory.forget();
|
||||
}
|
||||
|
||||
// static
|
||||
@ -798,26 +820,21 @@ IDBFactory::Open(const nsAString& aName,
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (gCurrentDatabaseIndex == BAD_TLS_INDEX) {
|
||||
// First time we're creating a database.
|
||||
if (PR_NewThreadPrivateIndex(&gCurrentDatabaseIndex, NULL) != PR_SUCCESS) {
|
||||
NS_ERROR("PR_NewThreadPrivateIndex failed!");
|
||||
gCurrentDatabaseIndex = BAD_TLS_INDEX;
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
nsContentUtils::AddIntPrefVarCache(PREF_INDEXEDDB_QUOTA, &gIndexedDBQuota,
|
||||
DEFAULT_QUOTA);
|
||||
}
|
||||
|
||||
if (aName.IsEmpty()) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
|
||||
NS_ENSURE_TRUE(window, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(window);
|
||||
NS_ENSURE_TRUE(sgo, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsIScriptContext* context = sgo->GetContext();
|
||||
NS_ENSURE_TRUE(context, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
rv = nsContentUtils::GetSecurityManager()->
|
||||
nsresult rv = nsContentUtils::GetSecurityManager()->
|
||||
GetSubjectPrincipal(getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
@ -835,33 +852,7 @@ IDBFactory::Open(const nsAString& aName,
|
||||
}
|
||||
}
|
||||
|
||||
nsIScriptContext* context = GetScriptContextFromJSContext(aCx);
|
||||
NS_ENSURE_TRUE(context, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> innerWindow;
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window =
|
||||
do_QueryInterface(context->GetGlobalObject());
|
||||
if (window) {
|
||||
innerWindow = window->GetCurrentInnerWindow();
|
||||
}
|
||||
NS_ENSURE_TRUE(innerWindow, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
|
||||
do_GetService(THIRDPARTYUTIL_CONTRACTID);
|
||||
NS_ENSURE_TRUE(thirdPartyUtil, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
PRBool isThirdPartyWindow;
|
||||
rv = thirdPartyUtil->IsThirdPartyWindow(window, nsnull, &isThirdPartyWindow);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
if (isThirdPartyWindow) {
|
||||
NS_WARNING("IndexedDB is not permitted in a third-party window.");
|
||||
*_retval = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<IDBRequest> request = IDBRequest::Create(this, context, innerWindow,
|
||||
nsRefPtr<IDBRequest> request = IDBRequest::Create(this, context, window,
|
||||
nsnull);
|
||||
NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
@ -869,7 +860,7 @@ IDBFactory::Open(const nsAString& aName,
|
||||
new OpenDatabaseHelper(request, aName, origin);
|
||||
|
||||
nsRefPtr<CheckPermissionsHelper> permissionHelper =
|
||||
new CheckPermissionsHelper(openHelper, innerWindow, aName, origin);
|
||||
new CheckPermissionsHelper(openHelper, window, aName, origin);
|
||||
|
||||
nsRefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::GetOrCreate();
|
||||
NS_ENSURE_TRUE(mgr, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
@ -956,7 +947,7 @@ OpenDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
|
||||
nsresult
|
||||
OpenDatabaseHelper::GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal)
|
||||
jsval *aVal)
|
||||
{
|
||||
DatabaseInfo* dbInfo;
|
||||
if (DatabaseInfo::Get(mDatabaseId, &dbInfo)) {
|
||||
@ -1036,12 +1027,13 @@ OpenDatabaseHelper::GetSuccessResult(JSContext* aCx,
|
||||
dbInfo->nextObjectStoreId = mLastObjectStoreId + 1;
|
||||
dbInfo->nextIndexId = mLastIndexId + 1;
|
||||
|
||||
nsRefPtr<IDBDatabase> db =
|
||||
nsRefPtr<IDBDatabase> database =
|
||||
IDBDatabase::Create(mRequest->ScriptContext(), mRequest->Owner(), dbInfo,
|
||||
mASCIIOrigin);
|
||||
if (!db) {
|
||||
if (!database) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
return WrapNative(aCx, static_cast<nsPIDOMEventTarget*>(db), aVal);
|
||||
return WrapNative(aCx, NS_ISUPPORTS_CAST(nsPIDOMEventTarget*, database),
|
||||
aVal);
|
||||
}
|
||||
|
@ -45,6 +45,10 @@
|
||||
#include "mozIStorageConnection.h"
|
||||
#include "nsIIDBFactory.h"
|
||||
|
||||
#include "nsIWeakReferenceUtils.h"
|
||||
|
||||
class nsPIDOMWindow;
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
|
||||
struct DatabaseInfo;
|
||||
@ -58,7 +62,7 @@ public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIIDBFACTORY
|
||||
|
||||
static already_AddRefed<nsIIDBFactory> Create();
|
||||
static already_AddRefed<nsIIDBFactory> Create(nsPIDOMWindow* aWindow);
|
||||
|
||||
static already_AddRefed<mozIStorageConnection>
|
||||
GetConnection(const nsAString& aDatabaseFilePath);
|
||||
@ -87,6 +91,8 @@ public:
|
||||
private:
|
||||
IDBFactory() { }
|
||||
~IDBFactory() { }
|
||||
|
||||
nsCOMPtr<nsIWeakReference> mWindow;
|
||||
};
|
||||
|
||||
END_INDEXEDDB_NAMESPACE
|
||||
|
@ -96,16 +96,15 @@ public:
|
||||
: GetKeyHelper(aTransaction, aRequest, aIndex, aKey)
|
||||
{ }
|
||||
|
||||
~GetHelper()
|
||||
{
|
||||
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
|
||||
}
|
||||
|
||||
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
|
||||
nsresult GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal);
|
||||
|
||||
void ReleaseMainThreadObjects()
|
||||
{
|
||||
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
|
||||
GetKeyHelper::ReleaseMainThreadObjects();
|
||||
}
|
||||
|
||||
protected:
|
||||
JSAutoStructuredCloneBuffer mCloneBuffer;
|
||||
};
|
||||
@ -141,15 +140,19 @@ public:
|
||||
: GetKeyHelper(aTransaction, aRequest, aIndex, aKey), mLimit(aLimit)
|
||||
{ }
|
||||
|
||||
~GetAllHelper()
|
||||
{
|
||||
for (PRUint32 index = 0; index < mCloneBuffers.Length(); index++) {
|
||||
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffers[index]);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
|
||||
nsresult GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal);
|
||||
|
||||
void ReleaseMainThreadObjects()
|
||||
{
|
||||
for (PRUint32 index = 0; index < mCloneBuffers.Length(); index++) {
|
||||
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffers[index]);
|
||||
}
|
||||
GetKeyHelper::ReleaseMainThreadObjects();
|
||||
}
|
||||
|
||||
@ -217,6 +220,11 @@ public:
|
||||
mUpperOpen(aUpperOpen), mDirection(aDirection)
|
||||
{ }
|
||||
|
||||
~OpenCursorHelper()
|
||||
{
|
||||
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
|
||||
}
|
||||
|
||||
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
|
||||
nsresult GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal);
|
||||
@ -224,7 +232,6 @@ public:
|
||||
void ReleaseMainThreadObjects()
|
||||
{
|
||||
mIndex = nsnull;
|
||||
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
|
||||
AsyncConnectionHelper::ReleaseMainThreadObjects();
|
||||
}
|
||||
|
||||
@ -773,7 +780,12 @@ nsresult
|
||||
GetHelper::GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal)
|
||||
{
|
||||
return ConvertCloneBufferToJSVal(aCx, mCloneBuffer, aVal);
|
||||
nsresult rv = ConvertCloneBufferToJSVal(aCx, mCloneBuffer, aVal);
|
||||
|
||||
mCloneBuffer.clear(aCx);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -1040,7 +1052,15 @@ GetAllHelper::GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal)
|
||||
{
|
||||
NS_ASSERTION(mCloneBuffers.Length() <= mLimit, "Too many results!");
|
||||
return ConvertCloneBuffersToArray(aCx, mCloneBuffers, aVal);
|
||||
|
||||
nsresult rv = ConvertCloneBuffersToArray(aCx, mCloneBuffers, aVal);
|
||||
|
||||
for (PRUint32 index = 0; index < mCloneBuffers.Length(); index++) {
|
||||
mCloneBuffers[index].clear(aCx);
|
||||
}
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -1551,5 +1571,7 @@ OpenCursorHelper::GetSuccessResult(JSContext* aCx,
|
||||
mCloneBuffer);
|
||||
NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
NS_ASSERTION(!mCloneBuffer.data(), "Should have swapped!");
|
||||
|
||||
return WrapNative(aCx, cursor, aVal);
|
||||
}
|
||||
|
@ -80,6 +80,11 @@ public:
|
||||
mIndexUpdateInfo.SwapElements(aIndexUpdateInfo);
|
||||
}
|
||||
|
||||
~AddHelper()
|
||||
{
|
||||
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
|
||||
}
|
||||
|
||||
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
|
||||
nsresult GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal);
|
||||
@ -117,6 +122,11 @@ public:
|
||||
mKey(aKey)
|
||||
{ }
|
||||
|
||||
~GetHelper()
|
||||
{
|
||||
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
|
||||
}
|
||||
|
||||
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
|
||||
nsresult GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal);
|
||||
@ -149,7 +159,6 @@ public:
|
||||
{ }
|
||||
|
||||
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
|
||||
nsresult OnSuccess();
|
||||
nsresult GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal);
|
||||
};
|
||||
@ -192,6 +201,11 @@ public:
|
||||
mUpperOpen(aUpperOpen), mDirection(aDirection)
|
||||
{ }
|
||||
|
||||
~OpenCursorHelper()
|
||||
{
|
||||
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
|
||||
}
|
||||
|
||||
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
|
||||
nsresult GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal);
|
||||
@ -303,6 +317,13 @@ public:
|
||||
mUpperOpen(aUpperOpen), mLimit(aLimit)
|
||||
{ }
|
||||
|
||||
~GetAllHelper()
|
||||
{
|
||||
for (PRUint32 index = 0; index < mCloneBuffers.Length(); index++) {
|
||||
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffers[index]);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
|
||||
nsresult GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal);
|
||||
@ -1710,6 +1731,9 @@ AddHelper::GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal)
|
||||
{
|
||||
NS_ASSERTION(!mKey.IsUnset(), "Badness!");
|
||||
|
||||
mCloneBuffer.clear(aCx);
|
||||
|
||||
return IDBObjectStore::GetJSValFromKey(mKey, aCx, aVal);
|
||||
}
|
||||
|
||||
@ -1813,7 +1837,12 @@ nsresult
|
||||
GetHelper::GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal)
|
||||
{
|
||||
return ConvertCloneBufferToJSVal(aCx, mCloneBuffer, aVal);
|
||||
nsresult rv = ConvertCloneBufferToJSVal(aCx, mCloneBuffer, aVal);
|
||||
|
||||
mCloneBuffer.clear(aCx);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -1846,19 +1875,12 @@ DeleteHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
// Search for it!
|
||||
rv = stmt->Execute();
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DeleteHelper::OnSuccess()
|
||||
{
|
||||
return AsyncConnectionHelper::OnSuccess();
|
||||
}
|
||||
|
||||
nsresult
|
||||
DeleteHelper::GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal)
|
||||
@ -2082,6 +2104,8 @@ OpenCursorHelper::GetSuccessResult(JSContext* aCx,
|
||||
mCloneBuffer);
|
||||
NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
NS_ASSERTION(!mCloneBuffer.data(), "Should have swapped!");
|
||||
|
||||
return WrapNative(aCx, cursor, aVal);
|
||||
}
|
||||
|
||||
@ -2386,5 +2410,13 @@ GetAllHelper::GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal)
|
||||
{
|
||||
NS_ASSERTION(mCloneBuffers.Length() <= mLimit, "Too many results!");
|
||||
return ConvertCloneBuffersToArray(aCx, mCloneBuffers, aVal);
|
||||
|
||||
nsresult rv = ConvertCloneBuffersToArray(aCx, mCloneBuffers, aVal);
|
||||
|
||||
for (PRUint32 index = 0; index < mCloneBuffers.Length(); index++) {
|
||||
mCloneBuffers[index].clear(aCx);
|
||||
}
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -110,7 +110,6 @@ void
|
||||
IDBRequest::Reset()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
mHelper = nsnull;
|
||||
mResultVal = JSVAL_VOID;
|
||||
mHaveResultOrErrorCode = false;
|
||||
mErrorCode = 0;
|
||||
@ -119,19 +118,66 @@ IDBRequest::Reset()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsresult
|
||||
IDBRequest::SetDone(AsyncConnectionHelper* aHelper)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(!mHelper, "Already called!");
|
||||
NS_ASSERTION(!mHaveResultOrErrorCode, "Already called!");
|
||||
NS_ASSERTION(!mResultValRooted, "Already rooted?!");
|
||||
NS_ASSERTION(JSVAL_IS_VOID(mResultVal), "Should be undefined!");
|
||||
|
||||
mErrorCode = NS_ERROR_GET_CODE(aHelper->GetResultCode());
|
||||
if (mErrorCode) {
|
||||
mHaveResultOrErrorCode = true;
|
||||
// See if our window is still valid. If not then we're going to pretend that
|
||||
// we never completed.
|
||||
if (NS_FAILED(CheckInnerWindowCorrectness())) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mHaveResultOrErrorCode = true;
|
||||
|
||||
nsresult rv = aHelper->GetResultCode();
|
||||
|
||||
// If the request failed then set the error code and return.
|
||||
if (NS_FAILED(rv)) {
|
||||
mErrorCode = NS_ERROR_GET_CODE(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Otherwise we need to get the result from the helper.
|
||||
JSContext* cx = static_cast<JSContext*>(mScriptContext->GetNativeContext());
|
||||
NS_ASSERTION(cx, "Failed to get a context!");
|
||||
|
||||
JSObject* global = static_cast<JSObject*>(mScriptContext->GetNativeGlobal());
|
||||
NS_ASSERTION(global, "Failed to get global object!");
|
||||
|
||||
JSAutoRequest ar(cx);
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(cx, global)) {
|
||||
rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
else {
|
||||
mHelper = aHelper;
|
||||
RootResultVal();
|
||||
|
||||
rv = aHelper->GetSuccessResult(cx, &mResultVal);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Unroot if we don't really need to be rooted.
|
||||
if (!JSVAL_IS_GCTHING(mResultVal)) {
|
||||
UnrootResultVal();
|
||||
}
|
||||
}
|
||||
else {
|
||||
NS_WARNING("GetSuccessResult failed!");
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mErrorCode = 0;
|
||||
}
|
||||
else {
|
||||
mErrorCode = NS_ERROR_GET_CODE(rv);
|
||||
mResultVal = JSVAL_VOID;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
@ -155,7 +201,7 @@ IDBRequest::GetReadyState(PRUint16* aReadyState)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (mHaveResultOrErrorCode || mHelper) {
|
||||
if (mHaveResultOrErrorCode) {
|
||||
*aReadyState = nsIIDBRequest::DONE;
|
||||
}
|
||||
else {
|
||||
@ -185,45 +231,17 @@ IDBRequest::GetTransaction(nsIIDBTransaction** aTransaction)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
IDBRequest::GetResult(JSContext* aCx,
|
||||
jsval* aResult)
|
||||
IDBRequest::GetResult(jsval* aResult)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (!mHaveResultOrErrorCode) {
|
||||
if (!mHelper) {
|
||||
// XXX Need a real error code here.
|
||||
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!mResultValRooted, "Huh?!");
|
||||
NS_ASSERTION(JSVAL_IS_VOID(mResultVal), "Should be undefined!");
|
||||
|
||||
if (NS_SUCCEEDED(mHelper->GetResultCode())) {
|
||||
// It's common practice for result values to be rooted before being set.
|
||||
// Root now, even though we may unroot below, to make mResultVal safe from
|
||||
// GC.
|
||||
RootResultVal();
|
||||
|
||||
rv = mHelper->GetSuccessResult(aCx, &mResultVal);
|
||||
if (NS_FAILED(rv)) {
|
||||
mResultVal = JSVAL_VOID;
|
||||
}
|
||||
|
||||
// There's no point in rooting non-GCThings. Unroot if possible.
|
||||
if (!JSVAL_IS_GCTHING(mResultVal)) {
|
||||
UnrootResultVal();
|
||||
}
|
||||
}
|
||||
|
||||
mHaveResultOrErrorCode = true;
|
||||
mHelper = nsnull;
|
||||
// XXX Need a real error code here.
|
||||
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
*aResult = mResultVal;
|
||||
return rv;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -231,7 +249,7 @@ IDBRequest::GetErrorCode(PRUint16* aErrorCode)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (!mHaveResultOrErrorCode && !mHelper) {
|
||||
if (!mHaveResultOrErrorCode) {
|
||||
// XXX Need a real error code here.
|
||||
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
|
||||
}
|
||||
@ -282,17 +300,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBRequest,
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnSuccessListener)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnErrorListener)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSource)
|
||||
|
||||
// mHelper is a threadsafe runnable and can't use a cycle-collecting refcnt.
|
||||
// We traverse manually here.
|
||||
if (tmp->mHelper) {
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mHelper->mDatabase,
|
||||
nsPIDOMEventTarget)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mHelper->mTransaction,
|
||||
nsPIDOMEventTarget)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mHelper->mRequest,
|
||||
nsPIDOMEventTarget)
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBRequest,
|
||||
@ -300,9 +307,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBRequest,
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnSuccessListener)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnErrorListener)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSource)
|
||||
|
||||
// Unlinking mHelper will unlink all the objects that we really care about.
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBRequest)
|
||||
|
@ -82,7 +82,7 @@ public:
|
||||
|
||||
void Reset();
|
||||
|
||||
void SetDone(AsyncConnectionHelper* aHelper);
|
||||
nsresult SetDone(AsyncConnectionHelper* aHelper);
|
||||
|
||||
nsIScriptContext* ScriptContext()
|
||||
{
|
||||
@ -105,7 +105,6 @@ protected:
|
||||
|
||||
nsCOMPtr<nsISupports> mSource;
|
||||
nsRefPtr<IDBTransaction> mTransaction;
|
||||
nsRefPtr<AsyncConnectionHelper> mHelper;
|
||||
|
||||
nsRefPtr<nsDOMEventListenerWrapper> mOnSuccessListener;
|
||||
nsRefPtr<nsDOMEventListenerWrapper> mOnErrorListener;
|
||||
|
@ -59,7 +59,6 @@ interface nsIIDBRequest : nsISupports
|
||||
|
||||
readonly attribute nsIIDBTransaction transaction;
|
||||
|
||||
[implicit_jscontext]
|
||||
readonly attribute jsval result;
|
||||
|
||||
readonly attribute unsigned short errorCode;
|
||||
|
@ -77,6 +77,7 @@ TEST_FILES = \
|
||||
test_objectStore_inline_autoincrement_key_added_on_put.html \
|
||||
test_objectStore_remove_values.html \
|
||||
test_object_identity.html \
|
||||
test_odd_result_order.html \
|
||||
test_open_empty_db.html \
|
||||
test_open_objectStore.html \
|
||||
test_overlapping_transactions.html \
|
||||
|
97
dom/indexedDB/test/test_odd_result_order.html
Normal file
97
dom/indexedDB/test/test_odd_result_order.html
Normal file
@ -0,0 +1,97 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Test</title>
|
||||
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
const data = { key: 5, index: 10 };
|
||||
|
||||
let request = mozIndexedDB.open(window.location.pathname);
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let db;
|
||||
setTimeout(function() {
|
||||
db = request.result;
|
||||
continueToNextStep();
|
||||
}, 0);
|
||||
yield;
|
||||
|
||||
ok(db instanceof IDBDatabase, "Got a real database");
|
||||
|
||||
db.onerror = errorHandler;
|
||||
|
||||
db.setVersion("1").onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
let objectStore = db.createObjectStore("foo", { keyPath: "key",
|
||||
autoIncrement: true });
|
||||
let index = objectStore.createIndex("foo", "index");
|
||||
|
||||
event.target.transaction.oncomplete = continueToNextStep;
|
||||
yield;
|
||||
|
||||
objectStore = db.transaction("foo", IDBTransaction.READ_WRITE)
|
||||
.objectStore("foo");
|
||||
request = objectStore.add(data);
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
let key;
|
||||
setTimeout(function() {
|
||||
key = request.result;
|
||||
continueToNextStep();
|
||||
}, 0);
|
||||
yield;
|
||||
|
||||
is(key, data.key, "Got the right key");
|
||||
|
||||
objectStore = db.transaction("foo").objectStore("foo");
|
||||
objectStore.get(data.key).onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
let obj;
|
||||
setTimeout(function() {
|
||||
obj = event.target.result;
|
||||
continueToNextStep();
|
||||
}, 0);
|
||||
yield;
|
||||
|
||||
is(obj.key, data.key, "Got the right key");
|
||||
is(obj.index, data.index, "Got the right property value");
|
||||
|
||||
objectStore = db.transaction("foo", IDBTransaction.READ_WRITE)
|
||||
.objectStore("foo");
|
||||
request = objectStore.delete(data.key);
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
key = undefined;
|
||||
setTimeout(function() {
|
||||
key = request.result;
|
||||
continueToNextStep();
|
||||
}, 0);
|
||||
yield;
|
||||
|
||||
is(key, data.key, "Got the right key");
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user