Bug 382871 - XMLHttpRequest JS wrapper not preserved by its event handlers, r+sr=jst

This commit is contained in:
Olli Pettay 2008-09-25 17:40:30 +03:00
Родитель e3596a93b4
Коммит aa6691f983
6 изменённых файлов: 139 добавлений и 59 удалений

Просмотреть файл

@ -308,21 +308,39 @@ GetDocumentFromScriptContext(nsIScriptContext *aScriptContext)
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXHREventTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXHREventTarget)
if (tmp->mOwner) {
nsCOMPtr<nsIDocument> doc =
do_QueryInterface(tmp->mOwner->GetExtantDocument());
if (doc) {
cb.NoteXPCOMChild(doc->GetReference(tmp));
}
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnLoadListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnErrorListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnAbortListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnLoadStartListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnProgressListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mListenerManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOwner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXHREventTarget)
if (tmp->mOwner) {
nsCOMPtr<nsIDocument> doc =
do_QueryInterface(tmp->mOwner->GetExtantDocument());
if (doc) {
doc->RemoveReference(tmp);
}
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnLoadListener)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnErrorListener)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnAbortListener)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnLoadStartListener)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnProgressListener)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mListenerManager)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mScriptContext)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOwner)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXHREventTarget)
@ -580,18 +598,18 @@ nsXHREventTarget::GetSystemEventGroup(nsIDOMEventGroup** aGroup)
return rv;
}
nsresult
nsXHREventTarget::GetContextForEventHandlers(nsIScriptContext** aContext)
{
nsresult rv = CheckInnerWindowCorrectness();
NS_ENSURE_SUCCESS(rv, rv);
NS_IF_ADDREF(*aContext = mScriptContext);
return NS_OK;
}
/////////////////////////////////////////////
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLHttpRequestUpload)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXMLHttpRequestUpload, nsXHREventTarget)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOwner)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLHttpRequestUpload, nsXHREventTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOwner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLHttpRequestUpload)
NS_INTERFACE_MAP_BEGIN(nsXMLHttpRequestUpload)
NS_INTERFACE_MAP_ENTRY(nsIXMLHttpRequestUpload)
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(XMLHttpRequestUpload)
NS_INTERFACE_MAP_END_INHERITING(nsXHREventTarget)
@ -599,12 +617,6 @@ NS_INTERFACE_MAP_END_INHERITING(nsXHREventTarget)
NS_IMPL_ADDREF_INHERITED(nsXMLHttpRequestUpload, nsXHREventTarget)
NS_IMPL_RELEASE_INHERITED(nsXMLHttpRequestUpload, nsXHREventTarget)
nsresult
nsXMLHttpRequestUpload::GetContextForEventHandlers(nsIScriptContext** aContext)
{
return mOwner->GetContextForEventHandlers(aContext);
}
/////////////////////////////////////////////
//
//
@ -735,7 +747,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLHttpRequest,
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannel)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mReadRequest)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnUploadProgressListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnReadystatechangeListener)
@ -744,8 +755,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLHttpRequest,
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannelEventSink)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mProgressEventSink)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOwner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mUpload,
nsIXMLHttpRequestUpload)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -757,7 +766,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXMLHttpRequest,
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChannel)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mReadRequest)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mScriptContext)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnUploadProgressListener)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnReadystatechangeListener)
@ -766,8 +774,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXMLHttpRequest,
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChannelEventSink)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mProgressEventSink)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOwner)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mUpload)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -2577,21 +2583,15 @@ nsXMLHttpRequest::GetInterface(const nsIID & aIID, void **aResult)
return QueryInterface(aIID, aResult);
}
nsresult
nsXMLHttpRequest::GetContextForEventHandlers(nsIScriptContext** aContext)
{
nsresult rv = CheckInnerWindowCorrectness();
NS_ENSURE_SUCCESS(rv, rv);
NS_IF_ADDREF(*aContext = mScriptContext);
return NS_OK;
}
NS_IMETHODIMP
nsXMLHttpRequest::GetUpload(nsIXMLHttpRequestUpload** aUpload)
{
*aUpload = nsnull;
nsCOMPtr<nsIScriptContext> scriptContext;
nsresult rv = GetContextForEventHandlers(getter_AddRefs(scriptContext));
NS_ENSURE_SUCCESS(rv, rv);
if (!mUpload) {
mUpload = new nsXMLHttpRequestUpload(this);
mUpload = new nsXMLHttpRequestUpload(mOwner, scriptContext);
NS_ENSURE_TRUE(mUpload, NS_ERROR_OUT_OF_MEMORY);
}
NS_ADDREF(*aUpload = mUpload);

Просмотреть файл

@ -117,7 +117,7 @@ public:
virtual nsresult RemoveEventListenerByIID(nsIDOMEventListener *aListener,
const nsIID& aIID);
virtual nsresult GetSystemEventGroup(nsIDOMEventGroup** aGroup);
virtual nsresult GetContextForEventHandlers(nsIScriptContext** aContext) = 0;
virtual nsresult GetContextForEventHandlers(nsIScriptContext** aContext);
PRBool HasListenersFor(const nsAString& aType)
{
@ -129,6 +129,18 @@ public:
nsresult GetInnerEventListener(nsRefPtr<nsDOMEventListenerWrapper>& aWrapper,
nsIDOMEventListener** aListener);
nsresult CheckInnerWindowCorrectness()
{
if (mOwner) {
NS_ASSERTION(mOwner->IsInnerWindow(), "Should have inner window here!\n");
nsPIDOMWindow* outer = mOwner->GetOuterWindow();
if (!outer || outer->GetCurrentInnerWindow() != mOwner) {
return NS_ERROR_FAILURE;
}
}
return NS_OK;
}
protected:
nsRefPtr<nsDOMEventListenerWrapper> mOnLoadListener;
nsRefPtr<nsDOMEventListenerWrapper> mOnErrorListener;
@ -137,23 +149,26 @@ protected:
nsRefPtr<nsDOMEventListenerWrapper> mOnProgressListener;
nsCOMPtr<nsIEventListenerManager> mListenerManager;
PRUint32 mLang;
// These may be null (native callers or xpcshell).
nsCOMPtr<nsIScriptContext> mScriptContext;
nsCOMPtr<nsPIDOMWindow> mOwner; // Inner window.
};
class nsXMLHttpRequestUpload : public nsXHREventTarget,
public nsIXMLHttpRequestUpload
{
public:
nsXMLHttpRequestUpload(nsPIDOMEventTarget* aOwner) : mOwner(aOwner) {}
nsXMLHttpRequestUpload(nsPIDOMWindow* aOwner,
nsIScriptContext* aScriptContext)
{
mOwner = aOwner;
mScriptContext = aScriptContext;
}
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXMLHttpRequestUpload,
nsXHREventTarget)
NS_FORWARD_NSIXMLHTTPREQUESTEVENTTARGET(nsXHREventTarget::)
NS_FORWARD_NSIDOMEVENTTARGET(nsXHREventTarget::)
NS_FORWARD_NSIDOMNSEVENTTARGET(nsXHREventTarget::)
NS_DECL_NSIXMLHTTPREQUESTUPLOAD
virtual nsresult GetContextForEventHandlers(nsIScriptContext** aContext);
protected:
nsCOMPtr<nsPIDOMEventTarget> mOwner;
};
class nsXMLHttpRequest : public nsXHREventTarget,
@ -217,8 +232,6 @@ public:
NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
PRUint32 argc, jsval* argv);
virtual nsresult GetContextForEventHandlers(nsIScriptContext** aContext);
// This creates a trusted readystatechange event, which is not cancelable and
// doesn't bubble.
@ -288,18 +301,6 @@ protected:
*/
nsresult CheckChannelForCrossSiteRequest();
nsresult CheckInnerWindowCorrectness()
{
if (mOwner) {
NS_ASSERTION(mOwner->IsInnerWindow(), "Should have inner window here!\n");
nsPIDOMWindow* outer = mOwner->GetOuterWindow();
if (!outer || outer->GetCurrentInnerWindow() != mOwner) {
return NS_ERROR_FAILURE;
}
}
return NS_OK;
}
nsCOMPtr<nsISupports> mContext;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsIChannel> mChannel;
@ -307,10 +308,6 @@ protected:
nsCOMPtr<nsIRequest> mReadRequest;
nsCOMPtr<nsIDOMDocument> mDocument;
// These may be null (native callers or xpcshell).
nsCOMPtr<nsIScriptContext> mScriptContext;
nsCOMPtr<nsPIDOMWindow> mOwner; // Inner window.
nsRefPtr<nsDOMEventListenerWrapper> mOnUploadProgressListener;
nsRefPtr<nsDOMEventListenerWrapper> mOnReadystatechangeListener;

Просмотреть файл

@ -123,6 +123,7 @@ _TEST_FILES = test_bug5141.html \
test_bug375314.html \
test_bug378969.html \
test_bug382113.html \
test_bug382871.html \
test_bug383430.html \
test_bug390219.html \
test_bug390735.html \

Просмотреть файл

@ -0,0 +1,50 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=382871
-->
<head>
<title>Test for Bug 382871</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=382871">Mozilla Bug 382871</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 382871 **/
function loadHandler(evt) {
ok("randomProperty" in evt.target);
ok("randomProperty" in evt.target.upload);
SimpleTest.finish();
}
function runTest() {
var xhr = new XMLHttpRequest();
xhr.onload = loadHandler;
xhr.randomProperty = true;
xhr.upload.randomProperty = true;
xhr.open("GET", "test_bug382871.html");
xhr.send();
xhr = null;
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils)
.garbageCollect();
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(runTest);
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1208,7 +1208,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(XMLHttpProgressEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(XMLHttpRequest, nsEventTargetSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
DOM_DEFAULT_SCRIPTABLE_FLAGS |
nsIXPCScriptable::WANT_ADDPROPERTY)
NS_DEFINE_CLASSINFO_DATA(ClientRect, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
@ -1281,7 +1282,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(XMLHttpRequestUpload, nsEventTargetSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
DOM_DEFAULT_SCRIPTABLE_FLAGS |
nsIXPCScriptable::WANT_ADDPROPERTY)
// DOM Traversal NodeIterator class
NS_DEFINE_CLASSINFO_DATA(NodeIterator, nsDOMGenericSH,
@ -7342,6 +7344,33 @@ nsEventTargetSH::NewResolve(nsIXPConnectWrappedNative *wrapper,
_retval);
}
NS_IMETHODIMP
nsEventTargetSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsval id, jsval *vp, PRBool *_retval)
{
if (id == sAddEventListener_id) {
return NS_OK;
}
nsISupports* native = wrapper->Native();
nsCOMPtr<nsPIDOMEventTarget> target = do_QueryInterface(native);
if (target) {
nsCOMPtr<nsIScriptContext> scriptContext;
target->GetContextForEventHandlers(getter_AddRefs(scriptContext));
if (scriptContext) {
nsCOMPtr<nsPIDOMWindow> window =
do_QueryInterface(scriptContext->GetGlobalObject());
if (window) {
nsCOMPtr<nsIDocument> doc =
do_QueryInterface(window->GetExtantDocument());
if (doc) {
doc->AddReference(native, wrapper);
}
}
}
}
return NS_OK;
}
// Element helper
NS_IMETHODIMP

Просмотреть файл

@ -388,6 +388,7 @@ public:
// Adds support for 4th parameter of addEventListener.
// Simpler than nsEventReceiverSH
// Makes also sure that the wrapper is preserved if new properties are added.
class nsEventTargetSH : public nsDOMGenericSH
{
protected:
@ -402,6 +403,8 @@ public:
NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsval id, PRUint32 flags,
JSObject **objp, PRBool *_retval);
NS_IMETHOD AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsval id, jsval *vp, PRBool *_retval);
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
{