Bug 682305 - nsXMLHttpRequest::Send fails with mChannel being implemented in JS. r=sicking

This commit is contained in:
Alexandre Poirot 2012-05-10 19:58:48 +01:00
Родитель 94c4150fb9
Коммит b74038af93
8 изменённых файлов: 218 добавлений и 34 удалений

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

@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 sw=2 et tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -109,6 +110,7 @@
#include "nsIDOMFormData.h"
#include "nsWrapperCacheInlines.h"
#include "nsStreamListenerWrapper.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -3046,9 +3048,6 @@ nsXMLHttpRequest::Send(JSContext *aCx, nsIVariant* aVariant, const Nullable<Requ
if (mState & XML_HTTP_REQUEST_MULTIPART) {
Telemetry::Accumulate(Telemetry::MULTIPART_XHR_RESPONSE, 1);
listener = new nsMultipartProxyListener(listener);
if (!listener) {
return NS_ERROR_OUT_OF_MEMORY;
}
} else {
Telemetry::Accumulate(Telemetry::MULTIPART_XHR_RESPONSE, 0);
}
@ -3062,9 +3061,18 @@ nsXMLHttpRequest::Send(JSContext *aCx, nsIVariant* aVariant, const Nullable<Requ
// a same-origin request right now, since it could be redirected.
listener = new nsCORSListenerProxy(listener, mPrincipal, mChannel,
withCredentials, true, &rv);
NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
// Because of bug 682305, we can't let listener be the XHR object itself
// because JS wouldn't be able to use it. So if we haven't otherwise
// created a listener around 'this', do so now.
listener = new nsStreamListenerWrapper(listener);
}
NS_ASSERTION(listener != this,
"Using an object as a listener that can't be exposed to JS");
// Bypass the network cache in cases where it makes no sense:
// 1) Multipart responses are very large and would likely be doomed by the

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

@ -75,6 +75,7 @@ _CHROME_FILES = \
test_bug650784.html \
test_bug752226-3.xul \
test_bug752226-4.xul \
test_bug682305.html \
$(NULL)
libs:: $(_TEST_FILES)

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

@ -0,0 +1,159 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=682305
-->
<head>
<title>XMLHttpRequest send and channel implemented in JS</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=682305">Mozilla Bug 682305</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
/*
* Register a custom nsIProtocolHandler service
* in order to be able to implement *and use* an
* nsIChannel component written in Javascript.
*/
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cr = Components.results;
var Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var SimpleURI = Cc["@mozilla.org/network/simple-uri;1"];
var ios = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
var PROTOCOL_SCHEME = "jsproto";
function CustomChannel(uri) {
this.URI = this.originalURI = uri;
}
CustomChannel.prototype = {
URI: null,
originalURI: null,
contentCharset: "utf-8",
contentLength: 0,
contentType: "text/plain",
owner: Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal),
securityInfo: null,
notificationCallbacks: null,
loadFlags: 0,
loadGroup: null,
name: null,
status: Cr.NS_OK,
asyncOpen: function(listener, context) {
let stream = this.open();
try {
listener.onStartRequest(this, context);
} catch(e) {}
try {
listener.onDataAvailable(this, context, stream, 0, stream.available());
} catch(e) {}
try {
listener.onStopRequest(this, context, Cr.NS_OK);
} catch(e) {}
},
open: function() {
let data = "bar";
let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
stream.setData(data, data.length);
return stream;
},
isPending: function() {
return false;
},
cancel: function() {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
suspend: function() {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
resume: function() {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannel, Ci.nsIRequest])
};
function CustomProtocol() {}
CustomProtocol.prototype = {
get scheme() {
return PROTOCOL_SCHEME;
},
get protocolFlags() {
return (Ci.nsIProtocolHandler.URI_NORELATIVE |
Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE |
Ci.nsIProtocolHandler.URI_DANGEROUS_TO_LOAD);
},
get defaultPort() {
return -1;
},
allowPort: function allowPort() {
return false;
},
newURI: function newURI(spec, charset, baseURI) {
var uri = SimpleURI.createInstance(Ci.nsIURI)
uri.spec = spec;
return uri.QueryInterface(Ci.nsIURI);
},
newChannel: function newChannel(URI) {
return new CustomChannel(URI);
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
Ci.nsISupportsWeakReference,
Ci.nsIProtocolHandler])
};
var gFactory = {
register: function() {
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
var classID = Components.ID("{ed064287-1e76-49ba-a28d-dc74394a8334}");
var description = PROTOCOL_SCHEME + ": protocol";
var contractID = "@mozilla.org/network/protocol;1?name=" + PROTOCOL_SCHEME;
var factory = XPCOMUtils._getFactory(CustomProtocol);
registrar.registerFactory(classID, description, contractID, factory);
this.unregister = function() {
registrar.unregisterFactory(classID, factory);
delete this.unregister;
};
}
};
// Register the custom procotol handler
gFactory.register();
// Then, checks if XHR works with it
var xhr = new XMLHttpRequest();
xhr.open("GET", PROTOCOL_SCHEME + ":foo", true);
xhr.onload = function () {
is(xhr.responseText, "bar", "protocol doesn't work");
gFactory.unregister();
SimpleTest.finish();
}
try {
xhr.send(null);
} catch(e) {
ok(false, e);
}
</script>
</pre>
</body>
</html>

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

@ -165,6 +165,7 @@ EXPORTS = \
nsReadLine.h \
nsASocketHandler.h \
nsAsyncRedirectVerifyHelper.h \
nsStreamListenerWrapper.h \
$(NULL)
include $(topsrcdir)/config/rules.mk

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

@ -0,0 +1,33 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsStreamListenerWrapper_h__
#define nsStreamListenerWrapper_h__
#include "nsCOMPtr.h"
#include "nsIStreamListener.h"
#include "nsIRequestObserver.h"
// Wrapper class to make replacement of nsHttpChannel's listener
// from JavaScript possible. It is workaround for bug 433711 and 682305.
class nsStreamListenerWrapper : public nsIStreamListener
{
public:
nsStreamListenerWrapper(nsIStreamListener *listener)
: mListener(listener)
{
NS_ASSERTION(mListener, "no stream listener specified");
}
NS_DECL_ISUPPORTS
NS_FORWARD_NSIREQUESTOBSERVER(mListener->)
NS_FORWARD_NSISTREAMLISTENER(mListener->)
private:
~nsStreamListenerWrapper() {}
nsCOMPtr<nsIStreamListener> mListener;
};
#endif // nsStreamListenerWrapper_h__

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

@ -93,6 +93,7 @@ CPPSRCS = \
nsDNSPrefetch.cpp \
RedirectChannelRegistrar.cpp \
nsPreloadedStream.cpp \
nsStreamListenerWrapper.cpp \
$(NULL)
ifeq ($(MOZ_WIDGET_TOOLKIT),os2)

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

@ -0,0 +1,10 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsStreamListenerWrapper.h"
NS_IMPL_ISUPPORTS2(nsStreamListenerWrapper,
nsIStreamListener,
nsIRequestObserver)

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

@ -53,6 +53,7 @@
#include "nsIResumableChannel.h"
#include "nsIApplicationCacheChannel.h"
#include "nsEscape.h"
#include "nsStreamListenerWrapper.h"
#include "prnetdb.h"
@ -1427,36 +1428,6 @@ HttpBaseChannel::GetEntityID(nsACString& aEntityID)
return NS_OK;
}
//-----------------------------------------------------------------------------
// nsStreamListenerWrapper <private>
//-----------------------------------------------------------------------------
// Wrapper class to make replacement of nsHttpChannel's listener
// from JavaScript possible. It is workaround for bug 433711.
class nsStreamListenerWrapper : public nsIStreamListener
{
public:
nsStreamListenerWrapper(nsIStreamListener *listener);
NS_DECL_ISUPPORTS
NS_FORWARD_NSIREQUESTOBSERVER(mListener->)
NS_FORWARD_NSISTREAMLISTENER(mListener->)
private:
~nsStreamListenerWrapper() {}
nsCOMPtr<nsIStreamListener> mListener;
};
nsStreamListenerWrapper::nsStreamListenerWrapper(nsIStreamListener *listener)
: mListener(listener)
{
NS_ASSERTION(mListener, "no stream listener specified");
}
NS_IMPL_ISUPPORTS2(nsStreamListenerWrapper,
nsIStreamListener,
nsIRequestObserver)
//-----------------------------------------------------------------------------
// nsHttpChannel::nsITraceableChannel
//-----------------------------------------------------------------------------