2006-04-20 07:36:50 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Netscape 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/NPL/
|
|
|
|
*
|
|
|
|
* 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 Netscape are
|
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
|
|
* Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "nsXMLHttpRequest.h"
|
|
|
|
#include "nsIStreamObserver.h"
|
|
|
|
#include "nsISimpleEnumerator.h"
|
|
|
|
#include "nsIHTTPHeader.h"
|
|
|
|
#include "nsIXPConnect.h"
|
|
|
|
#include "nsIByteArrayInputStream.h"
|
|
|
|
#include "nsIUnicodeEncoder.h"
|
|
|
|
#include "nsIServiceManager.h"
|
|
|
|
#include "nsICharsetConverterManager.h"
|
|
|
|
#include "nsLayoutCID.h"
|
|
|
|
#include "nsIDOMDOMImplementation.h"
|
|
|
|
#include "nsIPrivateDOMImplementation.h"
|
|
|
|
#include "nsXPIDLString.h"
|
|
|
|
#include "nsIURI.h"
|
|
|
|
#include "nsILoadGroup.h"
|
|
|
|
#include "nsNetUtil.h"
|
|
|
|
#include "nsIDOMSerializer.h"
|
|
|
|
#include "nsISupportsPrimitives.h"
|
2006-04-20 07:36:54 +04:00
|
|
|
#include "nsIDOMEventReceiver.h"
|
2006-04-20 07:36:50 +04:00
|
|
|
#include "prprf.h"
|
|
|
|
#include "nsIDOMEventListener.h"
|
|
|
|
#include "nsIJSContextStack.h"
|
2006-04-20 07:36:51 +04:00
|
|
|
#include "nsIScriptSecurityManager.h"
|
|
|
|
#include "nsICodebasePrincipal.h"
|
2006-04-20 07:36:54 +04:00
|
|
|
#include "nsWeakPtr.h"
|
|
|
|
#ifdef IMPLEMENT_SYNC_LOAD
|
|
|
|
#include "nsIScriptContext.h"
|
|
|
|
#include "nsIScriptGlobalObject.h"
|
|
|
|
#include "nsIDocShell.h"
|
|
|
|
#include "nsIDocShellTreeItem.h"
|
|
|
|
#include "nsIEventQueueService.h"
|
|
|
|
#endif
|
2006-04-20 07:36:50 +04:00
|
|
|
|
|
|
|
static const char* kLoadAsData = "loadAsData";
|
|
|
|
static const char* kLoadStr = "load";
|
|
|
|
static const char* kErrorStr = "error";
|
|
|
|
|
2006-04-20 07:36:54 +04:00
|
|
|
// CIDs
|
2006-04-20 07:36:50 +04:00
|
|
|
static NS_DEFINE_CID(kIDOMDOMImplementationCID, NS_DOM_IMPLEMENTATION_CID);
|
|
|
|
static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
|
2006-04-20 07:36:54 +04:00
|
|
|
#ifdef IMPLEMENT_SYNC_LOAD
|
|
|
|
static NS_DEFINE_IID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
|
|
|
#endif
|
2006-04-20 07:36:50 +04:00
|
|
|
|
|
|
|
static JSContext*
|
|
|
|
GetSafeContext()
|
|
|
|
{
|
|
|
|
// Get the "safe" JSContext: our JSContext of last resort
|
|
|
|
nsresult rv;
|
2006-04-20 07:37:00 +04:00
|
|
|
NS_WITH_SERVICE(nsIJSContextStack, stack, "@mozilla.org/js/xpc/ContextStack;1",
|
2006-04-20 07:36:50 +04:00
|
|
|
&rv);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return nsnull;
|
|
|
|
nsCOMPtr<nsIThreadJSContextStack> tcs = do_QueryInterface(stack);
|
|
|
|
JSContext* cx;
|
|
|
|
if (NS_FAILED(tcs->GetSafeJSContext(&cx))) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
return cx;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSContext*
|
|
|
|
GetCurrentContext()
|
|
|
|
{
|
|
|
|
// Get JSContext from stack.
|
|
|
|
nsresult rv;
|
2006-04-20 07:37:00 +04:00
|
|
|
NS_WITH_SERVICE(nsIJSContextStack, stack, "@mozilla.org/js/xpc/ContextStack;1",
|
2006-04-20 07:36:50 +04:00
|
|
|
&rv);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return nsnull;
|
|
|
|
JSContext *cx;
|
|
|
|
if (NS_FAILED(stack->Peek(&cx)))
|
|
|
|
return nsnull;
|
|
|
|
return cx;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsXMLHttpRequestScriptListener::nsXMLHttpRequestScriptListener(JSObject* aScopeObj, JSObject* aFunctionObj)
|
|
|
|
{
|
|
|
|
NS_INIT_ISUPPORTS();
|
|
|
|
// We don't have to add a GC root for the scope object
|
|
|
|
// since we'll go away if it goes away
|
|
|
|
mScopeObj = aScopeObj;
|
|
|
|
mFunctionObj = aFunctionObj;
|
|
|
|
JSContext* cx;
|
|
|
|
cx = GetSafeContext();
|
|
|
|
if (cx) {
|
|
|
|
JS_AddNamedRoot(cx, &mFunctionObj, "nsXMLHttpRequest");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsXMLHttpRequestScriptListener::~nsXMLHttpRequestScriptListener()
|
|
|
|
{
|
|
|
|
JSContext* cx;
|
|
|
|
cx = GetSafeContext();
|
|
|
|
if (cx) {
|
|
|
|
JS_RemoveRoot(cx, &mFunctionObj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS2(nsXMLHttpRequestScriptListener, nsIDOMEventListener, nsIPrivateJSEventListener)
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXMLHttpRequestScriptListener::HandleEvent(nsIDOMEvent* aEvent)
|
|
|
|
{
|
|
|
|
JSContext* cx;
|
|
|
|
cx = GetCurrentContext();
|
|
|
|
if (!cx) {
|
|
|
|
cx = GetSafeContext();
|
|
|
|
}
|
|
|
|
if (cx) {
|
|
|
|
jsval val;
|
|
|
|
|
|
|
|
// Hmmm...we can't pass along the nsIDOMEvent because
|
|
|
|
// we may not have the right type of context (required
|
|
|
|
// to get a JSObject from a nsIScriptObjectOwner)
|
|
|
|
JS_CallFunctionValue(cx, mScopeObj,
|
|
|
|
OBJECT_TO_JSVAL(mFunctionObj),
|
|
|
|
0, nsnull, &val);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLHttpRequestScriptListener::GetFunctionObj(JSObject** aObj)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aObj);
|
|
|
|
|
|
|
|
*aObj = mFunctionObj;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2006-04-20 07:36:54 +04:00
|
|
|
/////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// This class exists to prevent a circular reference between
|
|
|
|
// the loaded document and the nsXMLHttpRequest instance. The
|
|
|
|
// request owns the document. While the document is loading,
|
|
|
|
// the request is a load listener, held onto by the document.
|
|
|
|
// The proxy class breaks the circularity by filling in as the
|
|
|
|
// load listener and holding a weak reference to the request
|
|
|
|
// object.
|
|
|
|
//
|
|
|
|
/////////////////////////////////////////////
|
|
|
|
|
|
|
|
class nsLoadListenerProxy : public nsIDOMLoadListener {
|
|
|
|
public:
|
|
|
|
nsLoadListenerProxy(nsWeakPtr aParent);
|
|
|
|
virtual ~nsLoadListenerProxy();
|
|
|
|
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
|
|
|
// nsIDOMEventListener
|
|
|
|
virtual nsresult HandleEvent(nsIDOMEvent* aEvent);
|
|
|
|
|
|
|
|
// nsIDOMLoadListener
|
|
|
|
virtual nsresult Load(nsIDOMEvent* aEvent);
|
|
|
|
virtual nsresult Unload(nsIDOMEvent* aEvent);
|
|
|
|
virtual nsresult Abort(nsIDOMEvent* aEvent);
|
|
|
|
virtual nsresult Error(nsIDOMEvent* aEvent);
|
|
|
|
|
|
|
|
protected:
|
|
|
|
nsWeakPtr mParent;
|
|
|
|
};
|
|
|
|
|
|
|
|
nsLoadListenerProxy::nsLoadListenerProxy(nsWeakPtr aParent)
|
|
|
|
{
|
|
|
|
NS_INIT_ISUPPORTS();
|
|
|
|
mParent = aParent;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsLoadListenerProxy::~nsLoadListenerProxy()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS1(nsLoadListenerProxy, nsIDOMLoadListener)
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsLoadListenerProxy::HandleEvent(nsIDOMEvent* aEvent)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMLoadListener> listener = do_QueryReferent(mParent);
|
|
|
|
|
|
|
|
if (listener) {
|
|
|
|
return listener->HandleEvent(aEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsLoadListenerProxy::Load(nsIDOMEvent* aEvent)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMLoadListener> listener = do_QueryReferent(mParent);
|
|
|
|
|
|
|
|
if (listener) {
|
|
|
|
return listener->Load(aEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsLoadListenerProxy::Unload(nsIDOMEvent* aEvent)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMLoadListener> listener = do_QueryReferent(mParent);
|
|
|
|
|
|
|
|
if (listener) {
|
|
|
|
return listener->Unload(aEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsLoadListenerProxy::Abort(nsIDOMEvent* aEvent)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMLoadListener> listener = do_QueryReferent(mParent);
|
|
|
|
|
|
|
|
if (listener) {
|
|
|
|
return listener->Abort(aEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsLoadListenerProxy::Error(nsIDOMEvent* aEvent)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMLoadListener> listener = do_QueryReferent(mParent);
|
|
|
|
|
|
|
|
if (listener) {
|
|
|
|
return listener->Error(aEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2006-04-20 07:36:50 +04:00
|
|
|
/////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
//
|
|
|
|
/////////////////////////////////////////////
|
|
|
|
|
|
|
|
nsXMLHttpRequest::nsXMLHttpRequest()
|
|
|
|
{
|
|
|
|
NS_INIT_ISUPPORTS();
|
2006-04-20 07:36:54 +04:00
|
|
|
mStatus = XML_HTTP_REQUEST_INITIALIZED;
|
2006-04-20 07:36:51 +04:00
|
|
|
mAsync = PR_TRUE;
|
2006-04-20 07:36:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nsXMLHttpRequest::~nsXMLHttpRequest()
|
|
|
|
{
|
2006-04-20 07:36:54 +04:00
|
|
|
if (XML_HTTP_REQUEST_SENT == mStatus) {
|
|
|
|
Abort();
|
|
|
|
}
|
|
|
|
#ifdef IMPLEMENT_SYNC_LOAD
|
|
|
|
if (mDocShellTreeOwner) {
|
|
|
|
mDocShellTreeOwner->ExitModalLoop(NS_OK);
|
|
|
|
}
|
|
|
|
#endif
|
2006-04-20 07:36:50 +04:00
|
|
|
}
|
|
|
|
|
2006-04-20 07:36:54 +04:00
|
|
|
NS_IMPL_ADDREF(nsXMLHttpRequest)
|
|
|
|
NS_IMPL_RELEASE(nsXMLHttpRequest)
|
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN(nsXMLHttpRequest)
|
|
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXMLHttpRequest)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIXMLHttpRequest)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMLoadListener)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISecurityCheckedComponent)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
|
|
|
NS_INTERFACE_MAP_END
|
2006-04-20 07:36:50 +04:00
|
|
|
|
|
|
|
/* noscript void addEventListener (in string type, in nsIDOMEventListener listener); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLHttpRequest::AddEventListener(const char *type,
|
|
|
|
nsIDOMEventListener *listener)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(type);
|
|
|
|
NS_ENSURE_ARG(listener);
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
// I know, I know - strcmp's. But it's only for a couple of
|
|
|
|
// cases...and they are short strings. :-)
|
|
|
|
if (nsCRT::strcmp(type, kLoadStr) == 0) {
|
|
|
|
if (!mLoadEventListeners) {
|
|
|
|
rv = NS_NewISupportsArray(getter_AddRefs(mLoadEventListeners));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
mLoadEventListeners->AppendElement(listener);
|
|
|
|
}
|
|
|
|
else if (nsCRT::strcmp(type, kErrorStr) == 0) {
|
|
|
|
if (!mErrorEventListeners) {
|
|
|
|
rv = NS_NewISupportsArray(getter_AddRefs(mErrorEventListeners));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
mErrorEventListeners->AppendElement(listener);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* noscript void removeEventListener (in string type, in nsIDOMEventListener listener); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLHttpRequest::RemoveEventListener(const char *type,
|
|
|
|
nsIDOMEventListener *listener)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(type);
|
|
|
|
NS_ENSURE_ARG(listener);
|
|
|
|
|
|
|
|
if (nsCRT::strcmp(type, kLoadStr) == 0) {
|
|
|
|
if (mLoadEventListeners) {
|
|
|
|
mLoadEventListeners->RemoveElement(listener);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (nsCRT::strcmp(type, kErrorStr) == 0) {
|
|
|
|
if (mErrorEventListeners) {
|
|
|
|
mErrorEventListeners->RemoveElement(listener);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXMLHttpRequest::MakeScriptEventListener(nsISupports* aObject,
|
|
|
|
nsIDOMEventListener** aListener)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
*aListener = nsnull;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIXPCNativeCallContext> cc;
|
|
|
|
NS_WITH_SERVICE(nsIXPConnect, xpc, nsIXPConnect::GetCID(), &rv);
|
|
|
|
if(NS_SUCCEEDED(rv)) {
|
|
|
|
rv = xpc->GetCurrentNativeCallContext(getter_AddRefs(cc));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && cc) {
|
|
|
|
nsCOMPtr<nsIXPConnectJSObjectHolder> jsobjholder = do_QueryInterface(aObject);
|
|
|
|
if (jsobjholder) {
|
|
|
|
JSObject* funobj;
|
|
|
|
rv = jsobjholder->GetJSObject(&funobj);
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
JSContext* cx;
|
|
|
|
rv = cc->GetJSContext(&cx);
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
JSFunction* fun = JS_ValueToFunction(cx, OBJECT_TO_JSVAL(funobj));
|
|
|
|
if (!fun) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
|
|
|
|
rv = cc->GetCalleeWrapper(getter_AddRefs(wrapper));
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
JSObject* scopeobj;
|
|
|
|
rv = wrapper->GetJSObject(&scopeobj);
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
nsXMLHttpRequestScriptListener* listener = new nsXMLHttpRequestScriptListener(scopeobj, funobj);
|
|
|
|
if (!listener) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
*aListener = listener;
|
|
|
|
NS_ADDREF(*aListener);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRBool
|
|
|
|
CheckForScriptListener(nsISupports* aElement, void *aData)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIPrivateJSEventListener> jsel = do_QueryInterface(aElement);
|
|
|
|
if (jsel) {
|
|
|
|
nsIDOMEventListener** retval = (nsIDOMEventListener**)aData;
|
|
|
|
|
|
|
|
aElement->QueryInterface(NS_GET_IID(nsIDOMEventListener), (void**)retval);
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsXMLHttpRequest::GetScriptEventListener(nsISupportsArray* aList,
|
|
|
|
nsIDOMEventListener** aListener)
|
|
|
|
{
|
|
|
|
aList->EnumerateForwards(CheckForScriptListener, (void*)aListener);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsXMLHttpRequest::StuffReturnValue(nsIDOMEventListener* aListener)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIXPCNativeCallContext> cc;
|
|
|
|
NS_WITH_SERVICE(nsIXPConnect, xpc, nsIXPConnect::GetCID(), &rv);
|
|
|
|
if(NS_SUCCEEDED(rv)) {
|
|
|
|
rv = xpc->GetCurrentNativeCallContext(getter_AddRefs(cc));
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we're being called through JS, stuff the return value
|
|
|
|
if (NS_SUCCEEDED(rv) && cc) {
|
|
|
|
jsval* val;
|
|
|
|
rv = cc->GetRetValPtr(&val);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
JSObject* obj;
|
|
|
|
nsCOMPtr<nsIPrivateJSEventListener> jsel = do_QueryInterface(aListener);
|
|
|
|
if (jsel) {
|
|
|
|
jsel->GetFunctionObj(&obj);
|
|
|
|
*val = OBJECT_TO_JSVAL(obj);
|
2006-04-20 07:36:55 +04:00
|
|
|
cc->SetReturnValueWasSet(JS_TRUE);
|
2006-04-20 07:36:50 +04:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* attribute nsIDOMEventListener onload; */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLHttpRequest::GetOnload(nsISupports * *aOnLoad)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aOnLoad);
|
|
|
|
|
|
|
|
*aOnLoad = nsnull;
|
|
|
|
if (mLoadEventListeners) {
|
|
|
|
nsCOMPtr<nsIDOMEventListener> listener;
|
|
|
|
|
|
|
|
GetScriptEventListener(mLoadEventListeners, getter_AddRefs(listener));
|
|
|
|
if (listener) {
|
|
|
|
StuffReturnValue(listener);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLHttpRequest::SetOnload(nsISupports * aOnLoad)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aOnLoad);
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIDOMEventListener> listener;
|
|
|
|
|
|
|
|
rv = MakeScriptEventListener(aOnLoad, getter_AddRefs(listener));
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
if (listener) {
|
|
|
|
nsCOMPtr<nsIDOMEventListener> oldListener;
|
|
|
|
|
|
|
|
// Remove any old script event listener that exists since
|
|
|
|
// we can only have one
|
|
|
|
if (mLoadEventListeners) {
|
|
|
|
GetScriptEventListener(mLoadEventListeners, getter_AddRefs(oldListener));
|
|
|
|
RemoveEventListener(kLoadStr, oldListener);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// If it's not a script event listener, try to directly QI it to
|
|
|
|
// an actual event listener
|
|
|
|
listener = do_QueryInterface(aOnLoad);
|
|
|
|
if (!listener) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return AddEventListener(kLoadStr, listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* attribute nsIDOMEventListener onerror; */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLHttpRequest::GetOnerror(nsISupports * *aOnerror)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aOnerror);
|
|
|
|
|
|
|
|
*aOnerror = nsnull;
|
|
|
|
if (mErrorEventListeners) {
|
|
|
|
nsCOMPtr<nsIDOMEventListener> listener;
|
|
|
|
|
|
|
|
GetScriptEventListener(mErrorEventListeners, getter_AddRefs(listener));
|
|
|
|
if (listener) {
|
|
|
|
StuffReturnValue(listener);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLHttpRequest::SetOnerror(nsISupports * aOnerror)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aOnerror);
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIDOMEventListener> listener;
|
|
|
|
|
|
|
|
rv = MakeScriptEventListener(aOnerror, getter_AddRefs(listener));
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
if (listener) {
|
|
|
|
nsCOMPtr<nsIDOMEventListener> oldListener;
|
|
|
|
|
|
|
|
// Remove any old script event listener that exists since
|
|
|
|
// we can only have one
|
|
|
|
if (mErrorEventListeners) {
|
|
|
|
GetScriptEventListener(mErrorEventListeners,
|
|
|
|
getter_AddRefs(oldListener));
|
|
|
|
RemoveEventListener(kErrorStr, oldListener);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// If it's not a script event listener, try to directly QI it to
|
|
|
|
// an actual event listener
|
|
|
|
listener = do_QueryInterface(aOnerror);
|
|
|
|
if (!listener) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return AddEventListener(kErrorStr, listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* readonly attribute nsIDOMDocument responseXML; */
|
|
|
|
NS_IMETHODIMP nsXMLHttpRequest::GetResponseXML(nsIDOMDocument **aResponseXML)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aResponseXML);
|
|
|
|
*aResponseXML = nsnull;
|
2006-04-20 07:36:54 +04:00
|
|
|
if ((XML_HTTP_REQUEST_COMPLETED == mStatus) && mDocument) {
|
2006-04-20 07:36:50 +04:00
|
|
|
*aResponseXML = mDocument;
|
|
|
|
NS_ADDREF(*aResponseXML);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* readonly attribute unsigned long status; */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLHttpRequest::GetStatus(PRUint32 *aStatus)
|
|
|
|
{
|
|
|
|
if (mChannel) {
|
|
|
|
return mChannel->GetResponseStatus(aStatus);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* readonly attribute string statusText; */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLHttpRequest::GetStatusText(char * *aStatusText)
|
|
|
|
{
|
2006-04-20 07:36:55 +04:00
|
|
|
NS_ENSURE_ARG_POINTER(aStatusText);
|
|
|
|
*aStatusText = nsnull;
|
2006-04-20 07:36:50 +04:00
|
|
|
if (mChannel) {
|
|
|
|
return mChannel->GetResponseString(aStatusText);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* void abort (); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLHttpRequest::Abort()
|
|
|
|
{
|
|
|
|
if (mChannel) {
|
|
|
|
return mChannel->Cancel(NS_BINDING_ABORTED);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* string getAllResponseHeaders (); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLHttpRequest::GetAllResponseHeaders(char **_retval)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(_retval);
|
2006-04-20 07:36:55 +04:00
|
|
|
*_retval = nsnull;
|
2006-04-20 07:36:50 +04:00
|
|
|
if (mChannel) {
|
|
|
|
nsCOMPtr<nsISimpleEnumerator> enumerator;
|
|
|
|
nsCAutoString headers;
|
|
|
|
|
|
|
|
nsresult rv = mChannel->GetResponseHeaderEnumerator(getter_AddRefs(enumerator));
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool hasMore;
|
|
|
|
while(NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) {
|
|
|
|
nsCOMPtr<nsISupports> isup;
|
|
|
|
|
|
|
|
rv = enumerator->GetNext(getter_AddRefs(isup));
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIHTTPHeader> header = do_QueryInterface(isup);
|
|
|
|
if (header) {
|
|
|
|
nsXPIDLCString name, value;
|
|
|
|
header->GetFieldName(getter_Copies(name));
|
|
|
|
header->GetValue(getter_Copies(value));
|
|
|
|
headers.Append((const char*)name);
|
|
|
|
headers.Append(": ");
|
|
|
|
headers.Append((const char*)value);
|
|
|
|
headers.Append("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*_retval = headers.ToNewCString();
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* string getResponseHeader (in string header); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLHttpRequest::GetResponseHeader(const char *header, char **_retval)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(header);
|
|
|
|
NS_ENSURE_ARG_POINTER(_retval);
|
|
|
|
|
2006-04-20 07:36:55 +04:00
|
|
|
*_retval = nsnull;
|
2006-04-20 07:36:50 +04:00
|
|
|
if (mChannel) {
|
|
|
|
nsCOMPtr<nsIAtom> headerAtom = dont_AddRef(NS_NewAtom(header));
|
|
|
|
return mChannel->GetResponseHeader(headerAtom, _retval);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2006-04-20 07:36:55 +04:00
|
|
|
/* noscript void openRequest (in string method, in string url, in boolean async, in string user, in string password); */
|
2006-04-20 07:36:50 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLHttpRequest::OpenRequest(const char *method,
|
2006-04-20 07:36:55 +04:00
|
|
|
const char *url,
|
2006-04-20 07:36:50 +04:00
|
|
|
PRBool async,
|
|
|
|
const char *user,
|
|
|
|
const char *password)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(method);
|
|
|
|
NS_ENSURE_ARG(url);
|
|
|
|
|
|
|
|
nsresult rv;
|
2006-04-20 07:36:51 +04:00
|
|
|
nsCOMPtr<nsIURI> uri;
|
2006-04-20 07:36:50 +04:00
|
|
|
nsCOMPtr<nsILoadGroup> loadGroup;
|
|
|
|
PRBool authp = PR_FALSE;
|
|
|
|
|
2006-04-20 07:36:54 +04:00
|
|
|
// Return error if we're alreday processing a request
|
|
|
|
if (XML_HTTP_REQUEST_SENT == mStatus) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2006-04-20 07:36:50 +04:00
|
|
|
mAsync = async;
|
|
|
|
|
|
|
|
// If we have a base document, use it for the base URL and loadgroup
|
|
|
|
if (mBaseDocument) {
|
|
|
|
rv = mBaseDocument->GetDocumentLoadGroup(getter_AddRefs(loadGroup));
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
}
|
|
|
|
|
2006-04-20 07:36:55 +04:00
|
|
|
rv = NS_NewURI(getter_AddRefs(uri), url, mBaseURI);
|
2006-04-20 07:36:50 +04:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
// Only http URLs are allowed
|
|
|
|
nsXPIDLCString protocol;
|
|
|
|
uri->GetScheme(getter_Copies(protocol));
|
2006-04-20 07:36:51 +04:00
|
|
|
if (nsCRT::strncmp("http", (const char*)protocol, 4) != 0) {
|
2006-04-20 07:36:50 +04:00
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (user) {
|
|
|
|
nsCAutoString prehost;
|
|
|
|
prehost.Assign(user);
|
|
|
|
if (password) {
|
|
|
|
prehost.Append(":");
|
|
|
|
prehost.Append(password);
|
|
|
|
}
|
|
|
|
uri->SetPreHost(prehost.GetBuffer());
|
|
|
|
authp = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIChannel> channel;
|
|
|
|
rv = NS_OpenURI(getter_AddRefs(channel), uri, nsnull, loadGroup);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
mChannel = do_QueryInterface(channel);
|
|
|
|
if (!mChannel) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
mChannel->SetAuthTriedWithPrehost(authp);
|
2006-04-20 07:36:51 +04:00
|
|
|
|
2006-04-20 07:36:50 +04:00
|
|
|
nsCOMPtr<nsIAtom> methodAtom = dont_AddRef(NS_NewAtom(method));
|
|
|
|
if (methodAtom) {
|
|
|
|
rv = mChannel->SetRequestMethod(methodAtom);
|
|
|
|
}
|
2006-04-20 07:36:54 +04:00
|
|
|
|
|
|
|
mStatus = XML_HTTP_REQUEST_OPENED;
|
|
|
|
|
2006-04-20 07:36:50 +04:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2006-04-20 07:36:55 +04:00
|
|
|
/* void open (in string method, in string url); */
|
2006-04-20 07:36:50 +04:00
|
|
|
NS_IMETHODIMP
|
2006-04-20 07:36:55 +04:00
|
|
|
nsXMLHttpRequest::Open(const char *method, const char *url)
|
2006-04-20 07:36:50 +04:00
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
PRBool async = PR_TRUE;
|
|
|
|
char* user = nsnull;
|
|
|
|
char* password = nsnull;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIXPCNativeCallContext> cc;
|
|
|
|
NS_WITH_SERVICE(nsIXPConnect, xpc, nsIXPConnect::GetCID(), &rv);
|
|
|
|
if(NS_SUCCEEDED(rv)) {
|
|
|
|
rv = xpc->GetCurrentNativeCallContext(getter_AddRefs(cc));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && cc) {
|
|
|
|
PRUint32 argc;
|
|
|
|
rv = cc->GetArgc(&argc);
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
jsval* argv;
|
|
|
|
rv = cc->GetArgvPtr(&argv);
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
JSContext* cx;
|
|
|
|
rv = cc->GetJSContext(&cx);
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
|
2006-04-20 07:36:51 +04:00
|
|
|
NS_WITH_SERVICE(nsIScriptSecurityManager, secMan,
|
2006-04-20 07:37:00 +04:00
|
|
|
NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
|
2006-04-20 07:36:51 +04:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
nsCOMPtr<nsIPrincipal> principal;
|
|
|
|
rv = secMan->GetSubjectPrincipal(getter_AddRefs(principal));
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
nsCOMPtr<nsICodebasePrincipal> codebase = do_QueryInterface(principal);
|
|
|
|
if (codebase) {
|
|
|
|
codebase->GetURI(getter_AddRefs(mBaseURI));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-04-20 07:36:50 +04:00
|
|
|
if (argc > 2) {
|
2006-04-20 07:36:52 +04:00
|
|
|
JSBool asyncBool;
|
|
|
|
JS_ValueToBoolean(cx, argv[2], &asyncBool);
|
|
|
|
async = (PRBool)asyncBool;
|
2006-04-20 07:36:50 +04:00
|
|
|
|
|
|
|
if (argc > 3) {
|
|
|
|
JSString* userStr;
|
|
|
|
|
|
|
|
userStr = JS_ValueToString(cx, argv[3]);
|
|
|
|
if (userStr) {
|
|
|
|
user = JS_GetStringBytes(userStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc > 4) {
|
|
|
|
JSString* passwordStr;
|
|
|
|
|
|
|
|
passwordStr = JS_ValueToString(cx, argv[4]);
|
|
|
|
if (passwordStr) {
|
|
|
|
password = JS_GetStringBytes(passwordStr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return OpenRequest(method, url, async, user, password);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXMLHttpRequest::GetStreamForWString(const PRUnichar* aStr,
|
|
|
|
PRInt32 aLength,
|
|
|
|
nsIInputStream** aStream)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIUnicodeEncoder> encoder;
|
|
|
|
nsAutoString charsetStr;
|
|
|
|
char* postData;
|
|
|
|
|
|
|
|
// We want to encode the string as utf-8, so get the right encoder
|
|
|
|
NS_WITH_SERVICE(nsICharsetConverterManager,
|
|
|
|
charsetConv,
|
|
|
|
kCharsetConverterManagerCID,
|
|
|
|
&rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
charsetStr.AssignWithConversion("UTF-8");
|
|
|
|
rv = charsetConv->GetUnicodeEncoder(&charsetStr,
|
|
|
|
getter_AddRefs(encoder));
|
|
|
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
// Convert to utf-8
|
|
|
|
PRInt32 charLength;
|
|
|
|
const PRUnichar* unicodeBuf = aStr;
|
|
|
|
PRInt32 unicodeLength = aLength;
|
|
|
|
|
|
|
|
rv = encoder->GetMaxLength(unicodeBuf, unicodeLength, &charLength);
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
#define MAX_HEADER_SIZE 128
|
|
|
|
|
|
|
|
// Allocate extra space for the header and trailing CRLF
|
|
|
|
postData = (char*)nsMemory::Alloc(MAX_HEADER_SIZE + charLength + 3);
|
|
|
|
if (!postData) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
rv = encoder->Convert(unicodeBuf,
|
|
|
|
&unicodeLength, postData+MAX_HEADER_SIZE, &charLength);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
nsMemory::Free(postData);
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now that we know the real content length we can create the header
|
|
|
|
PR_snprintf(postData,
|
|
|
|
MAX_HEADER_SIZE,
|
|
|
|
"Content-type: text/xml\015\012Content-Length: %d\015\012\015\012",
|
|
|
|
charLength);
|
|
|
|
PRInt32 headerSize = nsCRT::strlen(postData);
|
|
|
|
|
|
|
|
// Copy the post data to immediately follow the header
|
|
|
|
nsCRT::memcpy(postData+headerSize, postData+MAX_HEADER_SIZE, charLength);
|
|
|
|
|
|
|
|
// Shove in the traling CRLF
|
|
|
|
postData[headerSize+charLength] = CR;
|
|
|
|
postData[headerSize+charLength+1] = LF;
|
|
|
|
postData[headerSize+charLength+2] = '\0';
|
|
|
|
|
|
|
|
// The new stream takes ownership of the buffer
|
|
|
|
rv = NS_NewByteArrayInputStream((nsIByteArrayInputStream**)aStream,
|
|
|
|
postData,
|
|
|
|
headerSize+charLength+2);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
nsMemory::Free(postData);
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* void send (in nsISupports body); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLHttpRequest::Send(nsISupports *body)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIInputStream> postDataStream;
|
|
|
|
|
2006-04-20 07:36:54 +04:00
|
|
|
// Return error if we're alreday processing a request
|
|
|
|
if (XML_HTTP_REQUEST_SENT == mStatus) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure we've been opened
|
2006-04-20 07:36:50 +04:00
|
|
|
if (!mChannel) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
|
2006-04-20 07:36:51 +04:00
|
|
|
if (body) {
|
|
|
|
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(body);
|
|
|
|
if (doc) {
|
|
|
|
// Get an XML serializer
|
2006-04-20 07:37:00 +04:00
|
|
|
nsCOMPtr<nsIDOMSerializer> serializer = do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID, &rv);
|
2006-04-20 07:36:51 +04:00
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// Serialize the current document to string
|
|
|
|
nsXPIDLString serial;
|
|
|
|
rv = serializer->SerializeToString(doc, getter_Copies(serial));
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// Convert to a byte stream
|
|
|
|
rv = GetStreamForWString((const PRUnichar*)serial,
|
|
|
|
nsCRT::strlen((const PRUnichar*)serial),
|
|
|
|
getter_AddRefs(postDataStream));
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
2006-04-20 07:36:50 +04:00
|
|
|
}
|
|
|
|
else {
|
2006-04-20 07:36:51 +04:00
|
|
|
nsCOMPtr<nsIInputStream> stream = do_QueryInterface(body);
|
|
|
|
if (stream) {
|
|
|
|
postDataStream = stream;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
nsCOMPtr<nsISupportsWString> wstr = do_QueryInterface(body);
|
|
|
|
if (wstr) {
|
|
|
|
nsXPIDLString holder;
|
|
|
|
wstr->GetData(getter_Copies(holder));
|
|
|
|
rv = GetStreamForWString((const PRUnichar*)holder,
|
|
|
|
nsCRT::strlen((const PRUnichar*)holder),
|
|
|
|
getter_AddRefs(postDataStream));
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
}
|
2006-04-20 07:36:50 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-04-20 07:36:51 +04:00
|
|
|
if (postDataStream) {
|
|
|
|
rv = mChannel->SetUploadStream(postDataStream);
|
|
|
|
}
|
2006-04-20 07:36:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get and initialize a DOMImplementation
|
|
|
|
nsCOMPtr<nsIDOMDOMImplementation> implementation = do_CreateInstance(kIDOMDOMImplementationCID, &rv);
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
|
2006-04-20 07:36:51 +04:00
|
|
|
if (mBaseURI) {
|
2006-04-20 07:36:50 +04:00
|
|
|
nsCOMPtr<nsIPrivateDOMImplementation> privImpl = do_QueryInterface(implementation);
|
|
|
|
if (privImpl) {
|
2006-04-20 07:36:51 +04:00
|
|
|
privImpl->Init(mBaseURI);
|
2006-04-20 07:36:50 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create an empty document from it
|
|
|
|
nsAutoString emptyStr;
|
|
|
|
rv = implementation->CreateDocument(emptyStr,
|
|
|
|
emptyStr,
|
|
|
|
nsnull,
|
|
|
|
getter_AddRefs(mDocument));
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// Register as a load listener on the document
|
2006-04-20 07:36:54 +04:00
|
|
|
nsCOMPtr<nsIDOMEventReceiver> target = do_QueryInterface(mDocument);
|
2006-04-20 07:36:50 +04:00
|
|
|
if (target) {
|
2006-04-20 07:36:56 +04:00
|
|
|
nsWeakPtr requestWeak = getter_AddRefs(NS_GetWeakReference(NS_STATIC_CAST(nsIXMLHttpRequest*, this)));
|
|
|
|
nsLoadListenerProxy* proxy = new nsLoadListenerProxy(requestWeak);
|
2006-04-20 07:36:54 +04:00
|
|
|
if (!proxy) return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
// This will addref the proxy
|
|
|
|
rv = target->AddEventListenerByIID(NS_STATIC_CAST(nsIDOMEventListener*,
|
|
|
|
proxy),
|
|
|
|
NS_GET_IID(nsIDOMLoadListener));
|
2006-04-20 07:36:50 +04:00
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tell the document to start loading
|
|
|
|
nsCOMPtr<nsIStreamListener> listener;
|
|
|
|
nsCOMPtr<nsIDocument> document = do_QueryInterface(mDocument);
|
|
|
|
if (!document) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2006-04-20 07:36:54 +04:00
|
|
|
|
|
|
|
#ifdef IMPLEMENT_SYNC_LOAD
|
|
|
|
nsCOMPtr<nsIEventQueue> modalEventQueue;
|
|
|
|
nsCOMPtr<nsIEventQueueService> eventQService;
|
|
|
|
|
|
|
|
if (!mAsync) {
|
|
|
|
nsCOMPtr<nsIXPCNativeCallContext> cc;
|
|
|
|
NS_WITH_SERVICE(nsIXPConnect, xpc, nsIXPConnect::GetCID(), &rv);
|
|
|
|
if(NS_SUCCEEDED(rv)) {
|
|
|
|
rv = xpc->GetCurrentNativeCallContext(getter_AddRefs(cc));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && cc) {
|
|
|
|
JSContext* cx;
|
|
|
|
rv = cc->GetJSContext(&cx);
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// We can only do this if we're called from a DOM script context
|
|
|
|
nsIScriptContext* scriptCX = (nsIScriptContext*)JS_GetContextPrivate(cx);
|
|
|
|
if (!scriptCX) return NS_OK;
|
|
|
|
|
|
|
|
// Get the nsIDocShellTreeOwner associated with the window
|
|
|
|
// containing this script context
|
|
|
|
// XXX Need to find a better way to do this rather than
|
|
|
|
// chaining through a bunch of getters and QIs
|
|
|
|
nsCOMPtr<nsIScriptGlobalObject> global;
|
|
|
|
global = dont_AddRef(scriptCX->GetGlobalObject());
|
|
|
|
if (!global) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocShell> docshell;
|
|
|
|
rv = global->GetDocShell(getter_AddRefs(docshell));
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(docshell);
|
|
|
|
if (!item) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
rv = item->GetTreeOwner(getter_AddRefs(mDocShellTreeOwner));
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
eventQService = do_GetService(kEventQueueServiceCID);
|
|
|
|
if(!eventQService ||
|
|
|
|
NS_FAILED(eventQService->PushThreadEventQueue(getter_AddRefs(modalEventQueue)))) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-04-20 07:36:50 +04:00
|
|
|
rv = document->StartDocumentLoad(kLoadAsData, mChannel,
|
|
|
|
nsnull, nsnull,
|
|
|
|
getter_AddRefs(listener),
|
|
|
|
PR_FALSE);
|
2006-04-20 07:36:54 +04:00
|
|
|
|
|
|
|
#ifdef IMPLEMENT_SYNC_LOAD
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
if (modalEventQueue) {
|
|
|
|
eventQService->PopThreadEventQueue(modalEventQueue);
|
|
|
|
}
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
#else
|
2006-04-20 07:36:50 +04:00
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
2006-04-20 07:36:54 +04:00
|
|
|
#endif
|
2006-04-20 07:36:50 +04:00
|
|
|
|
|
|
|
// Start reading from the channel
|
2006-04-20 07:36:54 +04:00
|
|
|
mStatus = XML_HTTP_REQUEST_SENT;
|
2006-04-20 07:36:50 +04:00
|
|
|
rv = mChannel->AsyncRead(listener, nsnull);
|
2006-04-20 07:36:54 +04:00
|
|
|
|
|
|
|
#ifdef IMPLEMENT_SYNC_LOAD
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
if (modalEventQueue) {
|
|
|
|
eventQService->PopThreadEventQueue(modalEventQueue);
|
|
|
|
}
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef IMPLEMENT_SYNC_LOAD
|
|
|
|
// If we're synchronous, spin an event loop here and wait
|
|
|
|
if (!mAsync && mDocShellTreeOwner) {
|
|
|
|
rv = mDocShellTreeOwner->ShowModal();
|
|
|
|
|
|
|
|
eventQService->PopThreadEventQueue(modalEventQueue);
|
|
|
|
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
2006-04-20 07:36:50 +04:00
|
|
|
}
|
2006-04-20 07:36:54 +04:00
|
|
|
#endif
|
2006-04-20 07:36:50 +04:00
|
|
|
|
2006-04-20 07:36:54 +04:00
|
|
|
return NS_OK;
|
2006-04-20 07:36:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* void setRequestHeader (in string header, in string value); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLHttpRequest::SetRequestHeader(const char *header, const char *value)
|
|
|
|
{
|
|
|
|
if (mChannel) {
|
|
|
|
nsCOMPtr<nsIAtom> headerAtom = dont_AddRef(NS_NewAtom(header));
|
|
|
|
return mChannel->SetRequestHeader(headerAtom, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// nsIDOMEventListener
|
|
|
|
nsresult
|
|
|
|
nsXMLHttpRequest::HandleEvent(nsIDOMEvent* aEvent)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// nsIDOMLoadListener
|
|
|
|
nsresult
|
|
|
|
nsXMLHttpRequest::Load(nsIDOMEvent* aEvent)
|
|
|
|
{
|
2006-04-20 07:36:54 +04:00
|
|
|
mStatus = XML_HTTP_REQUEST_COMPLETED;
|
|
|
|
#ifdef IMPLEMENT_SYNC_LOAD
|
|
|
|
if (mDocShellTreeOwner) {
|
|
|
|
mDocShellTreeOwner->ExitModalLoop(NS_OK);
|
|
|
|
mDocShellTreeOwner = 0;
|
|
|
|
}
|
|
|
|
#endif
|
2006-04-20 07:36:50 +04:00
|
|
|
if (mLoadEventListeners) {
|
|
|
|
PRUint32 index, count;
|
|
|
|
|
|
|
|
mLoadEventListeners->Count(&count);
|
|
|
|
for (index = 0; index < count; index++) {
|
|
|
|
nsCOMPtr<nsISupports> current = dont_AddRef(mLoadEventListeners->ElementAt(index));
|
|
|
|
if (current) {
|
|
|
|
nsCOMPtr<nsIDOMEventListener> listener = do_QueryInterface(current);
|
|
|
|
if (listener) {
|
|
|
|
listener->HandleEvent(aEvent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXMLHttpRequest::Unload(nsIDOMEvent* aEvent)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXMLHttpRequest::Abort(nsIDOMEvent* aEvent)
|
|
|
|
{
|
2006-04-20 07:36:54 +04:00
|
|
|
mStatus = XML_HTTP_REQUEST_ABORTED;
|
|
|
|
#ifdef IMPLEMENT_SYNC_LOAD
|
|
|
|
if (mDocShellTreeOwner) {
|
|
|
|
mDocShellTreeOwner->ExitModalLoop(NS_OK);
|
|
|
|
mDocShellTreeOwner = 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-04-20 07:36:50 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXMLHttpRequest::Error(nsIDOMEvent* aEvent)
|
|
|
|
{
|
2006-04-20 07:36:54 +04:00
|
|
|
mStatus = XML_HTTP_REQUEST_ABORTED;
|
|
|
|
#ifdef IMPLEMENT_SYNC_LOAD
|
|
|
|
if (mDocShellTreeOwner) {
|
|
|
|
mDocShellTreeOwner->ExitModalLoop(NS_OK);
|
|
|
|
mDocShellTreeOwner = 0;
|
|
|
|
}
|
|
|
|
#endif
|
2006-04-20 07:36:50 +04:00
|
|
|
if (mErrorEventListeners) {
|
|
|
|
PRUint32 index, count;
|
|
|
|
|
|
|
|
mErrorEventListeners->Count(&count);
|
|
|
|
for (index = 0; index < count; index++) {
|
|
|
|
nsCOMPtr<nsISupports> current = dont_AddRef(mErrorEventListeners->ElementAt(index));
|
|
|
|
if (current) {
|
|
|
|
nsCOMPtr<nsIDOMEventListener> listener = do_QueryInterface(current);
|
|
|
|
if (listener) {
|
|
|
|
listener->HandleEvent(aEvent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2006-04-20 07:36:53 +04:00
|
|
|
static const char* kAllAccess = "AllAccess";
|
|
|
|
|
|
|
|
/* string canCreateWrapper (in nsIIDPtr iid); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLHttpRequest::CanCreateWrapper(const nsIID * iid, char **_retval)
|
|
|
|
{
|
|
|
|
if (iid->Equals(NS_GET_IID(nsIXMLHttpRequest))) {
|
|
|
|
*_retval = nsCRT::strdup(kAllAccess);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* string canCallMethod (in nsIIDPtr iid, in wstring methodName); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLHttpRequest::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, char **_retval)
|
|
|
|
{
|
|
|
|
if (iid->Equals(NS_GET_IID(nsIXMLHttpRequest))) {
|
|
|
|
*_retval = nsCRT::strdup(kAllAccess);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* string canGetProperty (in nsIIDPtr iid, in wstring propertyName); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLHttpRequest::CanGetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
|
|
|
|
{
|
|
|
|
if (iid->Equals(NS_GET_IID(nsIXMLHttpRequest))) {
|
|
|
|
*_retval = nsCRT::strdup(kAllAccess);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* string canSetProperty (in nsIIDPtr iid, in wstring propertyName); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLHttpRequest::CanSetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
|
|
|
|
{
|
|
|
|
if (iid->Equals(NS_GET_IID(nsIXMLHttpRequest))) {
|
|
|
|
*_retval = nsCRT::strdup(kAllAccess);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|