Fixing bug 335540. Implement whatwg webapps storage. Patch by neil@mozilla.com and jst@mozilla.com, r/sr=neil/vlad/jst.

This commit is contained in:
jst%mozilla.jstenback.com 2006-05-19 05:57:36 +00:00
parent 43d0a92ac7
commit ed47496c33
28 changed files with 2941 additions and 26 deletions

View File

@ -152,8 +152,13 @@ tier_9_dirs += \
modules/libutil \
netwerk \
modules/libjar \
db \
$(NULL)
ifdef MOZ_STORAGE
tier_9_dirs += storage
endif
ifdef MOZ_XUL
tier_9_dirs += rdf
endif
@ -235,7 +240,6 @@ tier_50_dirs += xpfe/bootstrap/appleevents
endif
tier_50_dirs += \
db \
xpfe \
toolkit/components \
$(NULL)
@ -282,10 +286,6 @@ endif
endif
endif
ifdef MOZ_STORAGE
tier_50_dirs += storage
endif
ifdef MOZ_XUL_APP
ifndef BUILD_STATIC_LIBS
tier_50_dirs += toolkit/library

View File

@ -52,6 +52,8 @@
#include "nsIDOMDocument.h"
#include "nsIDOMNSDocument.h"
#include "nsIDOMElement.h"
#include "nsIDOMStorage.h"
#include "nsPIDOMStorage.h"
#include "nsIDocumentViewer.h"
#include "nsIDocumentLoaderFactory.h"
#include "nsCURILoader.h"
@ -340,6 +342,9 @@ nsDocShell::Init()
rv = mContentListener->Init();
NS_ENSURE_SUCCESS(rv, rv);
if (!mStorages.Init())
return NS_ERROR_OUT_OF_MEMORY;
// We want to hold a strong ref to the loadgroup, so it better hold a weak
// ref to us... use an InterfaceRequestorProxy to do this.
nsCOMPtr<InterfaceRequestorProxy> proxy =
@ -1659,6 +1664,78 @@ nsDocShell::HistoryPurged(PRInt32 aNumEntries)
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GetSessionStorageForDomain(const nsACString& aDomain,
nsIDOMStorage** aStorage)
{
NS_ENSURE_ARG_POINTER(aStorage);
*aStorage = nsnull;
if (aDomain.IsEmpty())
return NS_OK;
nsCOMPtr<nsIDocShellTreeItem> topItem;
nsresult rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem));
if (NS_FAILED(rv))
return rv;
if (!topItem)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDocShell> topDocShell = do_QueryInterface(topItem);
if (topDocShell != this)
return topDocShell->GetSessionStorageForDomain(aDomain, aStorage);
if (!mStorages.Get(aDomain, aStorage)) {
nsCOMPtr<nsIDOMStorage> newstorage =
do_CreateInstance("@mozilla.org/dom/storage;1");
if (!newstorage)
return NS_ERROR_OUT_OF_MEMORY;
nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(newstorage);
if (!pistorage)
return NS_ERROR_FAILURE;
pistorage->Init(NS_ConvertUTF8toUTF16(aDomain), PR_FALSE);
if (!mStorages.Put(aDomain, newstorage))
return NS_ERROR_OUT_OF_MEMORY;
*aStorage = newstorage;
NS_ADDREF(*aStorage);
}
return NS_OK;
}
nsresult
nsDocShell::AddSessionStorage(const nsACString& aDomain,
nsIDOMStorage* aStorage)
{
NS_ENSURE_ARG_POINTER(aStorage);
if (aDomain.IsEmpty())
return NS_OK;
nsCOMPtr<nsIDocShellTreeItem> topItem;
nsresult rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem));
if (NS_FAILED(rv))
return rv;
if (topItem) {
nsCOMPtr<nsIDocShell> topDocShell = do_QueryInterface(topItem);
if (topDocShell == this) {
if (!mStorages.Put(aDomain, aStorage))
return NS_ERROR_OUT_OF_MEMORY;
}
else {
return topDocShell->AddSessionStorage(aDomain, aStorage);
}
}
return NS_OK;
}
//*****************************************************************************
// nsDocShell::nsIDocShellTreeItem
//*****************************************************************************
@ -6278,6 +6355,40 @@ nsDocShell::InternalLoad(nsIURI * aURI,
nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(newWin);
targetDocShell = do_QueryInterface(webNav);
nsCOMPtr<nsIScriptObjectPrincipal> sop =
do_QueryInterface(mScriptGlobal);
nsCOMPtr<nsIURI> currentCodebase;
if (sop) {
nsIPrincipal *principal = sop->GetPrincipal();
if (principal) {
principal->GetURI(getter_AddRefs(currentCodebase));
}
}
// We opened a new window for the target, clone the
// session storage if the current URI's domain matches
// that of the loading URI.
if (targetDocShell && currentCodebase && aURI) {
nsCAutoString thisDomain, newDomain;
nsresult gethostrv = currentCodebase->GetAsciiHost(thisDomain);
gethostrv |= aURI->GetAsciiHost(newDomain);
if (NS_SUCCEEDED(gethostrv) && thisDomain.Equals(newDomain)) {
nsCOMPtr<nsIDOMStorage> storage;
GetSessionStorageForDomain(thisDomain,
getter_AddRefs(storage));
nsCOMPtr<nsPIDOMStorage> piStorage =
do_QueryInterface(storage);
if (piStorage) {
nsCOMPtr<nsIDOMStorage> newstorage =
piStorage->Clone();
targetDocShell->AddSessionStorage(thisDomain,
newstorage);
}
}
}
}
//

View File

@ -49,6 +49,7 @@
#include "nsIContentViewer.h"
#include "nsIPrefBranch.h"
#include "nsVoidArray.h"
#include "nsInterfaceHashtable.h"
#include "nsIScriptContext.h"
#include "nsITimer.h"
@ -562,6 +563,9 @@ protected:
// the event whenever necessary.
nsRevocableEventPtr<RestorePresentationEvent> mRestorePresentationEvent;
// hash of session storages, keyed by domain
nsInterfaceHashtable<nsCStringHashKey, nsIDOMStorage> mStorages;
// Index into the SHTransaction list, indicating the previous and current
// transaction at the time that this DocShell begins to load
PRInt32 mPreviousTransIndex;

View File

@ -65,8 +65,9 @@ interface nsIRequest;
interface nsISHEntry;
interface nsILayoutHistoryState;
interface nsISecureBrowserUI;
interface nsIDOMStorage;
[scriptable, uuid(9f0c7461-b9a4-47f6-b88c-421dce1bce66)]
[scriptable, uuid(616b8670-d170-11da-a94d-0800200c9a66)]
interface nsIDocShell : nsISupports
{
/**
@ -404,5 +405,21 @@ interface nsIDocShell : nsISupports
* @param numEntries - The number of entries removed
*/
void historyPurged(in long numEntries);
/*
* Retrieves the WebApps session storage object for the supplied domain.
* If it doesn't already exist, a new one will be created.
*
* @param domain the domain of the storage object to retrieve
*/
nsIDOMStorage getSessionStorageForDomain(in ACString aDomain);
/*
* Add a WebApps session storage object to the docshell.
*
* @param domain the domain the storage object is associated with
* @param storage the storage object to add
*/
void addSessionStorage(in ACString aDomain, in nsIDOMStorage storage);
};

View File

@ -1,4 +1,3 @@
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
@ -57,7 +56,8 @@ DIRS = \
xbl \
xpath \
ls \
xul
xul \
storage
ifdef MOZ_SVG
DIRS += svg

View File

@ -0,0 +1,65 @@
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# Neil Deakin <enndeakin@sympatico.ca>
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = dom
XPIDL_MODULE = dom_storage
GRE_MODULE = 1
EXPORTS = \
nsPIDOMStorage.h \
$(NULL)
XPIDLSRCS = \
nsIDOMToString.idl \
$(NULL)
SDK_XPIDLSRCS = \
nsIDOMStorage.idl \
nsIDOMStorageEvent.idl \
nsIDOMStorageItem.idl \
nsIDOMStorageList.idl \
nsIDOMStorageWindow.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,98 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Neil Deakin <enndeakin@sympatico.ca>
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "domstubs.idl"
/**
* Interface for client side storage. See
* http://www.whatwg.org/specs/web-apps/current-work/#scs-client-side
* for more information.
*
* A storage object stores an arbitrary set of key-value pairs, which
* may be retrieved, modified and removed as needed. A key may only
* exist once within a storage object, and only one value may be
* associated with a particular key. Keys are stored in a particular
* order with the condition that this order not change by merely changing
* the value associated with a key, but the order may change when a
* key is added or removed.
*/
interface nsIDOMStorageItem;
[scriptable, uuid(95CC1383-3B62-4B89-AAEF-1004A513EF47)]
interface nsIDOMStorage : nsISupports
{
/**
* The number of keys stored.
*/
readonly attribute unsigned long length;
/**
* Retrieve the name of the key at a particular index.
*
* @param index index of the item to retrieve
* @returns the key at index
* @throws INDEX_SIZE_ERR if there is no key at that index
*/
DOMString key(in unsigned long index);
/**
* Retrieve an item with a given key
*
* @param key key to retrieve
* @returns found item or null if the key was not found
*/
nsIDOMStorageItem getItem(in DOMString key);
/**
* Assign a value with a key. If the key does not exist already, a new
* key is added associated with that value. If the key already exists,
* then the existing value is replaced with a new value.
*
* @param key key to set
* @param data data to associate with the key
* @returns found item or null if the key was not found
*/
void setItem(in DOMString key, in DOMString data);
/**
* Remove a key and its corresponding value.
*
* @param key key to remove
*/
void removeItem(in DOMString key);
};

View File

@ -0,0 +1,74 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Neil Deakin <enndeakin@sympatico.ca>
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "domstubs.idl"
#include "nsIDOMEvent.idl"
/**
* Interface for a client side storage. See
* http://www.whatwg.org/specs/web-apps/current-work/#scs-client-side
* for more information.
*
* Event sent to a window when a storage area changes.
*/
[scriptable, uuid(FC540C28-8EDD-4B7A-9C30-8638289B7A7D)]
interface nsIDOMStorageEvent : nsIDOMEvent
{
/**
* Domain of the storage area which changed, or #session for
* session storage.
*/
readonly attribute DOMString domain;
/**
* Initialize a storage event.
*/
void initStorageEvent(in DOMString typeArg,
in boolean canBubbleArg,
in boolean cancelableArg,
in DOMString domainArg);
/**
* Initialize a storage event.
*/
void initStorageEventNS(in DOMString namespaceURIArg,
in DOMString typeArg,
in boolean canBubbleArg,
in boolean cancelableArg,
in DOMString domainArg);
};

View File

@ -0,0 +1,60 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Neil Deakin <enndeakin@sympatico.ca>
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "domstubs.idl"
/**
* Interface for a client side storage item. See
* http://www.whatwg.org/specs/web-apps/current-work/#scs-client-side
* for more information.
*
* A respresentation of a storage object item.
*/
[scriptable, uuid(0CC37C78-4C5F-48E1-ADFC-7480B8FE9DC4)]
interface nsIDOMStorageItem : nsISupports
{
/**
* Indicates whether a key is available only in a secure context.
*/
attribute boolean secure;
/**
* The value associated with the item.
*/
attribute DOMString value;
};

View File

@ -0,0 +1,60 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Neil Deakin <enndeakin@sympatico.ca>
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "domstubs.idl"
/**
* Interface for a client side storage. See
* http://www.whatwg.org/specs/web-apps/current-work/#scs-client-side
* for more information.
*
* Allows access to contextual storage areas by domain.
*/
interface nsIDOMStorage;
[scriptable, uuid(f2166929-91B6-4372-8D5F-C366F47A5F54)]
interface nsIDOMStorageList : nsISupports
{
/**
* Returns a storage object for a particular domain.
*
* @param domain domain to retrieve
* @returns a storage area for the given domain
*/
nsIDOMStorage namedItem(in DOMString domain);
};

View File

@ -0,0 +1,63 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Neil Deakin <enndeakin@sympatico.ca>
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "domstubs.idl"
/**
* Interface for a client side storage. See
* http://www.whatwg.org/specs/web-apps/current-work/#scs-client-side
* for more information.
*
* Allows access to contextual storage areas.
*/
interface nsIDOMStorage;
interface nsIDOMStorageList;
[scriptable, uuid(55E9C181-2476-47CF-97F8-EFDAAF7B6F7A)]
interface nsIDOMStorageWindow : nsISupports
{
/**
* Session storage for the current browsing context.
*/
readonly attribute nsIDOMStorage sessionStorage;
/**
* Global storage, accessible by domain.
*/
readonly attribute nsIDOMStorageList globalStorage;
};

View File

@ -0,0 +1,56 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.com code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Johnny Stenback <jst@mozilla.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "domstubs.idl"
/**
* The sole purpose of this interface is to make it easy for XPCOM
* object's to hook into JS' toString() when interacting with
* XPConnect. If you implement this interface and advertize it in the
* object's classinfo, you'll get automatic mapping from JS'
* toString() to the toString() method in this interface.
*
* XXXjst: This doesn't really belong in dom/public/idl/storage, but
* it gets to live here until I find a more suitable place.
*/
[scriptable, uuid(2a72e20f-e337-4822-8994-2e35b5550d03)]
interface nsIDOMToString : nsISupports
{
DOMString toString();
};

View File

@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=2 et tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.com code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Johnny Stenback <jst@mozilla.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __nsPIDOMStorage_h_
#define __nsPIDOMStorage_h_
#include "nsISupports.h"
#include "nsTArray.h"
class nsIDOMStorage;
#define NS_PIDOMSTORAGE_IID \
{ 0x2fdbb82e, 0x4b47, 0x406a, \
{ 0xb1, 0x17, 0x6d, 0x67, 0x58, 0xc1, 0xee, 0x6b } }
class nsPIDOMStorage : public nsISupports
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_PIDOMSTORAGE_IID)
virtual void Init(const nsAString &aDomain, PRBool aUseDB) = 0;
virtual already_AddRefed<nsIDOMStorage> Clone() = 0;
virtual nsTArray<nsString> *GetKeys() = 0;
};
#endif // __nsPIDOMStorage_h_

View File

@ -365,6 +365,12 @@ enum nsDOMClassInfoID {
eDOMClassInfo_XPathNSResolver_id,
eDOMClassInfo_XPathResult_id,
// WhatWG WebApps Objects
eDOMClassInfo_Storage_id,
eDOMClassInfo_StorageList_id,
eDOMClassInfo_StorageItem_id,
eDOMClassInfo_StorageEvent_id,
eDOMClassInfo_WindowRoot_id,
// DOMParser, XMLSerializer

View File

@ -42,7 +42,7 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
DIRS = base jsurl events
DIRS = base jsurl events storage
include $(topsrcdir)/config/rules.mk

View File

@ -80,6 +80,7 @@ REQUIRES = xpcom \
rdf \
xultmpl \
jar \
storage \
$(NULL)
ifdef NS_TRACE_MALLOC
@ -107,12 +108,15 @@ CPPSRCS = \
nsDOMScriptObjectFactory.cpp \
$(NULL)
# we don't want the shared lib, but we want to force the creation of a static lib.
# we don't want the shared lib, but we want to force the creation of a
# static lib.
FORCE_STATIC_LIB = 1
LOCAL_INCLUDES = \
-I$(srcdir)/../events \
-I$(srcdir)/../storage \
-I$(topsrcdir)/content/xbl/src \
-I$(topsrcdir)/content/events/src \
$(NULL)
DEFINES += -D_IMPL_NS_LAYOUT

View File

@ -56,6 +56,7 @@
#include "nsUnicharUtils.h"
#include "xptcall.h"
#include "prprf.h"
#include "nsTArray.h"
// JavaScript includes
#include "jsapi.h"
@ -412,6 +413,14 @@
#include "nsIImageDocument.h"
// Storage includes
#include "nsIDOMStorage.h"
#include "nsPIDOMStorage.h"
#include "nsIDOMStorageList.h"
#include "nsIDOMStorageItem.h"
#include "nsIDOMStorageEvent.h"
#include "nsIDOMToString.h"
static NS_DEFINE_CID(kCPluginManagerCID, NS_PLUGINMANAGER_CID);
static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
@ -1104,6 +1113,27 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(XPathResult, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
// WhatWG Storage
// mrbkap says we don't need WANT_ADDPROPERTY on Storage objects
// since a call to addProperty() is always followed by a call to
// setProperty(), except in the case when a getter or setter is set
// for a property. But we don't care about getters or setters here.
NS_DEFINE_CLASSINFO_DATA(Storage, nsStorageSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS |
nsIXPCScriptable::WANT_NEWRESOLVE |
nsIXPCScriptable::WANT_GETPROPERTY |
nsIXPCScriptable::WANT_SETPROPERTY |
nsIXPCScriptable::WANT_DELPROPERTY |
nsIXPCScriptable::DONT_ENUM_STATIC_PROPS |
nsIXPCScriptable::WANT_NEWENUMERATE)
NS_DEFINE_CLASSINFO_DATA(StorageList, nsStorageListSH,
ARRAY_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(StorageItem, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(StorageEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
// We just want this to have classinfo so it gets mark callbacks for marking
// event listeners.
// We really don't want any of the default flags!
@ -1760,6 +1790,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMViewCSS)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMAbstractView)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageWindow)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(WindowUtils, nsIDOMWindowUtils)
@ -2445,6 +2476,8 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindowInternal)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMChromeWindow)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
// XXXjst: Do we want this on chrome windows?
// DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageWindow)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMViewCSS)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMAbstractView)
DOM_CLASSINFO_MAP_END
@ -3024,6 +3057,23 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathResult)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(Storage, nsIDOMStorage)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorage)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(StorageList, nsIDOMStorageList)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageList)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(StorageItem, nsIDOMStorageItem)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageItem)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMToString)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(StorageEvent, nsIDOMStorageEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageEvent)
DOM_CLASSINFO_MAP_END
// We just want this to have classinfo so it gets mark callbacks for marking
// event listeners.
DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(WindowRoot, nsISupports)
@ -3350,7 +3400,6 @@ nsDOMClassInfo::PostCreate(nsIXPConnectWrappedNative *wrapper,
if (if_info) {
nsXPIDLCString name;
if_info->GetName(getter_Copies(name));
NS_ASSERTION(nsCRT::strcmp(CutPrefix(name), mData->mName) == 0,
"Class name and proto chain interface name mismatch!");
}
@ -6151,8 +6200,8 @@ nsWindowSH::NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
switch (enum_op) {
case JSENUMERATE_INIT:
{
// First, do the security check that nsDOMClassInfo does to see if we need to
// do any work at all.
// First, do the security check that nsDOMClassInfo does to see
// if we need to do any work at all.
nsDOMClassInfo::Enumerate(wrapper, cx, obj, _retval);
if (!*_retval) {
return NS_OK;
@ -9590,6 +9639,202 @@ nsTreeColumnsSH::GetNamedItem(nsISupports *aNative,
#endif
// Storage scriptable helper
// One reason we need a newResolve hook is that in order for
// enumeration of storage object keys to work the keys we're
// enumerating need to exist on the storage object for the JS engine
// to find them.
NS_IMETHODIMP
nsStorageSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsval id, PRUint32 flags,
JSObject **objp, PRBool *_retval)
{
JSObject *realObj;
wrapper->GetJSObject(&realObj);
// First check to see if the property is defined on our prototype,
// after converting id to a string if it's an integer.
JSString *jsstr = JS_ValueToString(cx, id);
if (!jsstr) {
return JS_FALSE;
}
JSObject *proto = ::JS_GetPrototype(cx, realObj);
JSBool hasProp;
if (proto &&
(::JS_HasUCProperty(cx, proto, ::JS_GetStringChars(jsstr),
::JS_GetStringLength(jsstr), &hasProp) &&
hasProp)) {
// We found the property we're resolving on the prototype,
// nothing left to do here then.
return NS_OK;
}
// We're resolving property that doesn't exist on the prototype,
// check if the key exists in the storage object.
nsCOMPtr<nsIDOMStorage> storage(do_QueryWrappedNative(wrapper));
// GetItem() will return null if the caller can't access the session
// storage item.
nsCOMPtr<nsIDOMStorageItem> item;
nsresult rv = storage->GetItem(nsDependentJSString(jsstr),
getter_AddRefs(item));
NS_ENSURE_SUCCESS(rv, rv);
if (item) {
if (!::JS_DefineUCProperty(cx, realObj, ::JS_GetStringChars(jsstr),
::JS_GetStringLength(jsstr), JSVAL_VOID, nsnull,
nsnull, 0)) {
return NS_ERROR_FAILURE;
}
*objp = realObj;
}
return NS_OK;
}
nsresult
nsStorageSH::GetNamedItem(nsISupports *aNative, const nsAString& aName,
nsISupports **aResult)
{
nsCOMPtr<nsIDOMStorage> storage(do_QueryInterface(aNative));
NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED);
// Weak, transfer the ownership over to aResult
nsIDOMStorageItem* item = nsnull;
nsresult rv = storage->GetItem(aName, &item);
*aResult = item;
return rv;
}
NS_IMETHODIMP
nsStorageSH::SetProperty(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj, jsval id,
jsval *vp, PRBool *_retval)
{
nsCOMPtr<nsIDOMStorage> storage(do_QueryWrappedNative(wrapper));
NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED);
JSString *key = ::JS_ValueToString(cx, id);
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
JSString *value = ::JS_ValueToString(cx, *vp);
NS_ENSURE_TRUE(value, NS_ERROR_UNEXPECTED);
nsresult rv = storage->SetItem(nsDependentJSString(key),
nsDependentJSString(value));
if (NS_SUCCEEDED(rv)) {
rv = NS_SUCCESS_I_DID_SOMETHING;
}
return rv;
}
NS_IMETHODIMP
nsStorageSH::DelProperty(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj, jsval id,
jsval *vp, PRBool *_retval)
{
nsCOMPtr<nsIDOMStorage> storage(do_QueryWrappedNative(wrapper));
NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED);
JSString *key = ::JS_ValueToString(cx, id);
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
nsresult rv = storage->RemoveItem(nsDependentJSString(key));
if (NS_SUCCEEDED(rv)) {
rv = NS_SUCCESS_I_DID_SOMETHING;
}
return rv;
}
NS_IMETHODIMP
nsStorageSH::NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, PRUint32 enum_op, jsval *statep,
jsid *idp, PRBool *_retval)
{
nsTArray<nsString> *keys =
(nsTArray<nsString> *)JSVAL_TO_PRIVATE(*statep);
switch (enum_op) {
case JSENUMERATE_INIT:
{
nsCOMPtr<nsPIDOMStorage> storage(do_QueryWrappedNative(wrapper));
// XXXndeakin need to free the keys afterwards
keys = storage->GetKeys();
NS_ENSURE_TRUE(keys, NS_ERROR_OUT_OF_MEMORY);
*statep = PRIVATE_TO_JSVAL(keys);
if (idp) {
*idp = INT_TO_JSVAL(keys->Length());
}
break;
}
case JSENUMERATE_NEXT:
if (keys->Length() != 0) {
nsString& key = keys->ElementAt(0);
JSString *str =
JS_NewUCStringCopyN(cx, NS_REINTERPRET_CAST(const jschar *,
key.get()),
key.Length());
NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
JS_ValueToId(cx, STRING_TO_JSVAL(str), idp);
keys->RemoveElementAt(0);
break;
}
// Fall through
case JSENUMERATE_DESTROY:
delete keys;
*statep = JSVAL_NULL;
break;
default:
NS_NOTREACHED("Bad call from the JS engine");
return NS_ERROR_FAILURE;
}
return NS_OK;
}
// StorageList scriptable helper
nsresult
nsStorageListSH::GetNamedItem(nsISupports *aNative, const nsAString& aName,
nsISupports **aResult)
{
nsCOMPtr<nsIDOMStorageList> storagelist(do_QueryInterface(aNative));
NS_ENSURE_TRUE(storagelist, NS_ERROR_UNEXPECTED);
// Weak, transfer the ownership over to aResult
nsIDOMStorage* storage = nsnull;
nsresult rv = storagelist->NamedItem(aName, &storage);
*aResult = storage;
return rv;
}
// nsIDOMEventListener::HandleEvent() 'this' converter helper
NS_INTERFACE_MAP_BEGIN(nsEventListenerThisTranslator)

View File

@ -480,7 +480,7 @@ public:
JSObject **objp, PRBool *_retval);
NS_IMETHOD NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, PRUint32 enum_op, jsval *statep,
jsid *id, PRBool *_retval);
jsid *idp, PRBool *_retval);
NS_IMETHOD Finalize(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj);
NS_IMETHOD Equality(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
@ -1475,6 +1475,63 @@ public:
};
#endif
// WebApps Storage helpers
class nsStorageSH : public nsNamedArraySH
{
protected:
nsStorageSH(nsDOMClassInfoData* aData) : nsNamedArraySH(aData)
{
}
virtual ~nsStorageSH()
{
}
NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsval id, PRUint32 flags,
JSObject **objp, PRBool *_retval);
NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsval id, jsval *vp, PRBool *_retval);
NS_IMETHOD DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsval id, jsval *vp, PRBool *_retval);
NS_IMETHOD NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, PRUint32 enum_op, jsval *statep,
jsid *idp, PRBool *_retval);
// Override nsNamedArraySH::GetNamedItem()
virtual nsresult GetNamedItem(nsISupports *aNative, const nsAString& aName,
nsISupports **aResult);
public:
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
{
return new nsStorageSH(aData);
}
};
class nsStorageListSH : public nsNamedArraySH
{
protected:
nsStorageListSH(nsDOMClassInfoData* aData) : nsNamedArraySH(aData)
{
}
virtual ~nsStorageListSH()
{
}
// Override nsNamedArraySH::GetNamedItem()
virtual nsresult GetNamedItem(nsISupports *aNative, const nsAString& aName,
nsISupports **aResult);
public:
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
{
return new nsStorageListSH(aData);
}
};
// Event handler 'this' translator class, this is called by XPConnect
// when a "function interface" (nsIDOMEventListener) is called, this

View File

@ -47,6 +47,7 @@
#include "nsScreen.h"
#include "nsHistory.h"
#include "nsBarProps.h"
#include "nsDOMStorage.h"
// Helper Classes
#include "nsXPIDLString.h"
@ -82,6 +83,8 @@
#include "nsIDocCharset.h"
#include "nsIDocument.h"
#include "nsIHTMLDocument.h"
#include "nsIDOMHTMLDocument.h"
#include "nsIDOMHTMLElement.h"
#include "nsIDOMCrypto.h"
#include "nsIDOMDocument.h"
#include "nsIDOMNSDocument.h"
@ -336,7 +339,8 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
mTimeoutInsertionPoint(&mTimeouts),
mTimeoutPublicIdCounter(1),
mTimeoutFiringDepth(0),
mJSObject(nsnull)
mJSObject(nsnull),
mPendingStorageEvents(nsnull)
#ifdef DEBUG
, mSetOpenerWindowCalled(PR_FALSE)
#endif
@ -357,7 +361,12 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
if (os) {
// Watch for online/offline status changes so we can fire events. Use
// a strong reference.
os->AddObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC, PR_FALSE);
os->AddObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
PR_FALSE);
// Watch for dom-storage-chaged so we can fire storage
// events. Use a strong reference.
os->AddObserver(mObserver, "dom-storage-changed", PR_FALSE);
}
}
} else {
@ -404,7 +413,9 @@ nsGlobalWindow::~nsGlobalWindow()
do_GetService("@mozilla.org/observer-service;1");
if (os) {
os->RemoveObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
os->RemoveObserver(mObserver, "dom-storage-changed");
}
// Drop its reference to this dying window, in case for some bogus reason
// the object stays around.
mObserver->Forget();
@ -450,6 +461,8 @@ nsGlobalWindow::~nsGlobalWindow()
NS_ASSERTION(!mArguments, "mArguments wasn't cleaned up properly!");
CleanUp();
delete mPendingStorageEvents;
}
// static
@ -573,6 +586,7 @@ NS_INTERFACE_MAP_BEGIN(nsGlobalWindow)
NS_INTERFACE_MAP_ENTRY(nsPIDOMWindow)
NS_INTERFACE_MAP_ENTRY(nsIDOMViewCSS)
NS_INTERFACE_MAP_ENTRY(nsIDOMAbstractView)
NS_INTERFACE_MAP_ENTRY(nsIDOMStorageWindow)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window)
@ -5345,7 +5359,56 @@ nsGlobalWindow::GetDocument(nsIDOMDocumentView ** aDocumentView)
return rv;
}
///*****************************************************************************
//*****************************************************************************
// nsGlobalWindow::nsIDOMStorageWindow
//*****************************************************************************
NS_IMETHODIMP
nsGlobalWindow::GetSessionStorage(nsIDOMStorage ** aSessionStorage)
{
*aSessionStorage = nsnull;
FORWARD_TO_OUTER(GetSessionStorage, (aSessionStorage), NS_OK);
nsIPrincipal *principal = GetPrincipal();
if (!principal || !mDocShell) {
return NS_OK;
}
nsCOMPtr<nsIURI> codebase;
nsresult rv = principal->GetURI(getter_AddRefs(codebase));
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && codebase, rv);
nsCAutoString currentDomain;
rv = codebase->GetAsciiHost(currentDomain);
NS_ENSURE_SUCCESS(rv, rv);
return GetDocShell()->GetSessionStorageForDomain(currentDomain,
aSessionStorage);
}
NS_IMETHODIMP
nsGlobalWindow::GetGlobalStorage(nsIDOMStorageList ** aGlobalStorage)
{
NS_ENSURE_ARG_POINTER(aGlobalStorage);
#ifdef MOZ_STORAGE
if (!gGlobalStorageList) {
nsresult rv = NS_NewDOMStorageList(getter_AddRefs(gGlobalStorageList));
NS_ENSURE_SUCCESS(rv, rv);
}
*aGlobalStorage = gGlobalStorageList;
NS_IF_ADDREF(*aGlobalStorage);
return NS_OK;
#else
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
#endif
}
//*****************************************************************************
// nsGlobalWindow::nsIInterfaceRequestor
//*****************************************************************************
@ -5455,8 +5518,7 @@ nsGlobalWindow::FireOfflineStatusEvent()
}
nsresult
nsGlobalWindow::Observe(nsISupports* aSubject,
const char* aTopic,
nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic,
const PRUnichar* aData)
{
if (!nsCRT::strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC)) {
@ -5469,6 +5531,96 @@ nsGlobalWindow::Observe(nsISupports* aSubject,
}
return NS_OK;
}
if (IsInnerWindow() && !nsCRT::strcmp(aTopic, "dom-storage-changed")) {
nsIPrincipal *principal;
nsresult rv;
if (!aData) {
nsCOMPtr<nsIDOMStorage> storage;
GetSessionStorage(getter_AddRefs(storage));
if (storage != aSubject && !aData) {
// A sessionStorage object changed, but not our session storage
// object.
return NS_OK;
}
} else if ((principal = GetPrincipal())) {
// A global storage object changed, check to see if it's one
// this window can access.
nsCOMPtr<nsIURI> codebase;
principal->GetURI(getter_AddRefs(codebase));
if (!codebase) {
return NS_OK;
}
nsCAutoString currentDomain;
rv = codebase->GetAsciiHost(currentDomain);
if (NS_FAILED(rv)) {
return NS_OK;
}
if (!nsDOMStorageList::CanAccessDomain(nsDependentString(aData),
NS_ConvertASCIItoUTF16(currentDomain))) {
// This window can't reach the global storage object for the
// domain for which the change happened, so don't fire any
// events in this window.
return NS_OK;
}
}
if (mIsFrozen) {
// This window is frozen, rather than firing the events here,
// store the domain in which the change happened and fire the
// events if we're ever thawed.
if (!mPendingStorageEvents) {
mPendingStorageEvents = new nsDataHashtable<nsStringHashKey, PRBool>;
NS_ENSURE_TRUE(mPendingStorageEvents, NS_ERROR_OUT_OF_MEMORY);
rv = mPendingStorageEvents->Init();
NS_ENSURE_SUCCESS(rv, rv);
}
mPendingStorageEvents->Put(Substring(aData,
aData + nsCRT::strlen(aData)),
PR_TRUE);
return NS_OK;
}
nsAutoString domain(aData);
nsRefPtr<nsDOMStorageEvent> event = new nsDOMStorageEvent(domain);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
rv = event->Init();
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
nsCOMPtr<nsIDOMEventTarget> target;
if (htmlDoc) {
nsCOMPtr<nsIDOMHTMLElement> body;
htmlDoc->GetBody(getter_AddRefs(body));
target = do_QueryInterface(body);
}
if (!target) {
target = this;
}
PRBool defaultActionEnabled;
target->DispatchEvent((nsIDOMStorageEvent *)event, &defaultActionEnabled);
return NS_OK;
}
NS_WARNING("unrecognized topic in nsGlobalWindow::Observe");
return NS_ERROR_FAILURE;
}
@ -5544,7 +5696,16 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
const PRBool checkForPopup =
!aDialog && !WindowExists(aName, !aCalledNoScript);
// Grab the current codebase before we do any opening as that could
// change the current codebase.
nsIPrincipal *currentPrincipal = GetPrincipal();
nsCOMPtr<nsIURI> currentCodebase;
if (currentPrincipal) {
currentPrincipal->GetURI(getter_AddRefs(currentCodebase));
}
// These next two variables are only accessed when checkForPopup is true
PopupControlState abuseLevel;
OpenAllowValue allowReason;
@ -5654,8 +5815,6 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
domReturn.swap(*aReturn);
}
if (NS_SUCCEEDED(rv)) {
if (aDoJSFixups) {
nsCOMPtr<nsIDOMChromeWindow> chrome_win(do_QueryInterface(*aReturn));
@ -5693,6 +5852,38 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
FireAbuseEvents(PR_FALSE, PR_TRUE, aUrl, aName, aOptions);
}
}
// copy the session storage data over to the new window if
// necessary. If the new window has the same domain as this window
// did at the beginning of this function, the session storage data
// for that domain, and only that domain, is copied over.
nsGlobalWindow *opened = NS_STATIC_CAST(nsGlobalWindow *, *aReturn);
nsIDocShell* newDocShell = opened->GetDocShell();
if (currentCodebase && newDocShell && mDocShell && url.get()) {
nsCOMPtr<nsIURI> newURI;
JSContext *cx;
PRBool freePass;
BuildURIfromBase(url, getter_AddRefs(newURI), &freePass, &cx);
if (newURI) {
nsCAutoString thisDomain, newDomain;
nsresult gethostrv = currentCodebase->GetAsciiHost(thisDomain);
gethostrv |= newURI->GetAsciiHost(newDomain);
if (NS_SUCCEEDED(gethostrv) && thisDomain.Equals(newDomain)) {
nsCOMPtr<nsIDOMStorage> storage;
mDocShell->GetSessionStorageForDomain(thisDomain,
getter_AddRefs(storage));
nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(storage);
if (piStorage) {
nsCOMPtr<nsIDOMStorage> newstorage = piStorage->Clone();
newDocShell->AddSessionStorage(thisDomain, newstorage);
}
}
}
}
return rv;
}
@ -6757,6 +6948,22 @@ nsGlobalWindow::SaveWindowState(nsISupports **aState)
return NS_OK;
}
PR_STATIC_CALLBACK(PLDHashOperator)
FirePendingStorageEvents(const nsAString& aKey, PRBool aData, void *userArg)
{
nsGlobalWindow *win = NS_STATIC_CAST(nsGlobalWindow *, userArg);
nsCOMPtr<nsIDOMStorage> storage;
win->GetSessionStorage(getter_AddRefs(storage));
if (storage) {
win->Observe(storage, "dom-storage-changed",
aKey.IsEmpty() ? nsnull : PromiseFlatString(aKey).get());
}
return PL_DHASH_NEXT;
}
nsresult
nsGlobalWindow::RestoreWindowState(nsISupports *aState)
{
@ -6820,6 +7027,15 @@ nsGlobalWindow::RestoreWindowState(nsISupports *aState)
holder->DidRestoreWindow();
if (inner->mPendingStorageEvents) {
// Fire pending storage events.
inner->mPendingStorageEvents->EnumerateRead(FirePendingStorageEvents,
inner);
delete inner->mPendingStorageEvents;
inner->mPendingStorageEvents = nsnull;
}
return NS_OK;
}

View File

@ -49,6 +49,7 @@
#include "nsAutoPtr.h"
#include "nsWeakReference.h"
#include "nsHashtable.h"
#include "nsDataHashtable.h"
// Interfaces Needed
#include "nsDOMWindowList.h"
@ -56,7 +57,6 @@
#include "nsIBrowserDOMWindow.h"
#include "nsIChromeEventHandler.h"
#include "nsIControllers.h"
#include "nsIObserver.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDOMViewCSS.h"
@ -90,6 +90,9 @@
#include "mozFlushType.h"
#include "prclist.h"
#include "nsIDOMGCParticipant.h"
#include "nsIDOMStorage.h"
#include "nsIDOMStorageList.h"
#include "nsIDOMStorageWindow.h"
#define DEFAULT_HOME_PAGE "www.mozilla.org"
#define PREF_BROWSER_STARTUP_HOMEPAGE "browser.startup.homepage"
@ -147,6 +150,7 @@ class nsGlobalWindow : public nsPIDOMWindow,
public nsIDOM3EventTarget,
public nsIDOMNSEventTarget,
public nsIDOMViewCSS,
public nsIDOMStorageWindow,
public nsSupportsWeakReference,
public nsIInterfaceRequestor,
public PRCListStr
@ -250,6 +254,9 @@ public:
// nsIDOMAbstractView
NS_DECL_NSIDOMABSTRACTVIEW
// nsIDOMStorageWindow
NS_DECL_NSIDOMSTORAGEWINDOW
// nsIInterfaceRequestor
NS_DECL_NSIINTERFACEREQUESTOR
@ -290,8 +297,9 @@ public:
{
return mIsFrozen;
}
nsresult Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aData);
nsresult Observe(nsISupports* aSubject, const char* aTopic,
const PRUnichar* aData);
static void ShutDown();
static PRBool IsCallerChrome();
@ -513,6 +521,8 @@ protected:
nsCOMPtr<nsIDOMCrypto> mCrypto;
nsCOMPtr<nsIDOMPkcs11> mPkcs11;
nsCOMPtr<nsIDOMStorageList> gGlobalStorageList;
nsCOMPtr<nsIXPConnectJSObjectHolder> mInnerWindowHolder;
nsCOMPtr<nsIPrincipal> mOpenerScriptPrincipal; // strong; used to determine
// whether to clear scope
@ -523,12 +533,15 @@ protected:
nsTimeout** mTimeoutInsertionPoint;
PRUint32 mTimeoutPublicIdCounter;
PRUint32 mTimeoutFiringDepth;
nsCOMPtr<nsIDOMStorage> mSessionStorage;
// These member variables are used on both inner and the outer windows.
nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
nsCOMPtr<nsIDocument> mDoc; // For fast access to principals
JSObject* mJSObject;
nsDataHashtable<nsStringHashKey, PRBool> *mPendingStorageEvents;
#ifdef DEBUG
PRBool mSetOpenerWindowCalled;
#endif

View File

@ -0,0 +1,85 @@
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# Netscape Communications Corporation.
# Portions created by the Initial Developer are Copyright (C) 1998
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = dom
LIBRARY_NAME = jsdomstorage_s
MOZILLA_INTERNAL_API = 1
REQUIRES = xpcom \
string \
content \
caps \
gfx \
js \
layout \
locale \
necko \
pref \
unicharutil \
widget \
xpconnect \
$(NULL)
ifdef MOZ_STORAGE
REQUIRES += storage
endif
CPPSRCS = \
nsDOMStorage.cpp \
$(NULL)
ifdef MOZ_STORAGE
CPPSRCS += nsDOMStorageDB.cpp
endif
# we don't want the shared lib, but we want to force the creation of a static lib.
FORCE_STATIC_LIB = 1
LOCAL_INCLUDES = \
-I$(srcdir)/../base \
-I$(topsrcdir)/content/events/src
DEFINES += -D_IMPL_NS_LAYOUT
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,910 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Neil Deakin <enndeakin@sympatico.ca>
* Johnny Stenback <jst@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsCOMPtr.h"
#include "nsDOMError.h"
#include "nsDOMClassInfo.h"
#include "nsUnicharUtils.h"
#include "nsIDocument.h"
#include "nsDOMStorage.h"
#include "nsContentUtils.h"
#include "nsIScriptSecurityManager.h"
#include "nsIPrincipal.h"
#include "nsIURI.h"
#include "nsReadableUtils.h"
#include "nsIObserverService.h"
//
// Helper that tells us whether the caller is secure or not.
//
static PRBool
IsCallerSecure()
{
nsCOMPtr<nsIDocument> callerDoc =
do_QueryInterface(nsContentUtils::GetDocumentFromCaller());
if (!callerDoc) {
return PR_FALSE;
}
nsIURI *uri = callerDoc->GetDocumentURI();
if (!uri) {
return PR_FALSE;
}
PRBool isHttps = PR_FALSE;
nsresult rv = uri->SchemeIs("https", &isHttps);
return NS_SUCCEEDED(rv) && isHttps;
}
//
// nsDOMStorage
//
#ifdef MOZ_STORAGE
nsDOMStorageDB* nsDOMStorage::gStorageDB = nsnull;
#endif
NS_INTERFACE_MAP_BEGIN(nsDOMStorage)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStorage)
NS_INTERFACE_MAP_ENTRY(nsIDOMStorage)
NS_INTERFACE_MAP_ENTRY(nsPIDOMStorage)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Storage)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsDOMStorage)
NS_IMPL_RELEASE(nsDOMStorage)
nsresult
NS_NewDOMStorage(nsISupports* aOuter, REFNSIID aIID, void** aResult)
{
nsDOMStorage* storage = new nsDOMStorage();
if (!storage)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(storage);
*aResult = storage;
return NS_OK;
}
nsDOMStorage::nsDOMStorage()
: mUseDB(PR_FALSE), mItemsCached(PR_FALSE)
{
mItems.Init(8);
}
nsDOMStorage::nsDOMStorage(const nsAString& aDomain, PRBool aUseDB)
: mUseDB(aUseDB), mItemsCached(PR_FALSE), mDomain(aDomain)
{
#ifndef MOZ_STORAGE
mUseDB = PR_FALSE;
#endif
mItems.Init(8);
}
nsDOMStorage::~nsDOMStorage()
{
}
void
nsDOMStorage::Init(const nsAString& aDomain, PRBool aUseDB)
{
mDomain.Assign(aDomain);
#ifdef MOZ_STORAGE
mUseDB = aUseDB;
#else
mUseDB = PR_FALSE;
#endif
}
class ItemCounterState
{
public:
ItemCounterState(PRBool aIsCallerSecure)
: mIsCallerSecure(aIsCallerSecure), mCount(0)
{
}
PRBool mIsCallerSecure;
PRBool mCount;
private:
ItemCounterState(); // Not to be implemented
};
PR_STATIC_CALLBACK(PLDHashOperator)
ItemCounter(nsSessionStorageEntry* aEntry, void* userArg)
{
ItemCounterState *state = (ItemCounterState *)userArg;
if (state->mIsCallerSecure || !aEntry->mItem->IsSecure()) {
++state->mCount;
}
return PL_DHASH_NEXT;
}
NS_IMETHODIMP
nsDOMStorage::GetLength(PRUint32 *aLength)
{
if (mUseDB)
CacheKeysFromDB();
ItemCounterState state(IsCallerSecure());
mItems.EnumerateEntries(ItemCounter, &state);
*aLength = state.mCount;
return NS_OK;
}
class IndexFinderData
{
public:
IndexFinderData(PRBool aIsCallerSecure, PRUint32 aWantedIndex)
: mIsCallerSecure(aIsCallerSecure), mIndex(0), mWantedIndex(aWantedIndex),
mItem(nsnull)
{
}
PRBool mIsCallerSecure;
PRUint32 mIndex;
PRUint32 mWantedIndex;
nsSessionStorageEntry *mItem;
private:
IndexFinderData(); // Not to be implemented
};
PR_STATIC_CALLBACK(PLDHashOperator)
IndexFinder(nsSessionStorageEntry* aEntry, void* userArg)
{
IndexFinderData *data = (IndexFinderData *)userArg;
if (data->mIndex == data->mWantedIndex &&
(data->mIsCallerSecure || !aEntry->mItem->IsSecure())) {
data->mItem = aEntry;
return PL_DHASH_STOP;
}
++data->mIndex;
return PL_DHASH_NEXT;
}
NS_IMETHODIMP
nsDOMStorage::Key(PRUint32 aIndex, nsAString& aKey)
{
// XXXjst: This is as retarded as the DOM spec is, takes an unsigned
// int, but the spec talks about what to do if a negative value is
// passed in.
// XXX: This does a linear search for the key at index, which would
// suck if there's a large numer of indexes. Do we care? If so,
// maybe we need to have a lazily populated key array here or
// something?
if (mUseDB)
CacheKeysFromDB();
IndexFinderData data(IsCallerSecure(), aIndex);
mItems.EnumerateEntries(IndexFinder, &data);
if (!data.mItem) {
// aIndex was larger than the number of accessible keys. Throw.
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
aKey = data.mItem->GetKey();
return NS_OK;
}
NS_IMETHODIMP
nsDOMStorage::GetItem(const nsAString& aKey, nsIDOMStorageItem **aItem)
{
*aItem = nsnull;
if (aKey.IsEmpty())
return NS_OK;
nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
if (entry) {
if (!IsCallerSecure() && entry->mItem->IsSecure()) {
return NS_OK;
}
NS_ADDREF(*aItem = entry->mItem);
}
else if (mUseDB) {
PRBool secure;
nsAutoString value;
nsresult rv = GetDBValue(aKey, value, &secure);
// return null if access isn't allowed or the key wasn't found
if (rv == NS_ERROR_DOM_SECURITY_ERR || rv == NS_ERROR_DOM_NOT_FOUND_ERR)
return NS_OK;
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<nsDOMStorageItem> newitem =
new nsDOMStorageItem(this, aKey, secure);
if (!newitem)
return NS_ERROR_OUT_OF_MEMORY;
entry = mItems.PutEntry(aKey);
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
entry->mItem = newitem;
NS_ADDREF(*aItem = newitem);
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMStorage::SetItem(const nsAString& aKey, const nsAString& aData)
{
if (aKey.IsEmpty())
return NS_OK;
nsresult rv;
nsRefPtr<nsDOMStorageItem> newitem = nsnull;
nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
if (entry) {
if (entry->mItem->IsSecure() && !IsCallerSecure()) {
return NS_ERROR_DOM_SECURITY_ERR;
}
if (!mUseDB) {
rv = entry->mItem->SetValue(aData);
NS_ENSURE_SUCCESS(rv, rv);
}
}
else {
if (mUseDB)
newitem = new nsDOMStorageItem(this, aKey, PR_FALSE);
else
newitem = new nsDOMStorageItem(nsnull, aData, PR_FALSE);
if (!newitem)
return NS_ERROR_OUT_OF_MEMORY;
}
if (mUseDB) {
rv = SetDBValue(aKey, aData, IsCallerSecure());
NS_ENSURE_SUCCESS(rv, rv);
}
if (newitem) {
entry = mItems.PutEntry(aKey);
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
entry->mItem = newitem;
}
// SetDBValue already calls BroadcastChangeNotification so don't do it again
if (!mUseDB)
BroadcastChangeNotification();
return NS_OK;
}
NS_IMETHODIMP nsDOMStorage::RemoveItem(const nsAString& aKey)
{
if (aKey.IsEmpty())
return NS_OK;
nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
if (entry && entry->mItem->IsSecure() && !IsCallerSecure()) {
return NS_ERROR_DOM_SECURITY_ERR;
}
if (mUseDB) {
#ifdef MOZ_STORAGE
nsresult rv = InitDB();
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString unused;
PRBool secureItem;
rv = GetDBValue(aKey, unused, &secureItem);
if (rv == NS_ERROR_DOM_NOT_FOUND_ERR)
return NS_OK;
NS_ENSURE_SUCCESS(rv, rv);
rv = gStorageDB->RemoveKey(mDomain, aKey);
NS_ENSURE_SUCCESS(rv, rv);
mItemsCached = PR_FALSE;
#endif
}
else if (entry) {
// clear string as StorageItems may be referencing this item
entry->mItem->ClearValue();
}
mItems.RawRemoveEntry(entry);
BroadcastChangeNotification();
return NS_OK;
}
nsresult
nsDOMStorage::InitDB()
{
#ifdef MOZ_STORAGE
if (!gStorageDB) {
gStorageDB = new nsDOMStorageDB();
if (!gStorageDB)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = gStorageDB->Init();
if (NS_FAILED(rv)) {
// Failed to initialize the DB, delete it and null out the
// pointer so we don't end up attempting to use an
// un-initialized DB later on.
delete gStorageDB;
gStorageDB = nsnull;
return rv;
}
}
#endif
return NS_OK;
}
nsresult
nsDOMStorage::CacheKeysFromDB()
{
#ifdef MOZ_STORAGE
// cache all the keys in the hash. This is used by the Length and Key methods
// use this cache for better performance. The disadvantage is that the
// order may break if someone changes the keys in the database directly.
if (!mItemsCached) {
nsresult rv = InitDB();
NS_ENSURE_SUCCESS(rv, rv);
rv = gStorageDB->GetAllKeys(mDomain, this, &mItems);
NS_ENSURE_SUCCESS(rv, rv);
mItemsCached = PR_TRUE;
}
#endif
return NS_OK;
}
nsresult
nsDOMStorage::GetDBValue(const nsAString& aKey, nsAString& aValue,
PRBool* aSecure)
{
aValue.Truncate();
#ifdef MOZ_STORAGE
NS_ASSERTION(mUseDB,
"Uh, we should only get here if we're using the database!");
nsresult rv = InitDB();
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString value;
rv = gStorageDB->GetKeyValue(mDomain, aKey, value, aSecure);
if (NS_FAILED(rv))
return rv;
if (!IsCallerSecure() && *aSecure) {
return NS_ERROR_DOM_SECURITY_ERR;
}
aValue.Assign(value);
#endif
return NS_OK;
}
nsresult
nsDOMStorage::SetDBValue(const nsAString& aKey,
const nsAString& aValue,
PRBool aSecure)
{
#ifdef MOZ_STORAGE
NS_ASSERTION(mUseDB,
"Uh, we should only get here if we're using the database!");
nsresult rv = InitDB();
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString value;
rv = gStorageDB->SetKey(mDomain, aKey, aValue, aSecure);
NS_ENSURE_SUCCESS(rv, rv);
mItemsCached = PR_FALSE;
BroadcastChangeNotification();
#endif
return NS_OK;
}
nsresult
nsDOMStorage::SetSecure(const nsAString& aKey, PRBool aSecure)
{
#ifdef MOZ_STORAGE
if (mUseDB) {
nsresult rv = InitDB();
NS_ENSURE_SUCCESS(rv, rv);
return gStorageDB->SetSecure(mDomain, aKey, aSecure);
}
#else
return NS_ERROR_NOT_IMPLEMENTED;
#endif
nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
NS_ASSERTION(entry, "Don't use SetSecure() with non-existing keys!");
if (entry) {
entry->mItem->SetSecureInternal(aSecure);
}
return NS_OK;
}
PR_STATIC_CALLBACK(PLDHashOperator)
CopyStorageItems(nsSessionStorageEntry* aEntry, void* userArg)
{
nsDOMStorage* newstorage = NS_STATIC_CAST(nsDOMStorage*, userArg);
newstorage->SetItem(aEntry->GetKey(), aEntry->mItem->GetValueInternal());
if (aEntry->mItem->IsSecure()) {
newstorage->SetSecure(aEntry->GetKey(), PR_TRUE);
}
return PL_DHASH_NEXT;
}
already_AddRefed<nsIDOMStorage>
nsDOMStorage::Clone()
{
if (mUseDB) {
NS_ERROR("Uh, don't clone a global storage object.");
return nsnull;
}
nsDOMStorage* storage = new nsDOMStorage(mDomain, PR_FALSE);
if (!storage)
return nsnull;
mItems.EnumerateEntries(CopyStorageItems, storage);
NS_ADDREF(storage);
return storage;
}
struct KeysArrayBuilderStruct
{
PRBool callerIsSecure;
nsTArray<nsString> *keys;
};
PR_STATIC_CALLBACK(PLDHashOperator)
KeysArrayBuilder(nsSessionStorageEntry* aEntry, void* userArg)
{
KeysArrayBuilderStruct *keystruct = (KeysArrayBuilderStruct *)userArg;
if (keystruct->callerIsSecure || !aEntry->mItem->IsSecure())
keystruct->keys->AppendElement(aEntry->GetKey());
return PL_DHASH_NEXT;
}
nsTArray<nsString> *
nsDOMStorage::GetKeys()
{
if (mUseDB)
CacheKeysFromDB();
KeysArrayBuilderStruct keystruct;
keystruct.callerIsSecure = IsCallerSecure();
keystruct.keys = new nsTArray<nsString>();
if (keystruct.keys)
mItems.EnumerateEntries(KeysArrayBuilder, &keystruct);
return keystruct.keys;
}
void
nsDOMStorage::BroadcastChangeNotification()
{
nsresult rv;
nsCOMPtr<nsIObserverService> observerService =
do_GetService("@mozilla.org/observer-service;1", &rv);
if (NS_FAILED(rv)) {
return;
}
// Fire off a notification that a storage object changed. If the
// storage object is a session storage object, we don't pass a
// domain, but if it's a global storage object we do.
observerService->NotifyObservers((nsIDOMStorage *)this,
"dom-storage-changed",
mUseDB ? mDomain.get() : nsnull);
}
//
// nsDOMStorageList
//
NS_INTERFACE_MAP_BEGIN(nsDOMStorageList)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsIDOMStorageList)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(StorageList)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsDOMStorageList)
NS_IMPL_RELEASE(nsDOMStorageList)
nsresult
nsDOMStorageList::NamedItem(const nsAString& aDomain,
nsIDOMStorage** aStorage)
{
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
if (!ssm)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIPrincipal> subjectPrincipal;
nsresult rv = ssm->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPrincipal> systemPrincipal;
rv = ssm->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString currentDomain;
if (subjectPrincipal) {
nsCOMPtr<nsIURI> uri;
rv = subjectPrincipal->GetURI(getter_AddRefs(uri));
if (NS_SUCCEEDED(rv) && uri) {
rv = uri->GetAsciiHost(currentDomain);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SECURITY_ERR);
}
}
if (subjectPrincipal == systemPrincipal || !currentDomain.IsEmpty()) {
return GetStorageForDomain(aDomain, NS_ConvertUTF8toUTF16(currentDomain),
subjectPrincipal == systemPrincipal, aStorage);
}
return NS_ERROR_DOM_SECURITY_ERR;
}
// static
PRBool
nsDOMStorageList::CanAccessDomain(const nsAString& aRequestedDomain,
const nsAString& aCurrentDomain)
{
nsStringArray requestedDomainArray, currentDomainArray;
PRBool ok = ConvertDomainToArray(aRequestedDomain, &requestedDomainArray);
if (!ok)
return PR_FALSE;
ok = ConvertDomainToArray(aCurrentDomain, &currentDomainArray);
if (!ok)
return PR_FALSE;
if (currentDomainArray.Count() == 1)
currentDomainArray.AppendString(NS_LITERAL_STRING("localdomain"));
// need to use the shorter of the two arrays
PRInt32 currentPos = 0;
PRInt32 requestedPos = 0;
PRInt32 length = requestedDomainArray.Count();
if (currentDomainArray.Count() > length)
currentPos = currentDomainArray.Count() - length;
else if (currentDomainArray.Count() < length)
requestedPos = length - currentDomainArray.Count();
// If the current domain is different in any of the parts from the
// requested domain, a security exception is raised
for (; requestedPos < length; requestedPos++, currentPos++) {
if (*requestedDomainArray[requestedPos] != *currentDomainArray[currentPos])
return PR_FALSE;
}
return PR_TRUE;
}
nsresult
nsDOMStorageList::GetStorageForDomain(const nsAString& aRequestedDomain,
const nsAString& aCurrentDomain,
PRBool aNoCurrentDomainCheck,
nsIDOMStorage** aStorage)
{
if (!aNoCurrentDomainCheck && !CanAccessDomain(aRequestedDomain,
aCurrentDomain)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
nsStringArray requestedDomainArray;
PRBool ok = ConvertDomainToArray(aRequestedDomain, &requestedDomainArray);
if (!ok)
return NS_ERROR_DOM_SECURITY_ERR;
// now rebuild a string for the domain.
nsAutoString usedDomain;
PRInt32 requestedPos = 0;
for (requestedPos = 0; requestedPos < requestedDomainArray.Count();
requestedPos++) {
if (!usedDomain.IsEmpty())
usedDomain.AppendLiteral(".");
usedDomain.Append(*requestedDomainArray[requestedPos]);
}
// now have a valid domain, so look it up in the storage table
if (!mStorages.Get(usedDomain, aStorage)) {
nsCOMPtr<nsIDOMStorage> newstorage = new nsDOMStorage(usedDomain, PR_TRUE);
if (!newstorage)
return NS_ERROR_OUT_OF_MEMORY;
if (!mStorages.Put(usedDomain, newstorage))
return NS_ERROR_OUT_OF_MEMORY;
newstorage.swap(*aStorage);
}
return NS_OK;
}
// static
PRBool
nsDOMStorageList::ConvertDomainToArray(const nsAString& aDomain,
nsStringArray* aArray)
{
PRInt32 length = aDomain.Length();
PRInt32 n = 0;
while (n < length) {
PRInt32 dotpos = aDomain.FindChar('.', n);
nsAutoString domain;
if (dotpos == -1) // no more dots
domain.Assign(Substring(aDomain, n));
else if (dotpos - n == 0) // no point continuing in this case
return false;
else if (dotpos >= 0)
domain.Assign(Substring(aDomain, n, dotpos - n));
ToLowerCase(domain);
aArray->AppendString(domain);
if (dotpos == -1)
break;
n = dotpos + 1;
}
// if n equals the length, there is a dot at the end, so treat it as invalid
return (n != length);
}
nsresult
NS_NewDOMStorageList(nsIDOMStorageList** aResult)
{
*aResult = new nsDOMStorageList();
if (!*aResult)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult);
return NS_OK;
}
//
// nsDOMStorageItem
//
NS_INTERFACE_MAP_BEGIN(nsDOMStorageItem)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStorageItem)
NS_INTERFACE_MAP_ENTRY(nsIDOMStorageItem)
NS_INTERFACE_MAP_ENTRY(nsIDOMToString)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(StorageItem)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsDOMStorageItem)
NS_IMPL_RELEASE(nsDOMStorageItem)
nsDOMStorageItem::nsDOMStorageItem(nsDOMStorage* aStorage,
const nsAString& aKey,
PRBool aSecure)
: mSecure(aSecure),
mKeyOrValue(aKey),
mStorage(aStorage)
{
}
nsDOMStorageItem::~nsDOMStorageItem()
{
}
NS_IMETHODIMP
nsDOMStorageItem::GetSecure(PRBool* aSecure)
{
if (!IsCallerSecure()) {
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
}
if (mStorage) {
nsAutoString value;
return mStorage->GetDBValue(mKeyOrValue, value, aSecure);
}
*aSecure = IsSecure();
return NS_OK;
}
NS_IMETHODIMP
nsDOMStorageItem::SetSecure(PRBool aSecure)
{
if (!IsCallerSecure()) {
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
}
if (mStorage) {
nsresult rv = mStorage->SetSecure(mKeyOrValue, aSecure);
NS_ENSURE_SUCCESS(rv, rv);
}
mSecure = aSecure;
return NS_OK;
}
NS_IMETHODIMP
nsDOMStorageItem::GetValue(nsAString& aValue)
{
if (mStorage) {
// GetDBValue checks the secure state so no need to do it here
PRBool secure;
nsresult rv = mStorage->GetDBValue(mKeyOrValue, aValue, &secure);
return (rv == NS_ERROR_DOM_NOT_FOUND_ERR) ? NS_OK : rv;
}
if (IsSecure() && !IsCallerSecure()) {
return NS_ERROR_DOM_SECURITY_ERR;
}
aValue = mKeyOrValue;
return NS_OK;
}
NS_IMETHODIMP
nsDOMStorageItem::SetValue(const nsAString& aValue)
{
PRBool secureCaller = IsCallerSecure();
if (mStorage) {
// SetDBValue() does the security checks for us.
return mStorage->SetDBValue(mKeyOrValue, aValue, secureCaller);
}
PRBool secureItem = IsSecure();
if (!secureCaller && secureItem) {
// The item is secure, but the caller isn't. Throw.
return NS_ERROR_DOM_SECURITY_ERR;
}
mKeyOrValue = aValue;
mSecure = secureCaller;
return NS_OK;
}
NS_IMETHODIMP
nsDOMStorageItem::ToString(nsAString& aStr)
{
return GetValue(aStr);
}
// QueryInterface implementation for nsDOMStorageEvent
NS_INTERFACE_MAP_BEGIN(nsDOMStorageEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMStorageEvent)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(StorageEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
NS_IMPL_ADDREF_INHERITED(nsDOMStorageEvent, nsDOMEvent)
NS_IMPL_RELEASE_INHERITED(nsDOMStorageEvent, nsDOMEvent)
NS_IMETHODIMP
nsDOMStorageEvent::GetDomain(nsAString& aDomain)
{
// mDomain will be #session for session storage for events that fire
// due to a change in a session storage object.
aDomain = mDomain;
return NS_OK;
}
nsresult
nsDOMStorageEvent::Init()
{
nsresult rv = InitEvent(NS_LITERAL_STRING("storage"), PR_TRUE, PR_FALSE);
// This init method is only called by native code, so set the
// trusted flag here.
SetTrusted(PR_TRUE);
return NS_OK;
}
NS_IMETHODIMP
nsDOMStorageEvent::InitStorageEvent(const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
const nsAString& aDomainArg)
{
nsresult rv = InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg);
NS_ENSURE_SUCCESS(rv, rv);
mDomain = aDomainArg;
return NS_OK;
}
NS_IMETHODIMP
nsDOMStorageEvent::InitStorageEventNS(const nsAString& aNamespaceURIArg,
const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
const nsAString& aDomainArg)
{
// XXXjst: Figure out what to do with aNamespaceURIArg here!
nsresult rv = InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg);
NS_ENSURE_SUCCESS(rv, rv);
mDomain = aDomainArg;
return NS_OK;
}

View File

@ -0,0 +1,279 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Neil Deakin <enndeakin@sympatico.ca>
* Johnny Stenback <jst@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsDOMStorage_h___
#define nsDOMStorage_h___
#include "nscore.h"
#include "nsAutoPtr.h"
#include "nsIDOMStorage.h"
#include "nsIDOMStorageList.h"
#include "nsIDOMStorageItem.h"
#include "nsInterfaceHashtable.h"
#include "nsVoidArray.h"
#include "nsPIDOMStorage.h"
#include "nsIDOMToString.h"
#include "nsDOMEvent.h"
#include "nsIDOMStorageEvent.h"
#ifdef MOZ_STORAGE
#include "nsDOMStorageDB.h"
#endif
class nsDOMStorageItem;
class nsSessionStorageEntry : public nsStringHashKey
{
public:
nsSessionStorageEntry(KeyTypePointer aStr) : nsStringHashKey(aStr)
{
}
nsSessionStorageEntry(const nsSessionStorageEntry& aToCopy)
: nsStringHashKey(aToCopy)
{
NS_ERROR("We're horked.");
}
nsRefPtr<nsDOMStorageItem> mItem;
};
class nsDOMStorage : public nsIDOMStorage,
public nsPIDOMStorage
{
public:
nsDOMStorage();
nsDOMStorage(const nsAString& aDomain, PRBool aUseDB);
virtual ~nsDOMStorage();
// nsISupports
NS_DECL_ISUPPORTS
// nsIDOMStorage
NS_DECL_NSIDOMSTORAGE
// nsPIDOMStorage
virtual void Init(const nsAString& aDomain, PRBool aUseDB);
virtual already_AddRefed<nsIDOMStorage> Clone();
virtual nsTArray<nsString> *GetKeys();
// cache the keys from the database for faster lookup
nsresult
CacheKeysFromDB();
// retrieve the value and secure state corresponding to a key out of storage.
nsresult
GetDBValue(const nsAString& aKey, nsAString& aValue, PRBool* aSecure);
// set the value corresponding to a key in the storage. If
// aSecure is false, then attempts to modify a secure value
// throw NS_ERROR_DOM_INVALID_ACCESS_ERR
nsresult
SetDBValue(const nsAString& aKey,
const nsAString& aValue,
PRBool aSecure);
// set the value corresponding to a key as secure.
nsresult
SetSecure(const nsAString& aKey, PRBool aSecure);
protected:
nsresult InitDB();
void BroadcastChangeNotification();
// true if the storage database should be used for values
PRBool mUseDB;
// true if items from the database are cached
PRBool mItemsCached;
// domain this store is associated with
nsAutoString mDomain;
// the key->value item pairs
nsTHashtable<nsSessionStorageEntry> mItems;
#ifdef MOZ_STORAGE
static nsDOMStorageDB* gStorageDB;
#endif
};
class nsDOMStorageList : public nsIDOMStorageList
{
public:
nsDOMStorageList()
{
mStorages.Init();
};
virtual ~nsDOMStorageList() {};
// nsISupports
NS_DECL_ISUPPORTS
// nsIDOMStorageList
NS_DECL_NSIDOMSTORAGELIST
/**
* Return the global nsIDOMStorage for a particular domain.
* aNoCurrentDomainCheck may be true to skip the domain comparison;
* this is used for chrome code so that it may retrieve data from
* any domain.
*
* @param aRequestedDomain domain to return
* @param aCurrentDomain domain of current caller
* @param aNoCurrentDomainCheck true to skip domain comparison
*/
nsresult
GetStorageForDomain(const nsAString& aRequestedDomain,
const nsAString& aCurrentDomain,
PRBool aNoCurrentDomainCheck,
nsIDOMStorage** aStorage);
/**
* Convert the domain into an array of its component parts.
*/
static PRBool
ConvertDomainToArray(const nsAString& aDomain,
nsStringArray* aArray);
/**
* Check whether aCurrentDomain has access to aRequestedDomain
*/
static PRBool
CanAccessDomain(const nsAString& aRequestedDomain,
const nsAString& aCurrentDomain);
protected:
nsInterfaceHashtable<nsStringHashKey, nsIDOMStorage> mStorages;
};
class nsDOMStorageItem : public nsIDOMStorageItem,
public nsIDOMToString
{
public:
nsDOMStorageItem(nsDOMStorage* aStorage,
const nsAString& aKey,
PRBool aSecure);
virtual ~nsDOMStorageItem();
// nsISupports
NS_DECL_ISUPPORTS
// nsIDOMStorage
NS_DECL_NSIDOMSTORAGEITEM
// nsIDOMToString
NS_DECL_NSIDOMTOSTRING
PRBool IsSecure()
{
return mSecure;
}
void SetSecureInternal(PRBool aSecure)
{
mSecure = aSecure;
}
const nsAString& GetValueInternal()
{
NS_ASSERTION(!mStorage, "Don't call this on global storage items!");
return mKeyOrValue;
}
void ClearValue()
{
NS_ASSERTION(!mStorage, "Don't call this on global storage items!");
mKeyOrValue.Truncate();
}
protected:
// true if this value is for secure sites only
PRBool mSecure;
// value of the item, or key for the item if it came from the db.
nsString mKeyOrValue;
// If this item came from the db, mStorage points to the storage
// object where this item came from.
nsRefPtr<nsDOMStorage> mStorage;
};
class nsDOMStorageEvent : public nsDOMEvent,
public nsIDOMStorageEvent
{
public:
nsDOMStorageEvent(const nsAString& aDomain)
: nsDOMEvent(nsnull, nsnull), mDomain(aDomain)
{
if (aDomain.IsEmpty()) {
// An empty domain means this event is for a session sotrage
// object change. Store #session as the domain.
mDomain = NS_LITERAL_STRING("#session");
}
}
virtual ~nsDOMStorageEvent()
{
}
nsresult Init();
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMSTORAGEEVENT
NS_FORWARD_NSIDOMEVENT(nsDOMEvent::)
protected:
nsString mDomain;
};
nsresult
NS_NewDOMStorage(nsISupports* aOuter, REFNSIID aIID, void** aResult);
nsresult
NS_NewDOMStorageList(nsIDOMStorageList** aResult);
#endif /* nsDOMStorage_h___ */

View File

@ -0,0 +1,302 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Neil Deakin <enndeakin@sympatico.ca>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsCOMPtr.h"
#include "nsDOMError.h"
#include "nsDOMStorage.h"
#include "nsDOMStorageDB.h"
#include "nsIFile.h"
#include "nsAppDirectoryServiceDefs.h"
#include "mozStorageCID.h"
#include "mozStorageHelper.h"
#include "mozIStorageService.h"
#include "mozIStorageValueArray.h"
nsresult
nsDOMStorageDB::Init()
{
nsresult rv;
nsCOMPtr<nsIFile> storageFile;
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(storageFile));
NS_ENSURE_SUCCESS(rv, rv);
rv = storageFile->Append(NS_LITERAL_STRING("webappsstore.sqlite"));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<mozIStorageService> service;
service = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = service->OpenDatabase(storageFile, getter_AddRefs(mConnection));
NS_ENSURE_SUCCESS(rv, rv);
PRBool exists;
rv = mConnection->TableExists(NS_LITERAL_CSTRING("moz_webappsstore"), &exists);
NS_ENSURE_SUCCESS(rv, rv);
if (! exists) {
rv = mConnection->ExecuteSimpleSQL(
NS_LITERAL_CSTRING("CREATE TABLE moz_webappsstore ("
"domain TEXT, "
"key TEXT, "
"value TEXT, "
"secure INTEGER) "));
NS_ENSURE_SUCCESS(rv, rv);
}
// retrieve all keys associated with a domain
rv = mConnection->CreateStatement(
NS_LITERAL_CSTRING("SELECT key, secure FROM moz_webappsstore "
"WHERE domain = ?1"),
getter_AddRefs(mGetAllKeysStatement));
NS_ENSURE_SUCCESS(rv, rv);
// retrieve a value given a domain and a key
rv = mConnection->CreateStatement(
NS_LITERAL_CSTRING("SELECT value, secure FROM moz_webappsstore "
"WHERE domain = ?1 "
"AND key = ?2"),
getter_AddRefs(mGetKeyValueStatement));
NS_ENSURE_SUCCESS(rv, rv);
// insert a new key
rv = mConnection->CreateStatement(
NS_LITERAL_CSTRING("INSERT INTO moz_webappsstore values (?1, ?2, ?3, ?4)"),
getter_AddRefs(mInsertKeyStatement));
NS_ENSURE_SUCCESS(rv, rv);
// update an existing key
rv = mConnection->CreateStatement(
NS_LITERAL_CSTRING("UPDATE moz_webappsstore "
"SET value = ?1, secure = ?2 "
"WHERE domain = ?3 "
"AND key = ?4 "),
getter_AddRefs(mUpdateKeyStatement));
NS_ENSURE_SUCCESS(rv, rv);
// update the secure status of an existing key
rv = mConnection->CreateStatement(
NS_LITERAL_CSTRING("UPDATE moz_webappsstore "
"SET secure = ?1 "
"WHERE domain = ?2 "
"AND key = ?3 "),
getter_AddRefs(mSetSecureStatement));
NS_ENSURE_SUCCESS(rv, rv);
// remove a key
rv = mConnection->CreateStatement(
NS_LITERAL_CSTRING("DELETE FROM moz_webappsstore "
"WHERE domain = ?1 "
"AND key = ?2"),
getter_AddRefs(mRemoveKeyStatement));
return rv;
}
nsresult
nsDOMStorageDB::GetAllKeys(const nsAString& aDomain,
nsDOMStorage* aStorage,
nsTHashtable<nsSessionStorageEntry>* aKeys)
{
mozStorageStatementScoper scope(mGetAllKeysStatement);
nsresult rv = mGetAllKeysStatement->BindStringParameter(0, aDomain);
NS_ENSURE_SUCCESS(rv, rv);
PRBool exists;
while (NS_SUCCEEDED(rv = mGetAllKeysStatement->ExecuteStep(&exists)) &&
exists) {
nsAutoString key;
rv = mGetAllKeysStatement->GetString(0, key);
NS_ENSURE_SUCCESS(rv, rv);
PRInt32 secureInt = 0;
rv = mGetAllKeysStatement->GetInt32(1, &secureInt);
NS_ENSURE_SUCCESS(rv, rv);
nsSessionStorageEntry* entry = aKeys->PutEntry(key);
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
entry->mItem = new nsDOMStorageItem(aStorage, key, secureInt);
if (!entry->mItem) {
aKeys->RawRemoveEntry(entry);
return NS_ERROR_OUT_OF_MEMORY;
}
}
return NS_OK;
}
nsresult
nsDOMStorageDB::GetKeyValue(const nsAString& aDomain,
const nsAString& aKey,
nsAString& aValue,
PRBool* aSecure)
{
mozStorageStatementScoper scope(mGetKeyValueStatement);
nsresult rv = mGetKeyValueStatement->BindStringParameter(0, aDomain);
NS_ENSURE_SUCCESS(rv, rv);
rv = mGetKeyValueStatement->BindStringParameter(1, aKey);
NS_ENSURE_SUCCESS(rv, rv);
PRBool exists;
rv = mGetKeyValueStatement->ExecuteStep(&exists);
NS_ENSURE_SUCCESS(rv, rv);
PRInt32 secureInt = 0;
if (exists) {
rv = mGetKeyValueStatement->GetString(0, aValue);
NS_ENSURE_SUCCESS(rv, rv);
rv = mGetKeyValueStatement->GetInt32(1, &secureInt);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
rv = NS_ERROR_DOM_NOT_FOUND_ERR;
}
*aSecure = (PRBool)secureInt;
return rv;
}
nsresult
nsDOMStorageDB::SetKey(const nsAString& aDomain,
const nsAString& aKey,
const nsAString& aValue,
PRBool aSecure)
{
mozStorageStatementScoper scope(mGetKeyValueStatement);
nsresult rv = mGetKeyValueStatement->BindStringParameter(0, aDomain);
NS_ENSURE_SUCCESS(rv, rv);
rv = mGetKeyValueStatement->BindStringParameter(1, aKey);
NS_ENSURE_SUCCESS(rv, rv);
PRBool exists;
rv = mGetKeyValueStatement->ExecuteStep(&exists);
NS_ENSURE_SUCCESS(rv, rv);
if (exists) {
if (!aSecure) {
PRInt32 secureInt = 0;
rv = mGetKeyValueStatement->GetInt32(1, &secureInt);
NS_ENSURE_SUCCESS(rv, rv);
if (secureInt)
return NS_ERROR_DOM_SECURITY_ERR;
}
mGetKeyValueStatement->Reset();
mozStorageStatementScoper scopeupdate(mUpdateKeyStatement);
rv = mUpdateKeyStatement->BindStringParameter(0, aValue);
NS_ENSURE_SUCCESS(rv, rv);
rv = mUpdateKeyStatement->BindInt32Parameter(1, aSecure);
NS_ENSURE_SUCCESS(rv, rv);
rv = mUpdateKeyStatement->BindStringParameter(2, aDomain);
NS_ENSURE_SUCCESS(rv, rv);
rv = mUpdateKeyStatement->BindStringParameter(3, aKey);
NS_ENSURE_SUCCESS(rv, rv);
return mUpdateKeyStatement->Execute();
}
mozStorageStatementScoper scopeinsert(mInsertKeyStatement);
rv = mInsertKeyStatement->BindStringParameter(0, aDomain);
NS_ENSURE_SUCCESS(rv, rv);
rv = mInsertKeyStatement->BindStringParameter(1, aKey);
NS_ENSURE_SUCCESS(rv, rv);
rv = mInsertKeyStatement->BindStringParameter(2, aValue);
NS_ENSURE_SUCCESS(rv, rv);
rv = mInsertKeyStatement->BindInt32Parameter(3, aSecure);
NS_ENSURE_SUCCESS(rv, rv);
return mInsertKeyStatement->Execute();
}
nsresult
nsDOMStorageDB::SetSecure(const nsAString& aDomain,
const nsAString& aKey,
const PRBool aSecure)
{
mozStorageStatementScoper scope(mGetKeyValueStatement);
nsresult rv = mGetKeyValueStatement->BindStringParameter(0, aDomain);
NS_ENSURE_SUCCESS(rv, rv);
rv = mGetKeyValueStatement->BindStringParameter(1, aKey);
NS_ENSURE_SUCCESS(rv, rv);
PRBool exists;
rv = mGetKeyValueStatement->ExecuteStep(&exists);
NS_ENSURE_SUCCESS(rv, rv);
if (exists) {
mGetKeyValueStatement->Reset();
mozStorageStatementScoper scopeupdate(mUpdateKeyStatement);
rv = mSetSecureStatement->BindInt32Parameter(0, aSecure ? 1 : 0);
NS_ENSURE_SUCCESS(rv, rv);
rv = mSetSecureStatement->BindStringParameter(1, aDomain);
NS_ENSURE_SUCCESS(rv, rv);
rv = mSetSecureStatement->BindStringParameter(2, aKey);
NS_ENSURE_SUCCESS(rv, rv);
return mSetSecureStatement->Execute();
}
return NS_OK;
}
nsresult
nsDOMStorageDB::RemoveKey(const nsAString& aDomain,
const nsAString& aKey)
{
mozStorageStatementScoper scope(mRemoveKeyStatement);
nsresult rv = mRemoveKeyStatement->BindStringParameter(0, aDomain);
NS_ENSURE_SUCCESS(rv, rv);
rv = mRemoveKeyStatement->BindStringParameter(1, aKey);
NS_ENSURE_SUCCESS(rv, rv);
return mRemoveKeyStatement->Execute();
}

View File

@ -0,0 +1,113 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Neil Deakin <enndeakin@sympatico.ca>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsDOMStorageDB_h___
#define nsDOMStorageDB_h___
#include "nscore.h"
#include "mozIStorageConnection.h"
#include "mozIStorageStatement.h"
#include "nsTHashtable.h"
class nsDOMStorage;
class nsSessionStorageEntry;
class nsDOMStorageDB
{
public:
nsDOMStorageDB() {};
~nsDOMStorageDB() {};
nsresult
Init();
/**
* Retrieve a list of all the keys associated with a particular domain.
*/
nsresult
GetAllKeys(const nsAString& aDomain,
nsDOMStorage* aStorage,
nsTHashtable<nsSessionStorageEntry>* aKeys);
/**
* Retrieve a value and secure flag for a key from storage.
*
* @throws NS_ERROR_DOM_NOT_FOUND_ERR if key not found
*/
nsresult
GetKeyValue(const nsAString& aDomain,
const nsAString& aKey,
nsAString& aValue,
PRBool* aSecure);
/**
* Set the value and secure flag for a key in storage.
*/
nsresult
SetKey(const nsAString& aDomain,
const nsAString& aKey,
const nsAString& aValue,
PRBool aSecure);
/**
* Set the secure flag for a key in storage. Does nothing if the key was
* not found.
*/
nsresult
SetSecure(const nsAString& aDomain,
const nsAString& aKey,
const PRBool aSecure);
/**
* Removes a key from storage.
*/
nsresult
RemoveKey(const nsAString& aDomain,
const nsAString& aKey);
protected:
nsCOMPtr<mozIStorageConnection> mConnection;
nsCOMPtr<mozIStorageStatement> mGetAllKeysStatement;
nsCOMPtr<mozIStorageStatement> mGetKeyValueStatement;
nsCOMPtr<mozIStorageStatement> mInsertKeyStatement;
nsCOMPtr<mozIStorageStatement> mUpdateKeyStatement;
nsCOMPtr<mozIStorageStatement> mSetSecureStatement;
nsCOMPtr<mozIStorageStatement> mRemoveKeyStatement;
};
#endif /* nsDOMStorageDB_h___ */

View File

@ -83,6 +83,7 @@ REQUIRES = xpcom \
locale \
necko \
dom \
storage \
editor \
webshell \
docshell \
@ -141,6 +142,7 @@ SHARED_LIBRARY_LIBS = \
$(DEPTH)/dom/src/base/$(LIB_PREFIX)jsdombase_s.$(LIB_SUFFIX) \
$(DEPTH)/dom/src/events/$(LIB_PREFIX)jsdomevents_s.$(LIB_SUFFIX) \
$(DEPTH)/dom/src/jsurl/$(LIB_PREFIX)jsurl_s.$(LIB_SUFFIX) \
$(DEPTH)/dom/src/storage/$(LIB_PREFIX)jsdomstorage_s.$(LIB_SUFFIX) \
$(NULL)
ifdef NS_PRINTING
@ -257,6 +259,7 @@ LOCAL_INCLUDES += -I$(srcdir)/../base \
-I$(topsrcdir)/view/src \
-I$(topsrcdir)/dom/src/base \
-I$(topsrcdir)/dom/src/jsurl \
-I$(topsrcdir)/dom/src/storage \
-I. \
$(NULL)

View File

@ -229,4 +229,8 @@
#define NS_CANVASRENDERINGCONTEXT2D_CID \
{ 0xa35d1cd4, 0xc505, 0x4d2d, { 0xa0, 0xf9, 0xae, 0xf0, 0x0b, 0x7c, 0xe5, 0xa5 } }
// {8b449142-1eab-4bfa-9830-fab6ebb09774}
#define NS_DOMSTORAGE_CID \
{ 0x8b449142, 0x1eab, 0x4bfa, { 0x98, 0x30, 0xfa, 0xb6, 0xeb, 0xb0, 0x97, 0x74 } }
#endif /* nsLayoutCID_h__ */

View File

@ -162,6 +162,7 @@
#include "nsDOMScriptObjectFactory.h"
#include "nsAutoCopyListener.h"
#include "nsDOMAttribute.h"
#include "nsDOMStorage.h"
#include "nsHTMLCanvasFrame.h"
@ -1353,7 +1354,12 @@ static const nsModuleComponentInfo gComponents[] = {
{ "DOM Parser",
NS_DOMPARSER_CID,
NS_DOMPARSER_CONTRACTID,
nsDOMParserConstructor }
nsDOMParserConstructor },
{ "DOM Storage",
NS_DOMSTORAGE_CID,
"@mozilla.org/dom/storage;1",
NS_NewDOMStorage }
};
NS_IMPL_NSGETMODULE_WITH_CTOR(nsLayoutModule, gComponents, Initialize)