Bug 628071 - 'Crash inspecting IDBRequest(mozIndexedDB.open)'. r=sicking, a=blocking.

This commit is contained in:
Ben Turner 2011-01-26 17:53:02 -08:00
parent 48dca18bc6
commit c96b568869
14 changed files with 352 additions and 182 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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;

View File

@ -59,7 +59,6 @@ interface nsIIDBRequest : nsISupports
readonly attribute nsIIDBTransaction transaction;
[implicit_jscontext]
readonly attribute jsval result;
readonly attribute unsigned short errorCode;

View File

@ -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 \

View 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>