2006-04-20 07:37:39 +04:00
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
2006-04-20 07:38:57 +04:00
* Version : MPL 1.1 / GPL 2.0 / LGPL 2.1
2006-04-20 07:36:50 +04:00
*
2006-04-20 07:38:57 +04:00
* 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/
2006-04-20 07:36:50 +04:00
*
2006-04-20 07:37:39 +04:00
* 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 .
2006-04-20 07:36:50 +04:00
*
* The Original Code is mozilla . org code .
*
2006-04-20 07:38:57 +04:00
* The Initial Developer of the Original Code is
2006-04-20 07:37:39 +04:00
* Netscape Communications Corporation .
* Portions created by the Initial Developer are Copyright ( C ) 1998
* the Initial Developer . All Rights Reserved .
2006-04-20 07:36:50 +04:00
*
2006-04-20 07:37:39 +04:00
* Contributor ( s ) :
*
* 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
2006-04-20 07:38:57 +04:00
* use your version of this file under the terms of the MPL , indicate your
2006-04-20 07:37:39 +04:00
* 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
2006-04-20 07:38:57 +04:00
* the terms of any one of the MPL , the GPL or the LGPL .
2006-04-20 07:37:39 +04:00
*
* * * * * * END LICENSE BLOCK * * * * * */
2006-04-20 07:36:50 +04:00
# include "nsXMLHttpRequest.h"
# include "nsISimpleEnumerator.h"
# include "nsIXPConnect.h"
# include "nsICharsetConverterManager.h"
# include "nsLayoutCID.h"
# include "nsXPIDLString.h"
2006-04-20 07:37:41 +04:00
# include "nsReadableUtils.h"
2006-04-20 07:36:50 +04:00
# include "nsIURI.h"
# include "nsILoadGroup.h"
# include "nsNetUtil.h"
2006-05-10 21:30:15 +04:00
# include "nsThreadUtils.h"
2006-04-20 07:37:32 +04:00
# include "nsIUploadChannel.h"
2006-04-20 07:36:50 +04:00
# include "nsIDOMSerializer.h"
2006-04-20 07:38:11 +04:00
# include "nsXPCOM.h"
2006-04-20 07:36:50 +04:00
# include "nsISupportsPrimitives.h"
2006-04-20 07:36:54 +04:00
# include "nsIDOMEventReceiver.h"
2006-04-20 07:37:34 +04:00
# include "nsIEventListenerManager.h"
# include "nsGUIEvent.h"
# include "nsIPrivateDOMEvent.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"
2006-04-20 07:36:54 +04:00
# include "nsWeakPtr.h"
2006-04-20 07:37:08 +04:00
# include "nsICharsetAlias.h"
2006-04-20 07:36:54 +04:00
# include "nsIScriptGlobalObject.h"
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2006-04-20 07:37:17 +04:00
# include "nsIDOMClassInfo.h"
2006-04-20 07:37:25 +04:00
# include "nsIDOMElement.h"
2006-04-20 07:38:10 +04:00
# include "nsIDOMWindow.h"
2006-04-20 07:37:45 +04:00
# include "nsIVariant.h"
2006-04-20 07:37:35 +04:00
# include "nsIParser.h"
# include "nsLoadListenerProxy.h"
2006-04-20 07:38:01 +04:00
# include "nsIWindowWatcher.h"
# include "nsIAuthPrompt.h"
2006-04-20 07:39:49 +04:00
# include "nsStringStream.h"
2006-04-20 07:38:52 +04:00
# include "nsIStreamConverterService.h"
2006-04-20 07:39:48 +04:00
# include "nsICachingChannel.h"
2006-04-26 13:19:48 +04:00
# include "nsContentUtils.h"
2006-05-05 21:01:53 +04:00
# include "nsEventDispatcher.h"
2006-06-13 07:07:47 +04:00
# include "nsDOMJSUtils.h"
2006-05-26 05:00:21 +04:00
# include "nsCOMArray.h"
# include "nsDOMClassInfo.h"
2006-06-16 00:30:44 +04:00
# include "nsIScriptableUConv.h"
2006-05-05 21:01:53 +04:00
# define LOAD_STR "load"
# define ERROR_STR "error"
# define PROGRESS_STR "progress"
# define UPLOADPROGRESS_STR "uploadprogress"
# define READYSTATE_STR "readystatechange"
2006-04-20 07:36:50 +04:00
2006-04-20 07:36:54 +04:00
// CIDs
2006-04-20 07:36:50 +04:00
2006-04-20 07:38:26 +04:00
// State
2006-04-20 07:38:52 +04:00
# define XML_HTTP_REQUEST_UNINITIALIZED (1 << 0) // 0
# define XML_HTTP_REQUEST_OPENED (1 << 1) // 1 aka LOADING
# define XML_HTTP_REQUEST_LOADED (1 << 2) // 2
# define XML_HTTP_REQUEST_INTERACTIVE (1 << 3) // 3
# define XML_HTTP_REQUEST_COMPLETED (1 << 4) // 4
# define XML_HTTP_REQUEST_SENT (1 << 5) // Internal, LOADING in IE and external view
# define XML_HTTP_REQUEST_STOPPED (1 << 6) // Internal, INTERACTIVE in IE and external view
2006-05-26 05:00:21 +04:00
// The above states are mutually exclusive, change with ChangeState() only.
2006-04-20 07:38:26 +04:00
// The states below can be combined.
2006-04-20 07:38:52 +04:00
# define XML_HTTP_REQUEST_ABORTED (1 << 7) // Internal
# define XML_HTTP_REQUEST_ASYNC (1 << 8) // Internal
# define XML_HTTP_REQUEST_PARSEBODY (1 << 9) // Internal
# define XML_HTTP_REQUEST_XSITEENABLED (1 << 10) // Internal
# define XML_HTTP_REQUEST_SYNCLOOPING (1 << 11) // Internal
# define XML_HTTP_REQUEST_MULTIPART (1 << 12) // Internal
2006-05-26 05:00:21 +04:00
# define XML_HTTP_REQUEST_ROOTED (1 << 13) // Internal
2006-04-20 07:38:26 +04:00
# define XML_HTTP_REQUEST_LOADSTATES \
( XML_HTTP_REQUEST_UNINITIALIZED | \
XML_HTTP_REQUEST_OPENED | \
XML_HTTP_REQUEST_LOADED | \
XML_HTTP_REQUEST_INTERACTIVE | \
XML_HTTP_REQUEST_COMPLETED | \
XML_HTTP_REQUEST_SENT | \
XML_HTTP_REQUEST_STOPPED )
2006-04-20 07:39:48 +04:00
// This helper function adds the given load flags to the request's existing
// load flags.
static void AddLoadFlags ( nsIRequest * request , nsLoadFlags newFlags )
{
nsLoadFlags flags ;
request - > GetLoadFlags ( & flags ) ;
flags | = newFlags ;
request - > SetLoadFlags ( flags ) ;
}
2006-04-20 07:38:52 +04:00
// Helper proxy class to be used when expecting an
// multipart/x-mixed-replace stream of XML documents.
class nsMultipartProxyListener : public nsIStreamListener
{
public :
nsMultipartProxyListener ( nsIStreamListener * dest ) ;
virtual ~ nsMultipartProxyListener ( ) ;
/* additional members */
NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUESTOBSERVER
private :
nsCOMPtr < nsIStreamListener > mDestListener ;
} ;
nsMultipartProxyListener : : nsMultipartProxyListener ( nsIStreamListener * dest )
: mDestListener ( dest )
{
}
nsMultipartProxyListener : : ~ nsMultipartProxyListener ( )
{
}
NS_IMPL_ISUPPORTS2 ( nsMultipartProxyListener , nsIStreamListener ,
nsIRequestObserver )
/** nsIRequestObserver methods **/
NS_IMETHODIMP
nsMultipartProxyListener : : OnStartRequest ( nsIRequest * aRequest ,
nsISupports * ctxt )
{
nsCOMPtr < nsIChannel > channel ( do_QueryInterface ( aRequest ) ) ;
NS_ENSURE_TRUE ( channel , NS_ERROR_UNEXPECTED ) ;
nsCAutoString contentType ;
nsresult rv = channel - > GetContentType ( contentType ) ;
2006-04-20 07:39:11 +04:00
if ( ! contentType . EqualsLiteral ( " multipart/x-mixed-replace " ) ) {
2006-04-20 07:38:52 +04:00
return NS_ERROR_INVALID_ARG ;
}
// If multipart/x-mixed-replace content, we'll insert a MIME
// decoder in the pipeline to handle the content and pass it along
// to our original listener.
nsCOMPtr < nsIStreamConverterService > convServ =
do_GetService ( " @mozilla.org/streamConverters;1 " , & rv ) ;
if ( NS_SUCCEEDED ( rv ) ) {
nsCOMPtr < nsIStreamListener > toListener ( mDestListener ) ;
nsCOMPtr < nsIStreamListener > fromListener ;
2006-04-20 07:39:15 +04:00
rv = convServ - > AsyncConvertData ( " multipart/x-mixed-replace " ,
" */* " ,
2006-04-20 07:38:52 +04:00
toListener ,
nsnull ,
getter_AddRefs ( fromListener ) ) ;
NS_ENSURE_TRUE ( NS_SUCCEEDED ( rv ) & & fromListener , NS_ERROR_UNEXPECTED ) ;
mDestListener = fromListener ;
}
return mDestListener - > OnStartRequest ( aRequest , ctxt ) ;
}
NS_IMETHODIMP
nsMultipartProxyListener : : OnStopRequest ( nsIRequest * aRequest ,
nsISupports * ctxt ,
nsresult status )
{
return mDestListener - > OnStopRequest ( aRequest , ctxt , status ) ;
}
/** nsIStreamListener methods **/
NS_IMETHODIMP
nsMultipartProxyListener : : OnDataAvailable ( nsIRequest * aRequest ,
nsISupports * ctxt ,
nsIInputStream * inStr ,
PRUint32 sourceOffset ,
PRUint32 count )
{
return mDestListener - > OnDataAvailable ( aRequest , ctxt , inStr , sourceOffset ,
count ) ;
}
2006-04-20 07:38:45 +04:00
static nsIScriptContext *
GetCurrentContext ( )
2006-04-20 07:36:50 +04:00
{
// Get JSContext from stack.
2006-04-20 07:37:23 +04:00
nsCOMPtr < nsIJSContextStack > stack =
do_GetService ( " @mozilla.org/js/xpc/ContextStack;1 " ) ;
2006-04-20 07:36:50 +04:00
2006-04-20 07:37:23 +04:00
if ( ! stack ) {
2006-04-20 07:38:45 +04:00
return nsnull ;
2006-04-20 07:36:50 +04:00
}
2006-04-20 07:37:23 +04:00
JSContext * cx ;
2006-04-20 07:36:50 +04:00
2006-04-20 07:38:45 +04:00
if ( NS_FAILED ( stack - > Peek ( & cx ) ) | | ! cx ) {
return nsnull ;
2006-04-20 07:36:50 +04:00
}
2006-04-20 07:38:45 +04:00
return GetScriptContextFromJSContext ( cx ) ;
2006-04-20 07:36:50 +04:00
}
2006-04-20 07:38:36 +04:00
/**
* Gets the nsIDocument given the script context . Will return nsnull on failure .
*
* @ param aScriptContext the script context to get the document for ; can be null
*
* @ return the document associated with the script context
*/
static already_AddRefed < nsIDocument >
GetDocumentFromScriptContext ( nsIScriptContext * aScriptContext )
{
if ( ! aScriptContext )
return nsnull ;
2006-04-20 07:38:45 +04:00
nsCOMPtr < nsIDOMWindow > window =
do_QueryInterface ( aScriptContext - > GetGlobalObject ( ) ) ;
2006-04-20 07:38:36 +04:00
nsIDocument * doc = nsnull ;
if ( window ) {
nsCOMPtr < nsIDOMDocument > domdoc ;
window - > GetDocument ( getter_AddRefs ( domdoc ) ) ;
2006-04-20 07:38:56 +04:00
if ( domdoc ) {
2006-04-20 07:38:55 +04:00
CallQueryInterface ( domdoc , & doc ) ;
2006-04-20 07:38:56 +04:00
}
2006-04-20 07:38:36 +04:00
}
return doc ;
}
2006-04-20 07:36:54 +04:00
2006-04-20 07:36:50 +04:00
/////////////////////////////////////////////
//
//
/////////////////////////////////////////////
nsXMLHttpRequest : : nsXMLHttpRequest ( )
2006-04-20 07:38:26 +04:00
: mState ( XML_HTTP_REQUEST_UNINITIALIZED )
2006-04-20 07:36:50 +04:00
{
}
nsXMLHttpRequest : : ~ nsXMLHttpRequest ( )
{
2006-04-20 07:39:09 +04:00
if ( mState & ( XML_HTTP_REQUEST_STOPPED |
XML_HTTP_REQUEST_SENT |
2006-04-20 07:38:26 +04:00
XML_HTTP_REQUEST_INTERACTIVE ) ) {
2006-04-20 07:36:54 +04:00
Abort ( ) ;
2006-04-20 07:39:09 +04:00
}
2006-04-20 07:38:26 +04:00
NS_ABORT_IF_FALSE ( ! ( mState & XML_HTTP_REQUEST_SYNCLOOPING ) , " we rather crash than hang " ) ;
mState & = ~ XML_HTTP_REQUEST_SYNCLOOPING ;
2006-05-26 05:00:21 +04:00
// Needed to free the listener arrays.
ClearEventListeners ( ) ;
2006-04-20 07:36:50 +04:00
}
2006-04-20 07:36:54 +04:00
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2006-04-20 07:37:17 +04:00
// QueryInterface implementation for nsXMLHttpRequest
2006-04-20 07:36:54 +04:00
NS_INTERFACE_MAP_BEGIN ( nsXMLHttpRequest )
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2006-04-20 07:37:17 +04:00
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS ( nsISupports , nsIXMLHttpRequest )
NS_INTERFACE_MAP_ENTRY ( nsIXMLHttpRequest )
2006-04-20 07:37:23 +04:00
NS_INTERFACE_MAP_ENTRY ( nsIJSXMLHttpRequest )
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2006-04-20 07:37:17 +04:00
NS_INTERFACE_MAP_ENTRY ( nsIDOMLoadListener )
NS_INTERFACE_MAP_ENTRY ( nsIDOMEventTarget )
NS_INTERFACE_MAP_ENTRY ( nsIRequestObserver )
NS_INTERFACE_MAP_ENTRY ( nsIStreamListener )
2006-04-20 07:39:29 +04:00
NS_INTERFACE_MAP_ENTRY ( nsIChannelEventSink )
2006-04-20 07:39:18 +04:00
NS_INTERFACE_MAP_ENTRY ( nsIProgressEventSink )
2006-04-20 07:38:01 +04:00
NS_INTERFACE_MAP_ENTRY ( nsIInterfaceRequestor )
2006-11-23 02:18:16 +03:00
NS_INTERFACE_MAP_ENTRY ( nsIDOMGCParticipant )
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2006-04-20 07:37:17 +04:00
NS_INTERFACE_MAP_ENTRY ( nsISupportsWeakReference )
2006-04-26 13:19:48 +04:00
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO ( XMLHttpRequest )
2006-04-20 07:36:54 +04:00
NS_INTERFACE_MAP_END
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2006-04-20 07:37:17 +04:00
2006-11-23 02:18:16 +03:00
NS_IMPL_ADDREF ( nsXMLHttpRequest )
NS_IMPL_RELEASE ( nsXMLHttpRequest )
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2006-04-20 07:37:17 +04:00
2006-04-20 07:37:23 +04:00
/* void addEventListener (in string type, in nsIDOMEventListener
listener ) ; */
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2006-04-20 07:37:17 +04:00
NS_IMETHODIMP
2006-04-20 07:37:57 +04:00
nsXMLHttpRequest : : AddEventListener ( const nsAString & type ,
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2006-04-20 07:37:17 +04:00
nsIDOMEventListener * listener ,
PRBool useCapture )
2006-04-20 07:36:50 +04:00
{
NS_ENSURE_ARG ( listener ) ;
2006-11-23 02:18:16 +03:00
nsTArray < ListenerHolder * > * array ;
2006-05-26 05:00:21 +04:00
2006-05-05 21:01:53 +04:00
# define IMPL_ADD_LISTENER(_type, _member) \
if ( type . EqualsLiteral ( _type ) ) { \
2006-05-26 05:00:21 +04:00
array = & ( _member ) ; \
2006-05-05 21:01:53 +04:00
} else
IMPL_ADD_LISTENER ( LOAD_STR , mLoadEventListeners )
IMPL_ADD_LISTENER ( ERROR_STR , mErrorEventListeners )
IMPL_ADD_LISTENER ( PROGRESS_STR , mProgressEventListeners )
IMPL_ADD_LISTENER ( UPLOADPROGRESS_STR , mUploadProgressEventListeners )
IMPL_ADD_LISTENER ( READYSTATE_STR , mReadystatechangeEventListeners )
{
2006-04-20 07:36:50 +04:00
return NS_ERROR_INVALID_ARG ;
}
2006-05-26 05:00:21 +04:00
2006-11-23 02:18:16 +03:00
ListenerHolder * holder = new ListenerHolder ;
NS_ENSURE_TRUE ( holder , NS_ERROR_OUT_OF_MEMORY ) ;
holder - > Set ( listener , this ) ;
array - > AppendElement ( holder ) ;
2006-05-26 05:00:21 +04:00
2006-04-20 07:38:45 +04:00
mScriptContext = GetCurrentContext ( ) ;
2006-04-20 07:36:50 +04:00
2006-05-05 21:01:53 +04:00
# undef IMPL_ADD_LISTENER
2006-04-20 07:36:50 +04:00
return NS_OK ;
}
2006-04-20 07:37:23 +04:00
/* void removeEventListener (in string type, in nsIDOMEventListener
listener ) ; */
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2006-04-20 07:37:57 +04:00
nsXMLHttpRequest : : RemoveEventListener ( const nsAString & type ,
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2006-04-20 07:37:17 +04:00
nsIDOMEventListener * listener ,
PRBool useCapture )
2006-04-20 07:36:50 +04:00
{
NS_ENSURE_ARG ( listener ) ;
2006-11-23 02:18:16 +03:00
nsTArray < ListenerHolder * > * array ;
2006-05-05 21:01:53 +04:00
# define IMPL_REMOVE_LISTENER(_type, _member) \
if ( type . EqualsLiteral ( _type ) ) { \
2006-05-26 05:00:21 +04:00
array = & ( _member ) ; \
2006-05-05 21:01:53 +04:00
} else
IMPL_REMOVE_LISTENER ( LOAD_STR , mLoadEventListeners )
IMPL_REMOVE_LISTENER ( ERROR_STR , mErrorEventListeners )
IMPL_REMOVE_LISTENER ( PROGRESS_STR , mProgressEventListeners )
IMPL_REMOVE_LISTENER ( UPLOADPROGRESS_STR , mUploadProgressEventListeners )
IMPL_REMOVE_LISTENER ( READYSTATE_STR , mReadystatechangeEventListeners )
{
2006-04-20 07:36:50 +04:00
return NS_ERROR_INVALID_ARG ;
}
2006-05-26 05:00:21 +04:00
// Allow a caller to remove O(N^2) behavior by removing end-to-start.
2006-11-23 02:18:16 +03:00
for ( PRUint32 i = array - > Length ( ) - 1 ; i ! = PRUint32 ( - 1 ) ; - - i ) {
ListenerHolder * holder = array - > ElementAt ( i ) ;
if ( nsCOMPtr < nsIDOMEventListener > ( holder - > Get ( ) ) = = listener ) {
array - > RemoveElementAt ( i ) ;
delete holder ;
2006-05-26 05:00:21 +04:00
break ;
}
}
2006-04-20 07:36:50 +04:00
return NS_OK ;
}
2006-04-20 07:37:40 +04:00
/* boolean dispatchEvent (in nsIDOMEvent evt); */
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2006-04-20 07:37:17 +04:00
NS_IMETHODIMP
2006-04-20 07:37:40 +04:00
nsXMLHttpRequest : : DispatchEvent ( nsIDOMEvent * evt , PRBool * _retval )
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2006-04-20 07:37:17 +04:00
{
// Ignored
return NS_OK ;
}
2006-05-05 21:01:53 +04:00
/* attribute nsIDOMEventListener onreadystatechange; */
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2006-05-05 21:01:53 +04:00
nsXMLHttpRequest : : GetOnreadystatechange ( nsIDOMEventListener * * aOnreadystatechange )
2006-04-20 07:37:31 +04:00
{
NS_ENSURE_ARG_POINTER ( aOnreadystatechange ) ;
2006-11-23 02:18:16 +03:00
mOnReadystatechangeListener . Get ( aOnreadystatechange ) ;
2006-04-20 07:37:31 +04:00
return NS_OK ;
}
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2006-05-05 21:01:53 +04:00
nsXMLHttpRequest : : SetOnreadystatechange ( nsIDOMEventListener * aOnreadystatechange )
2006-04-20 07:37:31 +04:00
{
2006-11-23 02:18:16 +03:00
mOnReadystatechangeListener . Set ( aOnreadystatechange , this ) ;
2006-04-20 07:37:31 +04:00
2006-04-20 07:38:45 +04:00
mScriptContext = GetCurrentContext ( ) ;
2006-04-20 07:37:31 +04:00
return NS_OK ;
}
2006-04-20 07:36:50 +04:00
/* attribute nsIDOMEventListener onload; */
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2006-04-20 07:37:23 +04:00
nsXMLHttpRequest : : GetOnload ( nsIDOMEventListener * * aOnLoad )
2006-04-20 07:36:50 +04:00
{
NS_ENSURE_ARG_POINTER ( aOnLoad ) ;
2006-11-23 02:18:16 +03:00
mOnLoadListener . Get ( aOnLoad ) ;
2006-04-20 07:37:23 +04:00
2006-04-20 07:36:50 +04:00
return NS_OK ;
}
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2006-04-20 07:37:23 +04:00
nsXMLHttpRequest : : SetOnload ( nsIDOMEventListener * aOnLoad )
2006-04-20 07:36:50 +04:00
{
2006-11-23 02:18:16 +03:00
mOnLoadListener . Set ( aOnLoad , this ) ;
2006-04-20 07:36:50 +04:00
2006-04-20 07:38:45 +04:00
mScriptContext = GetCurrentContext ( ) ;
2006-04-20 07:36:50 +04:00
2006-04-20 07:37:23 +04:00
return NS_OK ;
2006-04-20 07:36:50 +04:00
}
/* attribute nsIDOMEventListener onerror; */
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2006-04-20 07:37:23 +04:00
nsXMLHttpRequest : : GetOnerror ( nsIDOMEventListener * * aOnerror )
2006-04-20 07:36:50 +04:00
{
NS_ENSURE_ARG_POINTER ( aOnerror ) ;
2006-11-23 02:18:16 +03:00
mOnErrorListener . Get ( aOnerror ) ;
2006-04-20 07:37:23 +04:00
2006-04-20 07:36:50 +04:00
return NS_OK ;
}
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2006-04-20 07:37:23 +04:00
nsXMLHttpRequest : : SetOnerror ( nsIDOMEventListener * aOnerror )
2006-04-20 07:36:50 +04:00
{
2006-11-23 02:18:16 +03:00
mOnErrorListener . Set ( aOnerror , this ) ;
2006-04-20 07:36:50 +04:00
2006-04-20 07:38:45 +04:00
mScriptContext = GetCurrentContext ( ) ;
2006-04-20 07:36:50 +04:00
2006-04-20 07:37:23 +04:00
return NS_OK ;
2006-04-20 07:36:50 +04:00
}
2006-04-20 07:39:18 +04:00
/* attribute nsIDOMEventListener onprogress; */
NS_IMETHODIMP
nsXMLHttpRequest : : GetOnprogress ( nsIDOMEventListener * * aOnprogress )
{
2006-11-23 02:18:16 +03:00
NS_ENSURE_ARG_POINTER ( aOnprogress ) ;
2006-04-20 07:39:18 +04:00
2006-11-23 02:18:16 +03:00
mOnProgressListener . Get ( aOnprogress ) ;
2006-04-20 07:39:18 +04:00
return NS_OK ;
}
NS_IMETHODIMP
nsXMLHttpRequest : : SetOnprogress ( nsIDOMEventListener * aOnprogress )
{
2006-11-23 02:18:16 +03:00
mOnProgressListener . Set ( aOnprogress , this ) ;
2006-04-20 07:39:18 +04:00
mScriptContext = GetCurrentContext ( ) ;
return NS_OK ;
}
2006-05-05 21:01:53 +04:00
/* attribute nsIDOMEventListener onuploadprogress; */
NS_IMETHODIMP
nsXMLHttpRequest : : GetOnuploadprogress ( nsIDOMEventListener * * aOnuploadprogress )
{
2006-11-23 02:18:16 +03:00
NS_ENSURE_ARG_POINTER ( aOnuploadprogress ) ;
2006-05-05 21:01:53 +04:00
2006-11-23 02:18:16 +03:00
mOnUploadProgressListener . Get ( aOnuploadprogress ) ;
2006-05-05 21:01:53 +04:00
return NS_OK ;
}
NS_IMETHODIMP
nsXMLHttpRequest : : SetOnuploadprogress ( nsIDOMEventListener * aOnuploadprogress )
{
2006-11-23 02:18:16 +03:00
mOnUploadProgressListener . Set ( aOnuploadprogress , this ) ;
2006-05-05 21:01:53 +04:00
mScriptContext = GetCurrentContext ( ) ;
return NS_OK ;
}
2006-04-20 07:37:29 +04:00
/* readonly attribute nsIChannel channel; */
2006-04-20 07:39:10 +04:00
NS_IMETHODIMP
nsXMLHttpRequest : : GetChannel ( nsIChannel * * aChannel )
2006-04-20 07:37:01 +04:00
{
NS_ENSURE_ARG_POINTER ( aChannel ) ;
2006-11-23 02:18:16 +03:00
* aChannel = mChannel ;
NS_IF_ADDREF ( * aChannel ) ;
2006-04-20 07:37:01 +04:00
return NS_OK ;
}
2006-04-20 07:36:50 +04:00
/* readonly attribute nsIDOMDocument responseXML; */
2006-04-20 07:39:10 +04:00
NS_IMETHODIMP
nsXMLHttpRequest : : GetResponseXML ( nsIDOMDocument * * aResponseXML )
2006-04-20 07:36:50 +04:00
{
NS_ENSURE_ARG_POINTER ( aResponseXML ) ;
* aResponseXML = nsnull ;
2006-04-20 07:38:26 +04:00
if ( ( XML_HTTP_REQUEST_COMPLETED & mState ) & & mDocument ) {
2006-04-20 07:36:50 +04:00
* aResponseXML = mDocument ;
NS_ADDREF ( * aResponseXML ) ;
}
return NS_OK ;
}
2006-04-20 07:37:08 +04:00
/*
* This piece copied from nsXMLDocument , we try to get the charset
* from HTTP headers .
*/
nsresult
2006-04-20 07:38:32 +04:00
nsXMLHttpRequest : : DetectCharset ( nsACString & aCharset )
2006-04-20 07:37:08 +04:00
{
aCharset . Truncate ( ) ;
nsresult rv ;
2006-04-20 07:37:53 +04:00
nsCAutoString charsetVal ;
2006-04-20 07:38:52 +04:00
nsCOMPtr < nsIChannel > channel ( do_QueryInterface ( mReadRequest ) ) ;
if ( ! channel ) {
channel = mChannel ;
2006-04-20 07:39:32 +04:00
if ( ! channel ) {
// There will be no mChannel when we got a necko error in
// OnStopRequest or if we were never sent.
return NS_ERROR_NOT_AVAILABLE ;
}
2006-04-20 07:38:52 +04:00
}
rv = channel - > GetContentCharset ( charsetVal ) ;
2006-04-20 07:37:53 +04:00
if ( NS_SUCCEEDED ( rv ) ) {
2006-05-07 02:09:20 +04:00
nsCOMPtr < nsICharsetAlias > calias ( do_GetService ( NS_CHARSETALIAS_CONTRACTID , & rv ) ) ;
2006-04-20 07:37:53 +04:00
if ( NS_SUCCEEDED ( rv ) & & calias ) {
2006-04-20 07:38:32 +04:00
rv = calias - > GetPreferred ( charsetVal , aCharset ) ;
2006-04-20 07:37:08 +04:00
}
}
return rv ;
}
nsresult
2006-04-20 07:38:50 +04:00
nsXMLHttpRequest : : ConvertBodyToText ( nsAString & aOutBuffer )
2006-04-20 07:37:08 +04:00
{
2006-04-20 07:37:54 +04:00
// This code here is basically a copy of a similar thing in
// nsScanner::Append(const char* aBuffer, PRUint32 aLen).
2006-04-20 07:39:09 +04:00
// If we get illegal characters in the input we replace
2006-04-20 07:37:54 +04:00
// them and don't just fail.
2006-04-20 07:37:22 +04:00
PRInt32 dataLen = mResponseBody . Length ( ) ;
2006-04-20 07:37:08 +04:00
if ( ! dataLen )
return NS_OK ;
nsresult rv = NS_OK ;
2006-04-20 07:38:32 +04:00
nsCAutoString dataCharset ;
2006-04-20 07:37:08 +04:00
nsCOMPtr < nsIDocument > document ( do_QueryInterface ( mDocument ) ) ;
if ( document ) {
2006-04-20 07:38:41 +04:00
dataCharset = document - > GetDocumentCharacterSet ( ) ;
2006-04-20 07:37:08 +04:00
} else {
if ( NS_FAILED ( DetectCharset ( dataCharset ) ) | | dataCharset . IsEmpty ( ) ) {
2006-04-20 07:38:08 +04:00
// MS documentation states UTF-8 is default for responseText
2006-04-20 07:39:14 +04:00
dataCharset . AssignLiteral ( " UTF-8 " ) ;
2006-04-20 07:37:08 +04:00
}
}
2006-04-20 07:39:11 +04:00
if ( dataCharset . EqualsLiteral ( " ASCII " ) ) {
2006-04-20 07:38:50 +04:00
CopyASCIItoUTF16 ( mResponseBody , aOutBuffer ) ;
2006-04-20 07:37:08 +04:00
return NS_OK ;
}
2006-04-20 07:38:50 +04:00
nsCOMPtr < nsICharsetConverterManager > ccm =
do_GetService ( NS_CHARSETCONVERTERMANAGER_CONTRACTID , & rv ) ;
2006-04-20 07:37:08 +04:00
if ( NS_FAILED ( rv ) )
return rv ;
nsCOMPtr < nsIUnicodeDecoder > decoder ;
2006-04-20 07:38:32 +04:00
rv = ccm - > GetUnicodeDecoderRaw ( dataCharset . get ( ) ,
2006-04-20 07:38:28 +04:00
getter_AddRefs ( decoder ) ) ;
2006-04-20 07:37:08 +04:00
if ( NS_FAILED ( rv ) )
return rv ;
2006-04-20 07:37:22 +04:00
const char * inBuffer = mResponseBody . get ( ) ;
2006-04-20 07:37:54 +04:00
PRInt32 outBufferLength ;
rv = decoder - > GetMaxLength ( inBuffer , dataLen , & outBufferLength ) ;
if ( NS_FAILED ( rv ) )
return rv ;
2006-04-20 07:37:08 +04:00
2006-04-20 07:39:09 +04:00
PRUnichar * outBuffer =
2006-04-20 07:37:54 +04:00
NS_STATIC_CAST ( PRUnichar * , nsMemory : : Alloc ( ( outBufferLength + 1 ) *
sizeof ( PRUnichar ) ) ) ;
if ( ! outBuffer ) {
return NS_ERROR_OUT_OF_MEMORY ;
}
2006-04-20 07:37:08 +04:00
2006-04-20 07:37:54 +04:00
PRInt32 totalChars = 0 ,
outBufferIndex = 0 ,
outLen = outBufferLength ;
do {
PRInt32 inBufferLength = dataLen ;
2006-04-20 07:39:09 +04:00
rv = decoder - > Convert ( inBuffer ,
& inBufferLength ,
& outBuffer [ outBufferIndex ] ,
2006-04-20 07:37:54 +04:00
& outLen ) ;
totalChars + = outLen ;
if ( NS_FAILED ( rv ) ) {
2006-04-20 07:37:08 +04:00
// We consume one byte, replace it with U+FFFD
// and try the conversion again.
2006-04-20 07:37:54 +04:00
outBuffer [ outBufferIndex + outLen + + ] = ( PRUnichar ) 0xFFFD ;
2006-04-20 07:37:08 +04:00
outBufferIndex + = outLen ;
2006-04-20 07:37:54 +04:00
outLen = outBufferLength - ( + + totalChars ) ;
decoder - > Reset ( ) ;
if ( ( inBufferLength + 1 ) > dataLen ) {
inBufferLength = dataLen ;
} else {
inBufferLength + + ;
}
inBuffer = & inBuffer [ inBufferLength ] ;
dataLen - = inBufferLength ;
2006-04-20 07:37:08 +04:00
}
2006-04-20 07:37:54 +04:00
} while ( NS_FAILED ( rv ) & & ( dataLen > 0 ) ) ;
2006-04-20 07:38:50 +04:00
aOutBuffer . Assign ( outBuffer , totalChars ) ;
2006-04-20 07:39:19 +04:00
nsMemory : : Free ( outBuffer ) ;
2006-04-20 07:37:08 +04:00
return NS_OK ;
}
2006-04-20 07:38:50 +04:00
/* readonly attribute AString responseText; */
NS_IMETHODIMP nsXMLHttpRequest : : GetResponseText ( nsAString & aResponseText )
2006-04-20 07:37:08 +04:00
{
2006-04-20 07:38:50 +04:00
nsresult rv = NS_OK ;
aResponseText . Truncate ( ) ;
2006-04-20 07:38:26 +04:00
if ( mState & ( XML_HTTP_REQUEST_COMPLETED |
XML_HTTP_REQUEST_INTERACTIVE ) ) {
2006-04-20 07:38:50 +04:00
rv = ConvertBodyToText ( aResponseText ) ;
2006-04-20 07:37:08 +04:00
}
2006-04-20 07:38:50 +04:00
return rv ;
2006-04-20 07:37:08 +04:00
}
2006-04-20 07:36:50 +04:00
/* readonly attribute unsigned long status; */
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2006-04-20 07:36:50 +04:00
nsXMLHttpRequest : : GetStatus ( PRUint32 * aStatus )
{
2006-04-20 07:38:52 +04:00
nsCOMPtr < nsIHttpChannel > httpChannel = GetCurrentHttpChannel ( ) ;
2006-04-20 07:37:29 +04:00
if ( httpChannel ) {
2006-04-20 07:39:50 +04:00
nsresult rv = httpChannel - > GetResponseStatus ( aStatus ) ;
if ( rv = = NS_ERROR_NOT_AVAILABLE ) {
// Someone's calling this before we got a response... Check our
// ReadyState. If we're at 3 or 4, then this means the connection
// errored before we got any data; return a somewhat sensible error code
// in that case.
PRInt32 readyState ;
GetReadyState ( & readyState ) ;
if ( readyState > = 3 ) {
* aStatus = NS_ERROR_NOT_AVAILABLE ;
return NS_OK ;
}
}
return rv ;
2006-04-20 07:39:09 +04:00
}
2006-04-20 07:37:29 +04:00
* aStatus = 0 ;
2006-04-20 07:36:50 +04:00
return NS_OK ;
}
2006-04-20 07:38:50 +04:00
/* readonly attribute AUTF8String statusText; */
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2006-04-20 07:38:50 +04:00
nsXMLHttpRequest : : GetStatusText ( nsACString & aStatusText )
2006-04-20 07:36:50 +04:00
{
2006-04-20 07:38:52 +04:00
nsCOMPtr < nsIHttpChannel > httpChannel = GetCurrentHttpChannel ( ) ;
2006-04-20 07:37:29 +04:00
2006-04-20 07:38:50 +04:00
aStatusText . Truncate ( ) ;
nsresult rv = NS_OK ;
2006-04-20 07:37:53 +04:00
2006-04-20 07:37:29 +04:00
if ( httpChannel ) {
2006-04-20 07:38:50 +04:00
rv = httpChannel - > GetResponseStatusText ( aStatusText ) ;
2006-04-20 07:36:50 +04:00
}
2006-04-20 07:38:50 +04:00
return rv ;
2006-04-20 07:36:50 +04:00
}
/* void abort (); */
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2006-04-20 07:36:50 +04:00
nsXMLHttpRequest : : Abort ( )
{
2006-04-20 07:37:07 +04:00
if ( mReadRequest ) {
2006-04-20 07:37:51 +04:00
mReadRequest - > Cancel ( NS_BINDING_ABORTED ) ;
}
if ( mChannel ) {
mChannel - > Cancel ( NS_BINDING_ABORTED ) ;
2006-04-20 07:36:50 +04:00
}
2006-04-20 07:38:26 +04:00
mDocument = nsnull ;
mState | = XML_HTTP_REQUEST_ABORTED ;
2006-04-20 07:39:23 +04:00
ChangeState ( XML_HTTP_REQUEST_COMPLETED , PR_TRUE , PR_TRUE ) ;
2006-04-20 07:38:26 +04:00
2006-11-28 16:56:40 +03:00
// The ChangeState call above calls onreadystatechange handlers which
// if they load a new url will cause nsXMLHttpRequest::OpenRequest to clear
// the abort state bit. If this occurs we're not uninitialized (bug 361773).
if ( mState & XML_HTTP_REQUEST_ABORTED ) {
ChangeState ( XML_HTTP_REQUEST_UNINITIALIZED , PR_FALSE ) ; // IE seems to do it
}
2006-04-20 07:38:48 +04:00
2006-04-20 07:36:50 +04:00
return NS_OK ;
}
/* string getAllResponseHeaders (); */
2006-04-20 07:38:52 +04:00
NS_IMETHODIMP
2006-04-20 07:36:50 +04:00
nsXMLHttpRequest : : GetAllResponseHeaders ( char * * _retval )
{
NS_ENSURE_ARG_POINTER ( _retval ) ;
2006-04-20 07:36:55 +04:00
* _retval = nsnull ;
2006-04-20 07:38:52 +04:00
nsCOMPtr < nsIHttpChannel > httpChannel = GetCurrentHttpChannel ( ) ;
2006-04-20 07:37:29 +04:00
if ( httpChannel ) {
2006-04-20 07:37:18 +04:00
nsHeaderVisitor * visitor = nsnull ;
NS_NEWXPCOM ( visitor , nsHeaderVisitor ) ;
if ( ! visitor )
return NS_ERROR_OUT_OF_MEMORY ;
NS_ADDREF ( visitor ) ;
2006-04-20 07:36:50 +04:00
2006-04-20 07:37:29 +04:00
nsresult rv = httpChannel - > VisitResponseHeaders ( visitor ) ;
2006-04-20 07:37:18 +04:00
if ( NS_SUCCEEDED ( rv ) )
* _retval = ToNewCString ( visitor - > Headers ( ) ) ;
NS_RELEASE ( visitor ) ;
return rv ;
2006-04-20 07:36:50 +04:00
}
2006-04-20 07:39:09 +04:00
2006-04-20 07:36:50 +04:00
return NS_OK ;
}
2006-04-20 07:38:50 +04:00
/* ACString getResponseHeader (in AUTF8String header); */
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2006-04-20 07:38:50 +04:00
nsXMLHttpRequest : : GetResponseHeader ( const nsACString & header ,
nsACString & _retval )
2006-04-20 07:36:50 +04:00
{
2006-04-20 07:38:50 +04:00
nsresult rv = NS_OK ;
_retval . Truncate ( ) ;
2006-04-20 07:36:50 +04:00
2006-04-20 07:38:52 +04:00
nsCOMPtr < nsIHttpChannel > httpChannel = GetCurrentHttpChannel ( ) ;
2006-04-20 07:37:53 +04:00
if ( httpChannel ) {
2006-04-20 07:38:50 +04:00
rv = httpChannel - > GetResponseHeader ( header , _retval ) ;
2006-04-20 07:37:53 +04:00
}
2006-04-20 07:38:50 +04:00
2006-04-20 07:39:27 +04:00
if ( rv = = NS_ERROR_NOT_AVAILABLE ) {
// Means no header
2006-04-20 07:39:28 +04:00
_retval . SetIsVoid ( PR_TRUE ) ;
2006-04-20 07:39:27 +04:00
rv = NS_OK ;
}
2006-04-20 07:38:50 +04:00
return rv ;
2006-04-20 07:36:50 +04:00
}
2006-04-20 07:39:09 +04:00
nsresult
2006-04-20 07:38:10 +04:00
nsXMLHttpRequest : : GetLoadGroup ( nsILoadGroup * * aLoadGroup )
{
NS_ENSURE_ARG_POINTER ( aLoadGroup ) ;
* aLoadGroup = nsnull ;
if ( ! mScriptContext ) {
2006-04-20 07:38:45 +04:00
mScriptContext = GetCurrentContext ( ) ;
2006-04-20 07:38:10 +04:00
}
2006-04-20 07:38:36 +04:00
nsCOMPtr < nsIDocument > doc = GetDocumentFromScriptContext ( mScriptContext ) ;
if ( doc ) {
2006-04-20 07:38:41 +04:00
* aLoadGroup = doc - > GetDocumentLoadGroup ( ) . get ( ) ; // already_AddRefed
2006-04-20 07:38:10 +04:00
}
return NS_OK ;
}
2006-04-20 07:38:50 +04:00
nsIURI *
nsXMLHttpRequest : : GetBaseURI ( )
2006-04-20 07:38:20 +04:00
{
if ( ! mScriptContext ) {
2006-04-20 07:38:45 +04:00
mScriptContext = GetCurrentContext ( ) ;
2006-04-20 07:38:20 +04:00
if ( ! mScriptContext ) {
2006-04-20 07:38:50 +04:00
return nsnull ;
2006-04-20 07:38:20 +04:00
}
}
2006-04-20 07:38:36 +04:00
nsCOMPtr < nsIDocument > doc = GetDocumentFromScriptContext ( mScriptContext ) ;
2006-04-20 07:38:50 +04:00
if ( ! doc ) {
2006-04-20 07:38:51 +04:00
return nsnull ;
2006-04-20 07:38:20 +04:00
}
2006-04-20 07:38:50 +04:00
return doc - > GetBaseURI ( ) ;
2006-04-20 07:38:20 +04:00
}
2006-04-20 07:38:48 +04:00
nsresult
2006-05-05 21:01:53 +04:00
nsXMLHttpRequest : : CreateEvent ( nsEvent * aEvent , const nsAString & aType ,
nsIDOMEvent * * aDOMEvent )
2006-04-20 07:38:48 +04:00
{
2006-05-05 21:01:53 +04:00
nsresult rv = nsEventDispatcher : : CreateEvent ( nsnull , aEvent ,
NS_LITERAL_STRING ( " HTMLEvents " ) ,
aDOMEvent ) ;
2006-04-20 07:38:48 +04:00
if ( NS_FAILED ( rv ) ) {
return rv ;
}
nsCOMPtr < nsIPrivateDOMEvent > privevent ( do_QueryInterface ( * aDOMEvent ) ) ;
if ( ! privevent ) {
NS_IF_RELEASE ( * aDOMEvent ) ;
return NS_ERROR_FAILURE ;
}
2006-05-05 21:01:53 +04:00
if ( ! aType . IsEmpty ( ) ) {
( * aDOMEvent ) - > InitEvent ( aType , PR_FALSE , PR_FALSE ) ;
}
2006-04-20 07:38:48 +04:00
privevent - > SetTarget ( this ) ;
privevent - > SetCurrentTarget ( this ) ;
privevent - > SetOriginalTarget ( this ) ;
2006-05-05 21:01:53 +04:00
// We assume anyone who managed to call CreateEvent is trusted
privevent - > SetTrusted ( PR_TRUE ) ;
2006-04-20 07:39:31 +04:00
2006-04-20 07:38:48 +04:00
return NS_OK ;
}
void
2006-11-23 02:18:16 +03:00
nsXMLHttpRequest : : CopyEventListeners ( ListenerHolder & aListener ,
const nsTArray < ListenerHolder * > & aListenerArray ,
2006-05-26 05:00:21 +04:00
nsCOMArray < nsIDOMEventListener > & aCopy )
{
NS_PRECONDITION ( aCopy . Count ( ) = = 0 , " aCopy should start off empty " ) ;
2006-11-23 02:18:16 +03:00
nsCOMPtr < nsIDOMEventListener > listener = aListener . Get ( ) ;
if ( listener )
aCopy . AppendObject ( listener ) ;
2006-05-26 05:00:21 +04:00
2006-11-23 02:18:16 +03:00
PRUint32 count = aListenerArray . Length ( ) ;
for ( PRUint32 i = 0 ; i < count ; + + i )
aCopy . AppendObject ( nsCOMPtr < nsIDOMEventListener > ( aListenerArray [ i ] - > Get ( ) ) ) ;
2006-05-26 05:00:21 +04:00
}
void
nsXMLHttpRequest : : NotifyEventListeners ( const nsCOMArray < nsIDOMEventListener > & aListeners ,
2006-04-20 07:39:10 +04:00
nsIDOMEvent * aEvent )
2006-04-20 07:38:48 +04:00
{
2006-05-05 21:01:53 +04:00
// XXXbz wouldn't it be easier to just have an actual nsEventListenerManager
// to work with or something? I feel like we're duplicating code here...
2006-04-20 07:38:48 +04:00
if ( ! aEvent )
return ;
nsCOMPtr < nsIJSContextStack > stack ;
JSContext * cx = nsnull ;
if ( mScriptContext ) {
stack = do_GetService ( " @mozilla.org/js/xpc/ContextStack;1 " ) ;
if ( stack ) {
cx = ( JSContext * ) mScriptContext - > GetNativeContext ( ) ;
if ( cx ) {
stack - > Push ( cx ) ;
}
}
}
2006-05-05 21:01:53 +04:00
PRInt32 count = aListeners . Count ( ) ;
for ( PRInt32 index = 0 ; index < count ; + + index ) {
nsIDOMEventListener * listener = aListeners [ index ] ;
if ( listener ) {
listener - > HandleEvent ( aEvent ) ;
2006-04-20 07:38:48 +04:00
}
}
if ( cx ) {
stack - > Pop ( & cx ) ;
}
}
2006-04-20 07:38:26 +04:00
void
nsXMLHttpRequest : : ClearEventListeners ( )
{
2006-05-26 05:00:21 +04:00
if ( mState & XML_HTTP_REQUEST_ROOTED ) {
2006-11-23 02:18:16 +03:00
nsDOMClassInfo : : UnsetExternallyReferenced ( this ) ;
2006-05-26 05:00:21 +04:00
mState & = ~ XML_HTTP_REQUEST_ROOTED ;
}
2006-11-23 02:18:16 +03:00
// This isn't *really* needed anymore now that we use
// nsMarkedJSFunctionHolder, but we may as well keep it for safety
// (against leaks) and compatibility, and also for the code to clear
// the first listener arrays (called from the destructor).
PRUint32 i , i_end ;
# define CLEAR_ARRAY(member_) \
for ( i = 0 , i_end = ( member_ ) . Length ( ) ; i < i_end ; + + i ) \
delete ( member_ ) [ i ] ; \
( member_ ) . Clear ( ) ;
CLEAR_ARRAY ( mLoadEventListeners )
CLEAR_ARRAY ( mErrorEventListeners )
CLEAR_ARRAY ( mProgressEventListeners )
CLEAR_ARRAY ( mUploadProgressEventListeners )
CLEAR_ARRAY ( mReadystatechangeEventListeners )
2006-05-26 05:00:21 +04:00
2006-11-23 02:18:16 +03:00
# undef CLEAR_ARRAY
2006-05-26 05:00:21 +04:00
2006-11-23 02:18:16 +03:00
mOnLoadListener . Set ( nsnull , this ) ;
mOnErrorListener . Set ( nsnull , this ) ;
mOnProgressListener . Set ( nsnull , this ) ;
mOnUploadProgressListener . Set ( nsnull , this ) ;
mOnReadystatechangeListener . Set ( nsnull , this ) ;
2006-04-20 07:38:26 +04:00
}
2006-04-20 07:38:52 +04:00
already_AddRefed < nsIHttpChannel >
nsXMLHttpRequest : : GetCurrentHttpChannel ( )
{
nsIHttpChannel * httpChannel = nsnull ;
if ( mReadRequest ) {
CallQueryInterface ( mReadRequest , & httpChannel ) ;
}
if ( ! httpChannel & & mChannel ) {
CallQueryInterface ( mChannel , & httpChannel ) ;
}
return httpChannel ;
}
2006-04-20 07:38:50 +04:00
/* noscript void openRequest (in AUTF8String method, in AUTF8String url, in boolean async, in AString user, in AString password); */
NS_IMETHODIMP
2006-04-20 07:39:09 +04:00
nsXMLHttpRequest : : OpenRequest ( const nsACString & method ,
const nsACString & url ,
PRBool async ,
const nsAString & user ,
2006-04-20 07:38:50 +04:00
const nsAString & password )
2006-04-20 07:36:50 +04:00
{
2006-04-20 07:38:50 +04:00
NS_ENSURE_ARG ( ! method . IsEmpty ( ) ) ;
NS_ENSURE_ARG ( ! url . IsEmpty ( ) ) ;
2006-04-20 07:39:09 +04:00
2006-04-20 07:39:38 +04:00
// Disallow HTTP/1.1 TRACE method (see bug 302489).
if ( method . LowerCaseEqualsASCII ( " trace " ) ) {
return NS_ERROR_INVALID_ARG ;
}
2006-04-20 07:36:50 +04:00
nsresult rv ;
2006-04-20 07:39:09 +04:00
nsCOMPtr < nsIURI > uri ;
2006-04-20 07:36:50 +04:00
PRBool authp = PR_FALSE ;
2006-04-20 07:38:26 +04:00
if ( mState & XML_HTTP_REQUEST_ABORTED ) {
2006-04-20 07:38:52 +04:00
// Something caused this request to abort (e.g the current request
// was caceled, channels closed etc), most likely the abort()
// function was called by script. Unset our aborted state, and
// proceed as normal
mState & = ~ XML_HTTP_REQUEST_ABORTED ;
2006-04-20 07:39:09 +04:00
} else if ( mState & ( XML_HTTP_REQUEST_OPENED |
2006-04-20 07:38:26 +04:00
XML_HTTP_REQUEST_LOADED |
XML_HTTP_REQUEST_INTERACTIVE |
XML_HTTP_REQUEST_SENT |
XML_HTTP_REQUEST_STOPPED ) ) {
// IE aborts as well
Abort ( ) ;
2006-04-20 07:38:52 +04:00
2006-04-20 07:38:26 +04:00
// XXX We should probably send a warning to the JS console
// that load was aborted and event listeners were cleared
// since this looks like a situation that could happen
// by accident and you could spend a lot of time wondering
// why things didn't work.
return NS_OK ;
2006-04-20 07:36:54 +04:00
}
2006-04-20 07:38:26 +04:00
if ( async ) {
mState | = XML_HTTP_REQUEST_ASYNC ;
} else {
mState & = ~ XML_HTTP_REQUEST_ASYNC ;
}
2006-04-20 07:36:50 +04:00
2006-04-20 07:38:50 +04:00
rv = NS_NewURI ( getter_AddRefs ( uri ) , url , nsnull , GetBaseURI ( ) ) ;
2006-04-20 07:36:50 +04:00
if ( NS_FAILED ( rv ) ) return rv ;
2006-04-20 07:38:50 +04:00
if ( ! user . IsEmpty ( ) ) {
2006-04-20 07:37:52 +04:00
nsCAutoString userpass ;
2006-04-20 07:38:50 +04:00
CopyUTF16toUTF8 ( user , userpass ) ;
if ( ! password . IsEmpty ( ) ) {
userpass . Append ( ' : ' ) ;
AppendUTF16toUTF8 ( password , userpass ) ;
2006-04-20 07:36:50 +04:00
}
2006-04-20 07:37:52 +04:00
uri - > SetUserPass ( userpass ) ;
2006-04-20 07:36:50 +04:00
authp = PR_TRUE ;
}
2006-04-20 07:38:10 +04:00
// When we are called from JS we can find the load group for the page,
// and add ourselves to it. This way any pending requests
// will be automatically aborted if the user leaves the page.
nsCOMPtr < nsILoadGroup > loadGroup ;
GetLoadGroup ( getter_AddRefs ( loadGroup ) ) ;
2006-04-20 07:39:45 +04:00
// nsIRequest::LOAD_BACKGROUND prevents throbber from becoming active, which
// in turn keeps STOP button from becoming active. If the consumer passed in
// a progress event handler we must load with nsIRequest::LOAD_NORMAL or
// necko won't generate any progress notifications
nsLoadFlags loadFlags ;
2006-11-23 02:18:16 +03:00
if ( nsCOMPtr < nsIDOMEventListener > ( mOnProgressListener . Get ( ) ) | |
nsCOMPtr < nsIDOMEventListener > ( mOnUploadProgressListener . Get ( ) ) | |
mProgressEventListeners . Length ( ) ! = 0 | |
mUploadProgressEventListeners . Length ( ) ! = 0 ) {
2006-04-20 07:39:45 +04:00
loadFlags = nsIRequest : : LOAD_NORMAL ;
} else {
loadFlags = nsIRequest : : LOAD_BACKGROUND ;
}
rv = NS_NewChannel ( getter_AddRefs ( mChannel ) , uri , nsnull , loadGroup , nsnull ,
loadFlags ) ;
2006-04-20 07:36:50 +04:00
if ( NS_FAILED ( rv ) ) return rv ;
2006-04-20 07:39:09 +04:00
2006-04-20 07:37:18 +04:00
//mChannel->SetAuthTriedWithPrehost(authp);
2006-04-20 07:36:51 +04:00
2006-04-20 07:37:29 +04:00
nsCOMPtr < nsIHttpChannel > httpChannel ( do_QueryInterface ( mChannel ) ) ;
if ( httpChannel ) {
2006-04-20 07:38:50 +04:00
rv = httpChannel - > SetRequestMethod ( method ) ;
2006-04-20 07:37:29 +04:00
}
2006-04-20 07:36:54 +04:00
2006-04-20 07:37:31 +04:00
ChangeState ( XML_HTTP_REQUEST_OPENED ) ;
2006-04-20 07:36:54 +04:00
2006-04-20 07:36:50 +04:00
return rv ;
}
2006-04-20 07:38:50 +04:00
/* void open (in AUTF8String method, in AUTF8String url); */
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2006-04-20 07:38:50 +04:00
nsXMLHttpRequest : : Open ( const nsACString & method , const nsACString & url )
2006-04-20 07:36:50 +04:00
{
2006-09-20 21:21:11 +04:00
nsresult rv = NS_OK ;
2006-04-20 07:36:50 +04:00
PRBool async = PR_TRUE ;
2006-04-20 07:38:50 +04:00
nsAutoString user , password ;
2006-04-20 07:36:50 +04:00
nsCOMPtr < nsIXPCNativeCallContext > cc ;
2006-06-16 00:30:44 +04:00
nsIXPConnect * xpc = nsContentUtils : : XPConnect ( ) ;
if ( xpc ) {
2006-04-20 07:36:50 +04:00
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 ;
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2006-04-20 07:37:17 +04:00
2006-04-20 07:36:50 +04:00
JSContext * cx ;
rv = cc - > GetJSContext ( & cx ) ;
if ( NS_FAILED ( rv ) ) return NS_ERROR_FAILURE ;
2006-04-20 07:37:21 +04:00
nsCOMPtr < nsIURI > targetURI ;
2006-04-20 07:38:50 +04:00
rv = NS_NewURI ( getter_AddRefs ( targetURI ) , url , nsnull , GetBaseURI ( ) ) ;
2006-04-20 07:37:21 +04:00
if ( NS_FAILED ( rv ) ) return NS_ERROR_FAILURE ;
2006-06-16 00:30:44 +04:00
nsIScriptSecurityManager * secMan = nsContentUtils : : GetSecurityManager ( ) ;
if ( ! secMan ) {
return NS_ERROR_FAILURE ;
}
2006-04-20 07:38:20 +04:00
2006-04-20 07:37:21 +04:00
rv = secMan - > CheckConnect ( cx , targetURI , " XMLHttpRequest " , " open " ) ;
if ( NS_FAILED ( rv ) )
{
2006-04-20 07:37:30 +04:00
// Security check failed.
2006-04-20 07:37:21 +04:00
return NS_OK ;
}
2006-04-20 07:38:01 +04:00
// Find out if UniversalBrowserRead privileges are enabled
// we will need this in case of a redirect
2006-04-20 07:38:10 +04:00
PRBool crossSiteAccessEnabled ;
2006-04-20 07:38:01 +04:00
rv = secMan - > IsCapabilityEnabled ( " UniversalBrowserRead " ,
2006-04-20 07:38:10 +04:00
& crossSiteAccessEnabled ) ;
2006-04-20 07:38:01 +04:00
if ( NS_FAILED ( rv ) ) return rv ;
2006-04-20 07:38:26 +04:00
if ( crossSiteAccessEnabled ) {
mState | = XML_HTTP_REQUEST_XSITEENABLED ;
} else {
mState & = ~ XML_HTTP_REQUEST_XSITEENABLED ;
}
2006-04-20 07:38:01 +04:00
2006-04-20 07:36:50 +04:00
if ( argc > 2 ) {
2006-06-13 02:39:55 +04:00
JSAutoRequest ar ( cx ) ;
2006-04-20 07:36:52 +04:00
JSBool asyncBool ;
2006-04-20 07:38:50 +04:00
: : JS_ValueToBoolean ( cx , argv [ 2 ] , & asyncBool ) ;
2006-04-20 07:36:52 +04:00
async = ( PRBool ) asyncBool ;
2006-04-20 07:36:50 +04:00
2006-06-07 05:42:22 +04:00
if ( argc > 3 & & ! JSVAL_IS_NULL ( argv [ 3 ] ) & & ! JSVAL_IS_VOID ( argv [ 3 ] ) ) {
2006-04-20 07:38:50 +04:00
JSString * userStr = : : JS_ValueToString ( cx , argv [ 3 ] ) ;
2006-04-20 07:36:50 +04:00
if ( userStr ) {
2006-04-20 07:38:51 +04:00
user . Assign ( NS_REINTERPRET_CAST ( PRUnichar * ,
: : JS_GetStringChars ( userStr ) ) ,
2006-04-20 07:38:50 +04:00
: : JS_GetStringLength ( userStr ) ) ;
2006-04-20 07:36:50 +04:00
}
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2006-04-20 07:37:17 +04:00
2006-06-07 05:42:22 +04:00
if ( argc > 4 & & ! JSVAL_IS_NULL ( argv [ 4 ] ) & & ! JSVAL_IS_VOID ( argv [ 4 ] ) ) {
2006-04-20 07:38:51 +04:00
JSString * passwdStr = JS_ValueToString ( cx , argv [ 4 ] ) ;
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2006-04-20 07:37:17 +04:00
2006-04-20 07:38:51 +04:00
if ( passwdStr ) {
password . Assign ( NS_REINTERPRET_CAST ( PRUnichar * ,
: : JS_GetStringChars ( passwdStr ) ) ,
: : JS_GetStringLength ( passwdStr ) ) ;
2006-04-20 07:36:50 +04:00
}
}
}
}
}
return OpenRequest ( method , url , async , user , password ) ;
}
2006-04-20 07:37:08 +04:00
/*
2006-04-20 07:37:22 +04:00
* " Copy " from a stream .
2006-04-20 07:37:08 +04:00
*/
NS_METHOD
nsXMLHttpRequest : : StreamReaderFunc ( nsIInputStream * in ,
2006-04-20 07:38:50 +04:00
void * closure ,
const char * fromRawSegment ,
PRUint32 toOffset ,
PRUint32 count ,
PRUint32 * writeCount )
2006-04-20 07:37:08 +04:00
{
nsXMLHttpRequest * xmlHttpRequest = NS_STATIC_CAST ( nsXMLHttpRequest * , closure ) ;
2006-04-20 07:37:22 +04:00
if ( ! xmlHttpRequest | | ! writeCount ) {
NS_WARNING ( " XMLHttpRequest cannot read from stream: no closure or writeCount " ) ;
2006-04-20 07:37:08 +04:00
return NS_ERROR_FAILURE ;
}
// Copy for our own use
2006-04-20 07:37:22 +04:00
xmlHttpRequest - > mResponseBody . Append ( fromRawSegment , count ) ;
2006-04-20 07:37:08 +04:00
2006-04-20 07:37:59 +04:00
nsresult rv = NS_OK ;
2006-04-20 07:37:22 +04:00
2006-04-20 07:38:26 +04:00
if ( xmlHttpRequest - > mState & XML_HTTP_REQUEST_PARSEBODY ) {
2006-04-20 07:37:59 +04:00
// Give the same data to the parser.
2006-04-20 07:37:22 +04:00
2006-04-20 07:37:59 +04:00
// We need to wrap the data in a new lightweight stream and pass that
// to the parser, because calling ReadSegments() recursively on the same
// stream is not supported.
2006-04-20 07:38:34 +04:00
nsCOMPtr < nsIInputStream > copyStream ;
rv = NS_NewByteInputStream ( getter_AddRefs ( copyStream ) , fromRawSegment , count ) ;
2006-04-20 07:37:22 +04:00
2006-04-20 07:37:59 +04:00
if ( NS_SUCCEEDED ( rv ) ) {
2006-04-20 07:38:34 +04:00
NS_ASSERTION ( copyStream , " NS_NewByteInputStream lied " ) ;
2006-04-20 07:39:41 +04:00
nsresult parsingResult = xmlHttpRequest - > mXMLParserStreamListener
- > OnDataAvailable ( xmlHttpRequest - > mReadRequest ,
xmlHttpRequest - > mContext ,
copyStream , toOffset , count ) ;
// No use to continue parsing if we failed here, but we
// should still finish reading the stream
if ( NS_FAILED ( parsingResult ) ) {
xmlHttpRequest - > mState & = ~ XML_HTTP_REQUEST_PARSEBODY ;
}
2006-04-20 07:37:22 +04:00
}
}
2006-04-20 07:37:08 +04:00
2006-04-20 07:37:31 +04:00
xmlHttpRequest - > ChangeState ( XML_HTTP_REQUEST_INTERACTIVE ) ;
2006-04-20 07:37:22 +04:00
if ( NS_SUCCEEDED ( rv ) ) {
* writeCount = count ;
} else {
* writeCount = 0 ;
}
2006-04-20 07:37:08 +04:00
return rv ;
}
/* void onDataAvailable (in nsIRequest request, in nsISupports ctxt, in nsIInputStream inStr, in unsigned long sourceOffset, in unsigned long count); */
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2006-04-20 07:37:08 +04:00
nsXMLHttpRequest : : OnDataAvailable ( nsIRequest * request , nsISupports * ctxt , nsIInputStream * inStr , PRUint32 sourceOffset , PRUint32 count )
{
2006-04-20 07:37:22 +04:00
NS_ENSURE_ARG_POINTER ( inStr ) ;
2006-04-20 07:37:08 +04:00
NS_ABORT_IF_FALSE ( mContext . get ( ) = = ctxt , " start context different from OnDataAvailable context " ) ;
PRUint32 totalRead ;
2006-04-20 07:37:36 +04:00
return inStr - > ReadSegments ( nsXMLHttpRequest : : StreamReaderFunc , ( void * ) this , count , & totalRead ) ;
2006-04-20 07:37:08 +04:00
}
/* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2006-04-20 07:37:08 +04:00
nsXMLHttpRequest : : OnStartRequest ( nsIRequest * request , nsISupports * ctxt )
{
2006-04-20 07:38:48 +04:00
// Don't do anything if we have been aborted
if ( mState & XML_HTTP_REQUEST_UNINITIALIZED )
return NS_OK ;
2006-04-20 07:38:52 +04:00
if ( mState & XML_HTTP_REQUEST_ABORTED ) {
NS_ERROR ( " Ugh, still getting data on an aborted XMLHttpRequest! " ) ;
return NS_ERROR_UNEXPECTED ;
}
nsCOMPtr < nsIChannel > channel ( do_QueryInterface ( request ) ) ;
NS_ENSURE_TRUE ( channel , NS_ERROR_UNEXPECTED ) ;
2006-04-20 07:37:08 +04:00
mReadRequest = request ;
mContext = ctxt ;
2006-04-20 07:38:26 +04:00
mState | = XML_HTTP_REQUEST_PARSEBODY ;
2006-04-20 07:37:31 +04:00
ChangeState ( XML_HTTP_REQUEST_LOADED ) ;
2006-04-20 07:38:37 +04:00
2006-06-16 00:30:44 +04:00
// XXXbz this is probably all wrong when not called from JS... and possibly
// even then! Fixing that requires giving XMLHttpRequest some principals
// when inited. Until then, cases when we don't actually parse the
// document will give our mDocument he wrong principal. I'm just not sure
// how wrong it can get... Shouldn't be too bad as long as mScriptContext
// is sane, I guess.
nsCOMPtr < nsIDocument > doc = GetDocumentFromScriptContext ( mScriptContext ) ;
nsIURI * uri = GetBaseURI ( ) ;
nsIPrincipal * principal = nsnull ;
if ( doc ) {
principal = doc - > NodePrincipal ( ) ;
2006-04-20 07:38:52 +04:00
}
2006-05-05 21:01:53 +04:00
// Create an empty document from it
2006-04-20 07:38:52 +04:00
const nsAString & emptyStr = EmptyString ( ) ;
2006-06-16 00:30:44 +04:00
nsresult rv = nsContentUtils : : CreateDocument ( emptyStr , emptyStr , nsnull , uri ,
uri , principal ,
getter_AddRefs ( mDocument ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2006-04-20 07:38:52 +04:00
// Reset responseBody
mResponseBody . Truncate ( ) ;
// Register as a load listener on the document
nsCOMPtr < nsIDOMEventReceiver > target ( do_QueryInterface ( mDocument ) ) ;
if ( target ) {
nsWeakPtr requestWeak =
do_GetWeakReference ( NS_STATIC_CAST ( nsIXMLHttpRequest * , this ) ) ;
nsCOMPtr < nsIDOMEventListener > proxy = new nsLoadListenerProxy ( requestWeak ) ;
if ( ! proxy ) return NS_ERROR_OUT_OF_MEMORY ;
// This will addref the proxy
2006-04-20 07:39:09 +04:00
rv = target - > AddEventListenerByIID ( NS_STATIC_CAST ( nsIDOMEventListener * ,
proxy ) ,
2006-04-20 07:38:52 +04:00
NS_GET_IID ( nsIDOMLoadListener ) ) ;
if ( NS_FAILED ( rv ) ) return NS_ERROR_FAILURE ;
2006-04-20 07:38:37 +04:00
}
2006-04-20 07:39:41 +04:00
nsresult status ;
request - > GetStatus ( & status ) ;
2006-04-20 07:39:44 +04:00
PRBool parseBody = PR_TRUE ;
nsCOMPtr < nsIHttpChannel > httpChannel ( do_QueryInterface ( mChannel ) ) ;
if ( httpChannel ) {
nsCAutoString method ;
httpChannel - > GetRequestMethod ( method ) ;
parseBody = ! method . EqualsLiteral ( " HEAD " ) ;
}
if ( parseBody & & NS_SUCCEEDED ( status ) ) {
2006-04-20 07:39:41 +04:00
if ( ! mOverrideMimeType . IsEmpty ( ) ) {
channel - > SetContentType ( mOverrideMimeType ) ;
}
// We can gain a huge performance win by not even trying to
// parse non-XML data. This also protects us from the situation
// where we have an XML document and sink, but HTML (or other)
// parser, which can produce unreliable results.
2006-04-20 07:37:59 +04:00
nsCAutoString type ;
2006-04-20 07:38:52 +04:00
channel - > GetContentType ( type ) ;
2006-04-20 07:39:24 +04:00
if ( type . Find ( " xml " ) = = kNotFound ) {
2006-04-20 07:38:26 +04:00
mState & = ~ XML_HTTP_REQUEST_PARSEBODY ;
2006-04-20 07:37:59 +04:00
}
} else {
2006-04-20 07:39:41 +04:00
// The request failed, so we shouldn't be parsing anyway
mState & = ~ XML_HTTP_REQUEST_PARSEBODY ;
2006-04-20 07:37:48 +04:00
}
2006-04-20 07:39:09 +04:00
2006-04-20 07:38:37 +04:00
if ( mState & XML_HTTP_REQUEST_PARSEBODY ) {
nsCOMPtr < nsIStreamListener > listener ;
nsCOMPtr < nsILoadGroup > loadGroup ;
2006-04-20 07:38:52 +04:00
channel - > GetLoadGroup ( getter_AddRefs ( loadGroup ) ) ;
2006-04-20 07:38:37 +04:00
nsCOMPtr < nsIDocument > document ( do_QueryInterface ( mDocument ) ) ;
if ( ! document ) {
return NS_ERROR_FAILURE ;
}
2006-04-20 07:37:59 +04:00
2006-04-20 07:38:52 +04:00
rv = document - > StartDocumentLoad ( kLoadAsData , channel , loadGroup , nsnull ,
getter_AddRefs ( listener ) , PR_TRUE ) ;
2006-04-20 07:38:37 +04:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
mXMLParserStreamListener = listener ;
return mXMLParserStreamListener - > OnStartRequest ( request , ctxt ) ;
}
2006-04-20 07:39:09 +04:00
2006-04-20 07:38:37 +04:00
return NS_OK ;
2006-04-20 07:37:08 +04:00
}
/* void onStopRequest (in nsIRequest request, in nsISupports ctxt, in nsresult status, in wstring statusArg); */
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2006-04-20 07:37:13 +04:00
nsXMLHttpRequest : : OnStopRequest ( nsIRequest * request , nsISupports * ctxt , nsresult status )
2006-04-20 07:37:08 +04:00
{
2006-04-20 07:38:48 +04:00
// Don't do anything if we have been aborted
if ( mState & XML_HTTP_REQUEST_UNINITIALIZED )
return NS_OK ;
2006-04-20 07:38:37 +04:00
nsresult rv = NS_OK ;
nsCOMPtr < nsIParser > parser ;
2006-04-20 07:38:52 +04:00
// If we're loading a multipart stream of XML documents, we'll get
// an OnStopRequest() for the last part in the stream, and then
// another one for the end of the initiating
// "multipart/x-mixed-replace" stream too. So we must check that we
// still have an xml parser stream listener before accessing it
// here.
// Is this good enough here?
2006-04-20 07:39:09 +04:00
if ( mState & XML_HTTP_REQUEST_PARSEBODY & & mXMLParserStreamListener ) {
2006-04-20 07:38:37 +04:00
parser = do_QueryInterface ( mXMLParserStreamListener ) ;
NS_ABORT_IF_FALSE ( parser , " stream listener was expected to be a parser " ) ;
rv = mXMLParserStreamListener - > OnStopRequest ( request , ctxt , status ) ;
}
2006-04-20 07:37:35 +04:00
2006-04-20 07:37:08 +04:00
mXMLParserStreamListener = nsnull ;
mReadRequest = nsnull ;
mContext = nsnull ;
2006-04-20 07:38:52 +04:00
nsCOMPtr < nsIChannel > channel ( do_QueryInterface ( request ) ) ;
NS_ENSURE_TRUE ( channel , NS_ERROR_UNEXPECTED ) ;
channel - > SetNotificationCallbacks ( nsnull ) ;
2006-04-20 07:39:34 +04:00
mNotificationCallbacks = nsnull ;
mChannelEventSink = nsnull ;
mProgressEventSink = nsnull ;
2006-04-20 07:37:31 +04:00
2006-04-20 07:38:10 +04:00
if ( NS_FAILED ( status ) ) {
2006-04-20 07:38:52 +04:00
// This can happen if the server is unreachable. Other possible
// reasons are that the user leaves the page or hits the ESC key.
2006-04-20 07:38:48 +04:00
Error ( nsnull ) ;
2006-04-20 07:38:52 +04:00
// By nulling out channel here we make it so that Send() can test
// for that and throw. Also calling the various status
// methods/members will not throw.
2006-04-20 07:38:23 +04:00
// This matches what IE does.
mChannel = nsnull ;
2006-04-20 07:38:37 +04:00
} else if ( ! parser | | parser - > IsParserEnabled ( ) ) {
// If we don't have a parser, we never attempted to parse the
// incoming data, and we can proceed to call RequestCompleted().
// Alternatively, if we do have a parser, its possible that we
// have given it some data and this caused it to block e.g. by a
// by a xml-stylesheet PI. In this case, we will have to wait till
// it gets enabled again and RequestCompleted() must be called
// later, when we get the load event from the document. If the
// parser is enabled, it is not blocked and we can still go ahead
// and call RequestCompleted() and expect everything to get
// cleaned up immediately.
2006-04-20 07:37:35 +04:00
RequestCompleted ( ) ;
} else {
2006-04-20 07:38:10 +04:00
ChangeState ( XML_HTTP_REQUEST_STOPPED , PR_FALSE ) ;
2006-04-20 07:37:35 +04:00
}
2006-04-20 07:37:31 +04:00
2006-04-20 07:38:52 +04:00
if ( mScriptContext ) {
// Force a GC since we could be loading a lot of documents
// (especially if streaming), and not doing anything that would
// normally trigger a GC.
mScriptContext - > GC ( ) ;
}
2006-04-20 07:38:26 +04:00
mState & = ~ XML_HTTP_REQUEST_SYNCLOOPING ;
2006-04-20 07:38:20 +04:00
2006-04-20 07:37:31 +04:00
return rv ;
}
2006-04-20 07:39:09 +04:00
nsresult
2006-04-20 07:37:31 +04:00
nsXMLHttpRequest : : RequestCompleted ( )
{
nsresult rv = NS_OK ;
2006-04-20 07:38:26 +04:00
mState & = ~ XML_HTTP_REQUEST_SYNCLOOPING ;
2006-04-20 07:38:20 +04:00
2006-04-20 07:37:34 +04:00
// If we're uninitialized at this point, we encountered an error
2006-04-20 07:37:35 +04:00
// earlier and listeners have already been notified. Also we do
// not want to do this if we already completed.
2006-04-20 07:38:26 +04:00
if ( mState & ( XML_HTTP_REQUEST_UNINITIALIZED |
XML_HTTP_REQUEST_COMPLETED ) ) {
2006-04-20 07:37:34 +04:00
return NS_OK ;
}
2006-05-26 05:00:21 +04:00
// Grab hold of the event listeners we will need before we possibly clear
// them.
nsCOMArray < nsIDOMEventListener > loadEventListeners ;
CopyEventListeners ( mOnLoadListener , mLoadEventListeners , loadEventListeners ) ;
2006-04-20 07:38:48 +04:00
// We need to create the event before nulling out mDocument
2006-08-31 23:33:01 +04:00
nsEvent evt ( PR_TRUE , NS_LOAD ) ;
2006-04-20 07:37:34 +04:00
nsCOMPtr < nsIDOMEvent > domevent ;
2006-05-26 05:00:21 +04:00
if ( loadEventListeners . Count ( ) ) {
2006-05-05 21:01:53 +04:00
rv = CreateEvent ( & evt , EmptyString ( ) , getter_AddRefs ( domevent ) ) ;
}
2006-04-20 07:37:31 +04:00
// We might have been sent non-XML data. If that was the case,
// we should null out the document member. The idea in this
// check here is that if there is no document element it is not
// an XML document. We might need a fancier check...
if ( mDocument ) {
nsCOMPtr < nsIDOMElement > root ;
mDocument - > GetDocumentElement ( getter_AddRefs ( root ) ) ;
if ( ! root ) {
mDocument = nsnull ;
}
}
2006-04-20 07:39:23 +04:00
// Clear listeners here unless we're multipart
ChangeState ( XML_HTTP_REQUEST_COMPLETED , PR_TRUE ,
! ( mState & XML_HTTP_REQUEST_MULTIPART ) ) ;
2006-05-05 21:01:53 +04:00
if ( NS_SUCCEEDED ( rv ) & & domevent ) {
2006-05-26 05:00:21 +04:00
NotifyEventListeners ( loadEventListeners , domevent ) ;
2006-05-05 21:01:53 +04:00
}
2006-04-20 07:38:52 +04:00
if ( mState & XML_HTTP_REQUEST_MULTIPART ) {
// We're a multipart request, so we're not done. Reset to opened.
ChangeState ( XML_HTTP_REQUEST_OPENED ) ;
}
2006-04-20 07:38:26 +04:00
2006-04-20 07:37:08 +04:00
return rv ;
}
2006-04-20 07:37:45 +04:00
/* void send (in nsIVariant aBody); */
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2006-04-20 07:37:45 +04:00
nsXMLHttpRequest : : Send ( nsIVariant * aBody )
2006-04-20 07:36:50 +04:00
{
nsresult rv ;
2006-04-20 07:38:48 +04:00
2006-04-20 07:37:08 +04:00
// Return error if we're already processing a request
2006-04-20 07:38:26 +04:00
if ( XML_HTTP_REQUEST_SENT & mState ) {
2006-04-20 07:36:54 +04:00
return NS_ERROR_FAILURE ;
}
2006-04-20 07:39:09 +04:00
2006-04-20 07:36:54 +04:00
// Make sure we've been opened
2006-04-20 07:38:26 +04:00
if ( ! mChannel | | ! ( XML_HTTP_REQUEST_OPENED & mState ) ) {
2006-04-20 07:36:50 +04:00
return NS_ERROR_NOT_INITIALIZED ;
}
2006-04-20 07:38:26 +04:00
// XXX We should probably send a warning to the JS console
// if there are no event listeners set and we are doing
// an asynchronous call.
2006-04-20 07:38:50 +04:00
// Ignore argument if method is GET, there is no point in trying to
// upload anything
2006-04-20 07:37:53 +04:00
nsCAutoString method ;
2006-04-20 07:37:29 +04:00
nsCOMPtr < nsIHttpChannel > httpChannel ( do_QueryInterface ( mChannel ) ) ;
if ( httpChannel ) {
2006-04-20 07:37:53 +04:00
httpChannel - > GetRequestMethod ( method ) ; // If GET, method name will be uppercase
2006-07-07 02:10:04 +04:00
nsCOMPtr < nsIDocument > doc =
do_QueryInterface ( nsContentUtils : : GetDocumentFromCaller ( ) ) ;
if ( doc ) {
nsIPrincipal * principal = doc - > NodePrincipal ( ) ;
if ( principal ) {
nsCOMPtr < nsIURI > codebase ;
principal - > GetURI ( getter_AddRefs ( codebase ) ) ;
httpChannel - > SetReferrer ( codebase ) ;
}
}
2006-04-20 07:37:29 +04:00
}
2006-04-20 07:37:22 +04:00
2006-04-20 07:39:11 +04:00
if ( aBody & & httpChannel & & ! method . EqualsLiteral ( " GET " ) ) {
2006-04-20 07:37:45 +04:00
nsXPIDLString serial ;
2006-04-20 07:37:22 +04:00
nsCOMPtr < nsIInputStream > postDataStream ;
2006-04-20 07:37:45 +04:00
PRUint16 dataType ;
rv = aBody - > GetDataType ( & dataType ) ;
2006-04-20 07:39:09 +04:00
if ( NS_FAILED ( rv ) )
2006-04-20 07:38:50 +04:00
return rv ;
2006-04-20 07:37:45 +04:00
2006-04-20 07:37:58 +04:00
switch ( dataType ) {
case nsIDataType : : VTYPE_INTERFACE :
case nsIDataType : : VTYPE_INTERFACE_IS :
{
nsCOMPtr < nsISupports > supports ;
nsID * iid ;
rv = aBody - > GetAsInterface ( & iid , getter_AddRefs ( supports ) ) ;
2006-04-20 07:39:09 +04:00
if ( NS_FAILED ( rv ) )
2006-04-20 07:38:50 +04:00
return rv ;
if ( iid )
2006-04-20 07:37:58 +04:00
nsMemory : : Free ( iid ) ;
// document?
nsCOMPtr < nsIDOMDocument > doc ( do_QueryInterface ( supports ) ) ;
if ( doc ) {
nsCOMPtr < nsIDOMSerializer > serializer ( do_CreateInstance ( NS_XMLSERIALIZER_CONTRACTID , & rv ) ) ;
2006-04-20 07:39:09 +04:00
if ( NS_FAILED ( rv ) ) return rv ;
2006-04-20 07:38:50 +04:00
2006-12-01 07:48:05 +03:00
// Serialize to a stream so that the encoding used will
// match the document's.
nsCOMPtr < nsIInputStream > input ;
nsCOMPtr < nsIOutputStream > output ;
rv = NS_NewPipe ( getter_AddRefs ( input ) , getter_AddRefs ( output ) ,
0 , PR_UINT32_MAX ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
// Empty string for encoding means to use document's current
// encoding.
rv = serializer - > SerializeToStream ( doc , output , EmptyCString ( ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
output - > Close ( ) ;
postDataStream = input ;
2006-04-20 07:37:45 +04:00
} else {
2006-04-20 07:38:05 +04:00
// nsISupportsString?
nsCOMPtr < nsISupportsString > wstr ( do_QueryInterface ( supports ) ) ;
2006-04-20 07:37:58 +04:00
if ( wstr ) {
2006-04-20 07:38:09 +04:00
wstr - > GetData ( serial ) ;
2006-04-20 07:37:58 +04:00
} else {
// stream?
nsCOMPtr < nsIInputStream > stream ( do_QueryInterface ( supports ) ) ;
if ( stream ) {
postDataStream = stream ;
}
2006-04-20 07:37:45 +04:00
}
}
}
2006-04-20 07:37:59 +04:00
break ;
2006-04-20 07:37:58 +04:00
case nsIDataType : : VTYPE_VOID :
case nsIDataType : : VTYPE_EMPTY :
// Makes us act as if !aBody, don't upload anything
break ;
case nsIDataType : : VTYPE_EMPTY_ARRAY :
case nsIDataType : : VTYPE_ARRAY :
// IE6 throws error here, so we do that as well
return NS_ERROR_INVALID_ARG ;
default :
2006-04-20 07:37:45 +04:00
// try variant string
2006-04-20 07:39:09 +04:00
rv = aBody - > GetAsWString ( getter_Copies ( serial ) ) ;
if ( NS_FAILED ( rv ) )
2006-04-20 07:37:45 +04:00
return rv ;
2006-04-20 07:37:58 +04:00
break ;
2006-04-20 07:37:45 +04:00
}
if ( serial ) {
2006-04-20 07:36:51 +04:00
// Convert to a byte stream
2006-06-16 00:30:44 +04:00
nsCOMPtr < nsIScriptableUnicodeConverter > converter =
do_CreateInstance ( " @mozilla.org/intl/scriptableunicodeconverter " , & rv ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
rv = converter - > SetCharset ( " UTF-8 " ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
rv = converter - > ConvertToInputStream ( serial ,
getter_AddRefs ( postDataStream ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2006-04-20 07:36:50 +04:00
}
2006-04-20 07:36:51 +04:00
if ( postDataStream ) {
2006-04-20 07:37:32 +04:00
nsCOMPtr < nsIUploadChannel > uploadChannel ( do_QueryInterface ( httpChannel ) ) ;
NS_ASSERTION ( uploadChannel , " http must support nsIUploadChannel " ) ;
2006-04-20 07:39:20 +04:00
// If no content type header was set by the client, we set it to
2006-04-20 07:39:30 +04:00
// application/xml.
2006-04-20 07:39:20 +04:00
nsCAutoString contentType ;
if ( NS_FAILED ( httpChannel - >
GetRequestHeader ( NS_LITERAL_CSTRING ( " Content-Type " ) ,
contentType ) ) | |
contentType . IsEmpty ( ) ) {
2006-04-20 07:39:30 +04:00
contentType = NS_LITERAL_CSTRING ( " application/xml " ) ;
2006-04-20 07:39:20 +04:00
}
rv = uploadChannel - > SetUploadStream ( postDataStream , contentType , - 1 ) ;
2006-04-20 07:37:49 +04:00
// Reset the method to its original value
if ( httpChannel ) {
2006-04-20 07:38:50 +04:00
httpChannel - > SetRequestMethod ( method ) ;
2006-04-20 07:37:49 +04:00
}
2006-04-20 07:36:51 +04:00
}
2006-04-20 07:36:50 +04:00
}
2006-04-20 07:37:08 +04:00
// Reset responseBody
mResponseBody . Truncate ( ) ;
2006-04-20 07:38:52 +04:00
// Reset responseXML
mDocument = nsnull ;
2006-04-20 07:36:54 +04:00
2006-04-20 07:38:26 +04:00
if ( ! ( mState & XML_HTTP_REQUEST_ASYNC ) ) {
mState | = XML_HTTP_REQUEST_SYNCLOOPING ;
2006-04-20 07:36:54 +04:00
}
2006-04-20 07:38:01 +04:00
if ( ! mScriptContext ) {
// We need a context to check if redirect (if any) is allowed
2006-04-20 07:38:45 +04:00
mScriptContext = GetCurrentContext ( ) ;
2006-04-20 07:38:01 +04:00
}
// Hook us up to listen to redirects and the like
2006-04-20 07:39:34 +04:00
mChannel - > GetNotificationCallbacks ( getter_AddRefs ( mNotificationCallbacks ) ) ;
2006-04-20 07:38:01 +04:00
mChannel - > SetNotificationCallbacks ( this ) ;
2006-04-20 07:38:52 +04:00
nsCOMPtr < nsIStreamListener > listener ;
if ( mState & XML_HTTP_REQUEST_MULTIPART ) {
listener = new nsMultipartProxyListener ( this ) ;
if ( ! listener ) {
return NS_ERROR_OUT_OF_MEMORY ;
}
2006-04-20 07:39:45 +04:00
} else {
listener = this ;
}
2006-04-20 07:39:25 +04:00
2006-04-20 07:39:45 +04:00
// Bypass the network cache in cases where it makes no sense:
// 1) Multipart responses are very large and would likely be doomed by the
// cache once they grow too large, so they are not worth caching.
// 2) POST responses are always unique, and we provide no API that would
// allow our consumers to specify a "cache key" to access old POST
// responses, so they are not worth caching.
if ( ( mState & XML_HTTP_REQUEST_MULTIPART ) | | method . EqualsLiteral ( " POST " ) ) {
2006-04-20 07:39:48 +04:00
AddLoadFlags ( mChannel ,
nsIRequest : : LOAD_BYPASS_CACHE | nsIRequest : : INHIBIT_CACHING ) ;
}
// When we are sync loading, we need to bypass the local cache when it would
// otherwise block us waiting for exclusive access to the cache. If we don't
// do this, then we could dead lock in some cases (see bug 309424).
else if ( mState & XML_HTTP_REQUEST_SYNCLOOPING ) {
AddLoadFlags ( mChannel ,
nsICachingChannel : : LOAD_BYPASS_LOCAL_CACHE_IF_BUSY ) ;
2006-04-20 07:38:52 +04:00
}
2006-04-20 07:39:43 +04:00
// Since we expect XML data, set the type hint accordingly
// This means that we always try to parse local files as XML
// ignoring return value, as this is not critical
mChannel - > SetContentType ( NS_LITERAL_CSTRING ( " application/xml " ) ) ;
2006-04-20 07:36:50 +04:00
// Start reading from the channel
2006-04-20 07:37:31 +04:00
ChangeState ( XML_HTTP_REQUEST_SENT ) ;
2006-04-20 07:38:52 +04:00
rv = mChannel - > AsyncOpen ( listener , nsnull ) ;
2006-04-20 07:36:54 +04:00
if ( NS_FAILED ( rv ) ) {
2006-04-20 07:39:52 +04:00
// Drop our ref to the channel to avoid cycles
mChannel = nsnull ;
2006-04-20 07:38:50 +04:00
return rv ;
2006-04-20 07:39:09 +04:00
}
2006-04-20 07:36:54 +04:00
// If we're synchronous, spin an event loop here and wait
2006-04-20 07:38:26 +04:00
if ( ! ( mState & XML_HTTP_REQUEST_ASYNC ) ) {
2006-05-10 21:30:15 +04:00
nsIThread * thread = NS_GetCurrentThread ( ) ;
2006-04-20 07:38:26 +04:00
while ( mState & XML_HTTP_REQUEST_SYNCLOOPING ) {
2006-05-10 21:30:15 +04:00
if ( ! NS_ProcessNextEvent ( thread ) ) {
rv = NS_ERROR_UNEXPECTED ;
break ;
}
2006-04-20 07:38:20 +04:00
}
2006-05-26 05:00:21 +04:00
} else {
// If we're asynchronous, we need to prevent our event listeners
// from being garbage collected even if this object becomes
// unreachable from script, since they can fire as a result of our
// reachability from the network stack.
2006-11-23 02:18:16 +03:00
rv = nsDOMClassInfo : : SetExternallyReferenced ( this ) ;
if ( NS_SUCCEEDED ( rv ) )
mState | = XML_HTTP_REQUEST_ROOTED ;
2006-04-20 07:36:50 +04:00
}
2006-04-20 07:38:52 +04:00
2006-04-20 07:38:23 +04:00
if ( ! mChannel ) {
return NS_ERROR_FAILURE ;
}
2006-05-10 21:30:15 +04:00
return rv ;
2006-04-20 07:36:50 +04:00
}
2006-04-20 07:38:50 +04:00
/* void setRequestHeader (in AUTF8String header, in AUTF8String value); */
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2006-04-20 07:38:50 +04:00
nsXMLHttpRequest : : SetRequestHeader ( const nsACString & header ,
const nsACString & value )
2006-04-20 07:36:50 +04:00
{
2006-04-20 07:37:31 +04:00
if ( ! mChannel ) // open() initializes mChannel, and open()
return NS_ERROR_FAILURE ; // must be called before first setRequestHeader()
2006-04-20 07:39:46 +04:00
// Prevent modification to certain HTTP headers (see bug 302263), unless
// the executing script has UniversalBrowserWrite permission.
2006-06-16 00:30:44 +04:00
nsIScriptSecurityManager * secMan = nsContentUtils : : GetSecurityManager ( ) ;
if ( ! secMan ) {
2006-04-20 07:39:46 +04:00
return NS_ERROR_FAILURE ;
2006-06-16 00:30:44 +04:00
}
2006-04-20 07:39:46 +04:00
PRBool privileged ;
nsresult rv = secMan - > IsCapabilityEnabled ( " UniversalBrowserWrite " ,
& privileged ) ;
if ( NS_FAILED ( rv ) )
return NS_ERROR_FAILURE ;
if ( ! privileged ) {
const char * kInvalidHeaders [ ] = {
" host " , " content-length " , " transfer-encoding " , " via " , " upgrade "
} ;
for ( size_t i = 0 ; i < NS_ARRAY_LENGTH ( kInvalidHeaders ) ; + + i ) {
if ( header . LowerCaseEqualsASCII ( kInvalidHeaders [ i ] ) ) {
NS_WARNING ( " refusing to set request header " ) ;
return NS_OK ;
}
2006-04-20 07:39:36 +04:00
}
2006-04-20 07:38:50 +04:00
}
2006-04-20 07:37:29 +04:00
nsCOMPtr < nsIHttpChannel > httpChannel ( do_QueryInterface ( mChannel ) ) ;
2006-04-20 07:38:07 +04:00
if ( httpChannel ) {
2006-04-20 07:38:16 +04:00
// We need to set, not add to, the header.
2006-04-20 07:38:50 +04:00
return httpChannel - > SetRequestHeader ( header , value , PR_FALSE ) ;
2006-04-20 07:38:07 +04:00
}
2006-04-20 07:38:48 +04:00
2006-04-20 07:36:50 +04:00
return NS_OK ;
}
2006-04-20 07:37:31 +04:00
/* readonly attribute long readyState; */
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2006-04-20 07:37:31 +04:00
nsXMLHttpRequest : : GetReadyState ( PRInt32 * aState )
{
NS_ENSURE_ARG_POINTER ( aState ) ;
2006-04-20 07:37:35 +04:00
// Translate some of our internal states for external consumers
2006-04-20 07:38:26 +04:00
if ( mState & XML_HTTP_REQUEST_UNINITIALIZED ) {
* aState = 0 ; // UNINITIALIZED
} else if ( mState & ( XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT ) ) {
* aState = 1 ; // LOADING
} else if ( mState & XML_HTTP_REQUEST_LOADED ) {
* aState = 2 ; // LOADED
} else if ( mState & ( XML_HTTP_REQUEST_INTERACTIVE | XML_HTTP_REQUEST_STOPPED ) ) {
* aState = 3 ; // INTERACTIVE
} else if ( mState & XML_HTTP_REQUEST_COMPLETED ) {
* aState = 4 ; // COMPLETED
} else {
NS_ERROR ( " Should not happen " ) ;
2006-04-20 07:37:31 +04:00
}
2006-04-20 07:39:09 +04:00
2006-04-20 07:37:31 +04:00
return NS_OK ;
}
2006-04-20 07:38:50 +04:00
/* void overrideMimeType(in AUTF8String mimetype); */
2006-04-20 07:37:48 +04:00
NS_IMETHODIMP
2006-04-20 07:38:50 +04:00
nsXMLHttpRequest : : OverrideMimeType ( const nsACString & aMimeType )
2006-04-20 07:37:48 +04:00
{
// XXX Should we do some validation here?
mOverrideMimeType . Assign ( aMimeType ) ;
return NS_OK ;
}
2006-04-20 07:38:48 +04:00
2006-04-20 07:38:52 +04:00
/* attribute boolean multipart; */
NS_IMETHODIMP
nsXMLHttpRequest : : GetMultipart ( PRBool * _retval )
{
* _retval = mState & XML_HTTP_REQUEST_MULTIPART ;
return NS_OK ;
}
/* attribute boolean multipart; */
NS_IMETHODIMP
nsXMLHttpRequest : : SetMultipart ( PRBool aMultipart )
{
if ( ! ( mState & XML_HTTP_REQUEST_UNINITIALIZED ) ) {
// Can't change this while we're in the middle of something.
return NS_ERROR_IN_PROGRESS ;
}
if ( aMultipart ) {
mState | = XML_HTTP_REQUEST_MULTIPART ;
} else {
mState & = ~ XML_HTTP_REQUEST_MULTIPART ;
}
return NS_OK ;
}
2006-04-20 07:36:50 +04:00
// nsIDOMEventListener
nsresult
nsXMLHttpRequest : : HandleEvent ( nsIDOMEvent * aEvent )
{
return NS_OK ;
}
// nsIDOMLoadListener
nsresult
nsXMLHttpRequest : : Load ( nsIDOMEvent * aEvent )
{
2006-04-20 07:37:31 +04:00
// If we had an XML error in the data, the parser terminated and
// we received the load event, even though we might still be
// loading data into responseBody/responseText. We will delay
// sending the load event until OnStopRequest(). In normal case
// there is no harm done, we will get OnStopRequest() immediately
// after the load event.
2006-04-20 07:37:35 +04:00
//
// However, if the data we were loading caused the parser to stop,
// for example when loading external stylesheets, we can receive
// the OnStopRequest() call before the parser has finished building
// the document. In that case, we obviously should not fire the event
// in OnStopRequest(). For those documents, we must wait for the load
// event from the document to fire our RequestCompleted().
2006-04-20 07:38:26 +04:00
if ( mState & XML_HTTP_REQUEST_STOPPED ) {
2006-04-20 07:37:35 +04:00
RequestCompleted ( ) ;
}
2006-04-20 07:36:50 +04:00
return NS_OK ;
}
nsresult
nsXMLHttpRequest : : Unload ( nsIDOMEvent * aEvent )
{
return NS_OK ;
}
2006-04-20 07:38:47 +04:00
nsresult
nsXMLHttpRequest : : BeforeUnload ( nsIDOMEvent * aEvent )
{
return NS_OK ;
}
2006-04-20 07:36:50 +04:00
nsresult
nsXMLHttpRequest : : Abort ( nsIDOMEvent * aEvent )
{
2006-04-20 07:38:26 +04:00
Abort ( ) ;
mState & = ~ XML_HTTP_REQUEST_SYNCLOOPING ;
2006-04-20 07:36:54 +04:00
2006-04-20 07:36:50 +04:00
return NS_OK ;
}
nsresult
nsXMLHttpRequest : : Error ( nsIDOMEvent * aEvent )
{
2006-05-26 05:00:21 +04:00
nsCOMArray < nsIDOMEventListener > errorEventListeners ;
CopyEventListeners ( mOnErrorListener , mErrorEventListeners ,
errorEventListeners ) ;
2006-04-20 07:38:48 +04:00
// We need to create the event before nulling out mDocument
2006-05-05 21:01:53 +04:00
nsCOMPtr < nsIDOMEvent > event = aEvent ;
2006-09-02 14:00:26 +04:00
nsEvent evt ( PR_TRUE , NS_LOAD_ERROR ) ;
2006-05-26 05:00:21 +04:00
if ( ! event & & errorEventListeners . Count ( ) ) {
2006-05-05 21:01:53 +04:00
CreateEvent ( & evt , EmptyString ( ) , getter_AddRefs ( event ) ) ;
2006-04-20 07:36:53 +04:00
}
2006-04-20 07:38:48 +04:00
mDocument = nsnull ;
ChangeState ( XML_HTTP_REQUEST_COMPLETED ) ;
2006-04-20 07:36:53 +04:00
2006-04-20 07:38:48 +04:00
mState & = ~ XML_HTTP_REQUEST_SYNCLOOPING ;
2006-04-20 07:36:53 +04:00
2006-04-20 07:38:26 +04:00
ClearEventListeners ( ) ;
2006-04-20 07:39:23 +04:00
2006-05-05 21:01:53 +04:00
if ( event ) {
2006-05-26 05:00:21 +04:00
NotifyEventListeners ( errorEventListeners , event ) ;
2006-05-05 21:01:53 +04:00
}
2006-04-20 07:38:26 +04:00
2006-04-20 07:36:53 +04:00
return NS_OK ;
}
2006-04-20 07:37:18 +04:00
2006-04-20 07:37:31 +04:00
nsresult
2006-04-20 07:39:23 +04:00
nsXMLHttpRequest : : ChangeState ( PRUint32 aState , PRBool aBroadcast ,
PRBool aClearEventListeners )
2006-04-20 07:37:31 +04:00
{
2006-05-26 05:00:21 +04:00
// If we are setting one of the mutually exclusive states,
2006-04-20 07:38:26 +04:00
// unset those state bits first.
if ( aState & XML_HTTP_REQUEST_LOADSTATES ) {
mState & = ~ XML_HTTP_REQUEST_LOADSTATES ;
}
mState | = aState ;
2006-04-20 07:37:31 +04:00
nsresult rv = NS_OK ;
2006-04-20 07:39:23 +04:00
2006-05-05 21:01:53 +04:00
// Grab private copies of the listeners we need
2006-05-26 05:00:21 +04:00
nsCOMArray < nsIDOMEventListener > readystatechangeEventListeners ;
CopyEventListeners ( mOnReadystatechangeListener ,
mReadystatechangeEventListeners ,
readystatechangeEventListeners ) ;
2006-04-20 07:39:23 +04:00
if ( aClearEventListeners ) {
ClearEventListeners ( ) ;
}
2006-04-20 07:38:26 +04:00
if ( ( mState & XML_HTTP_REQUEST_ASYNC ) & &
( aState & XML_HTTP_REQUEST_LOADSTATES ) & & // Broadcast load states only
2006-04-20 07:39:09 +04:00
aBroadcast & &
2006-05-26 05:00:21 +04:00
readystatechangeEventListeners . Count ( ) ) {
2006-05-05 21:01:53 +04:00
nsCOMPtr < nsIDOMEvent > event ;
rv = CreateEvent ( nsnull , NS_LITERAL_STRING ( READYSTATE_STR ) ,
getter_AddRefs ( event ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2006-04-20 07:37:31 +04:00
2006-05-26 05:00:21 +04:00
NotifyEventListeners ( readystatechangeEventListeners , event ) ;
2006-04-20 07:37:31 +04:00
}
return rv ;
}
2006-04-20 07:38:01 +04:00
/////////////////////////////////////////////////////
2006-04-20 07:39:29 +04:00
// nsIChannelEventSink methods:
2006-04-20 07:38:01 +04:00
//
NS_IMETHODIMP
2006-04-20 07:39:29 +04:00
nsXMLHttpRequest : : OnChannelRedirect ( nsIChannel * aOldChannel ,
nsIChannel * aNewChannel ,
PRUint32 aFlags )
2006-04-20 07:38:01 +04:00
{
2006-04-20 07:39:29 +04:00
NS_PRECONDITION ( aNewChannel , " Redirect without a channel? " ) ;
2006-04-20 07:38:01 +04:00
2006-04-20 07:38:26 +04:00
if ( mScriptContext & & ! ( mState & XML_HTTP_REQUEST_XSITEENABLED ) ) {
2006-04-20 07:38:01 +04:00
nsresult rv = NS_ERROR_FAILURE ;
nsCOMPtr < nsIJSContextStack > stack ( do_GetService ( " @mozilla.org/js/xpc/ContextStack;1 " , & rv ) ) ;
if ( NS_FAILED ( rv ) )
return rv ;
JSContext * cx = ( JSContext * ) mScriptContext - > GetNativeContext ( ) ;
if ( ! cx )
return NS_ERROR_UNEXPECTED ;
2006-06-16 00:30:44 +04:00
nsIScriptSecurityManager * secMan = nsContentUtils : : GetSecurityManager ( ) ;
if ( ! secMan ) {
return NS_ERROR_FAILURE ;
}
2006-04-20 07:38:01 +04:00
nsCOMPtr < nsIURI > newURI ;
rv = aNewChannel - > GetURI ( getter_AddRefs ( newURI ) ) ; // The redirected URI
2006-04-20 07:39:09 +04:00
if ( NS_FAILED ( rv ) )
2006-04-20 07:38:01 +04:00
return rv ;
stack - > Push ( cx ) ;
rv = secMan - > CheckSameOrigin ( cx , newURI ) ;
stack - > Pop ( & cx ) ;
2006-04-20 07:39:09 +04:00
2006-04-20 07:38:01 +04:00
if ( NS_FAILED ( rv ) )
return rv ;
}
2006-04-20 07:39:34 +04:00
if ( mChannelEventSink ) {
nsresult rv =
mChannelEventSink - > OnChannelRedirect ( aOldChannel , aNewChannel , aFlags ) ;
if ( NS_FAILED ( rv ) ) {
return rv ;
}
}
2006-04-20 07:38:01 +04:00
mChannel = aNewChannel ;
return NS_OK ;
}
2006-04-20 07:39:18 +04:00
/////////////////////////////////////////////////////
// nsIProgressEventSink methods:
//
NS_IMETHODIMP
2006-04-20 07:39:26 +04:00
nsXMLHttpRequest : : OnProgress ( nsIRequest * aRequest , nsISupports * aContext , PRUint64 aProgress , PRUint64 aProgressMax )
2006-04-20 07:39:18 +04:00
{
2006-05-15 22:28:21 +04:00
// We're uploading if our state is XML_HTTP_REQUEST_OPENED or
// XML_HTTP_REQUEST_SENT
PRBool downloading =
! ( ( XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT ) & mState ) ;
2006-05-26 05:00:21 +04:00
nsCOMArray < nsIDOMEventListener > progressListeners ;
if ( downloading ) {
CopyEventListeners ( mOnProgressListener ,
mProgressEventListeners , progressListeners ) ;
} else {
CopyEventListeners ( mOnUploadProgressListener ,
mUploadProgressEventListeners , progressListeners ) ;
}
2006-05-05 21:01:53 +04:00
2006-05-26 05:00:21 +04:00
if ( progressListeners . Count ( ) ) {
2006-04-20 07:39:18 +04:00
nsCOMPtr < nsIDOMEvent > event ;
2006-05-05 21:01:53 +04:00
nsresult rv = CreateEvent ( nsnull , NS_LITERAL_STRING ( PROGRESS_STR ) ,
getter_AddRefs ( event ) ) ;
2006-04-20 07:39:18 +04:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2006-05-05 21:01:53 +04:00
nsXMLHttpProgressEvent * progressEvent =
new nsXMLHttpProgressEvent ( event , aProgress , aProgressMax ) ;
2006-04-20 07:39:18 +04:00
if ( ! progressEvent )
return NS_ERROR_OUT_OF_MEMORY ;
2006-05-05 21:01:53 +04:00
event = progressEvent ;
2006-05-26 05:00:21 +04:00
NotifyEventListeners ( progressListeners , event ) ;
2006-04-20 07:39:18 +04:00
}
2006-04-20 07:39:34 +04:00
if ( mProgressEventSink ) {
mProgressEventSink - > OnProgress ( aRequest , aContext , aProgress ,
aProgressMax ) ;
}
2006-04-20 07:39:18 +04:00
return NS_OK ;
}
NS_IMETHODIMP
nsXMLHttpRequest : : OnStatus ( nsIRequest * aRequest , nsISupports * aContext , nsresult aStatus , const PRUnichar * aStatusArg )
{
2006-04-20 07:39:34 +04:00
if ( mProgressEventSink ) {
mProgressEventSink - > OnStatus ( aRequest , aContext , aStatus , aStatusArg ) ;
}
2006-04-20 07:39:18 +04:00
return NS_OK ;
}
2006-04-20 07:38:01 +04:00
/////////////////////////////////////////////////////
// nsIInterfaceRequestor methods:
//
NS_IMETHODIMP
nsXMLHttpRequest : : GetInterface ( const nsIID & aIID , void * * aResult )
{
2006-04-20 07:39:34 +04:00
// Make sure to return ourselves for the channel event sink interface and
// progress event sink interface, no matter what. We can forward these to
// mNotificationCallbacks if it wants to get notifications for them. But we
// need to see these notifications for proper functioning.
if ( aIID . Equals ( NS_GET_IID ( nsIChannelEventSink ) ) ) {
mChannelEventSink = do_GetInterface ( mNotificationCallbacks ) ;
* aResult = NS_STATIC_CAST ( nsIChannelEventSink * , this ) ;
NS_ADDREF_THIS ( ) ;
return NS_OK ;
} else if ( aIID . Equals ( NS_GET_IID ( nsIProgressEventSink ) ) ) {
mProgressEventSink = do_GetInterface ( mNotificationCallbacks ) ;
* aResult = NS_STATIC_CAST ( nsIProgressEventSink * , this ) ;
NS_ADDREF_THIS ( ) ;
return NS_OK ;
}
// Now give mNotificationCallbacks (if non-null) a chance to return the
// desired interface. Note that this means that it can override our
// nsIAuthPrompt impl, but that's fine, if it has a better auth prompt idea.
if ( mNotificationCallbacks ) {
nsresult rv = mNotificationCallbacks - > GetInterface ( aIID , aResult ) ;
if ( NS_SUCCEEDED ( rv ) ) {
NS_ASSERTION ( * aResult , " Lying nsIInterfaceRequestor implementation! " ) ;
return rv ;
}
}
if ( aIID . Equals ( NS_GET_IID ( nsIAuthPrompt ) ) ) {
2006-04-20 07:38:01 +04:00
* aResult = nsnull ;
nsresult rv ;
2006-04-20 07:38:06 +04:00
nsCOMPtr < nsIWindowWatcher > ww ( do_GetService ( NS_WINDOWWATCHER_CONTRACTID , & rv ) ) ;
2006-04-20 07:38:01 +04:00
if ( NS_FAILED ( rv ) )
return rv ;
nsCOMPtr < nsIAuthPrompt > prompt ;
rv = ww - > GetNewAuthPrompter ( nsnull , getter_AddRefs ( prompt ) ) ;
if ( NS_FAILED ( rv ) )
return rv ;
nsIAuthPrompt * p = prompt . get ( ) ;
NS_ADDREF ( p ) ;
* aResult = p ;
return NS_OK ;
}
return QueryInterface ( aIID , aResult ) ;
}
2006-11-23 02:18:16 +03:00
/////////////////////////////////////////////////////
// nsIDOMGCParticipant methods:
//
/* virtual */ nsIDOMGCParticipant *
nsXMLHttpRequest : : GetSCCIndex ( )
{
return this ;
}
/* virtual */ void
nsXMLHttpRequest : : AppendReachableList ( nsCOMArray < nsIDOMGCParticipant > & aArray )
{
nsCOMPtr < nsIDOMGCParticipant > gcp = do_QueryInterface ( mDocument ) ;
if ( gcp )
aArray . AppendObject ( gcp ) ;
}
2006-05-26 05:00:21 +04:00
2006-04-20 07:37:18 +04:00
NS_IMPL_ISUPPORTS1 ( nsXMLHttpRequest : : nsHeaderVisitor , nsIHttpHeaderVisitor )
NS_IMETHODIMP nsXMLHttpRequest : :
2006-04-20 07:37:53 +04:00
nsHeaderVisitor : : VisitHeader ( const nsACString & header , const nsACString & value )
2006-04-20 07:37:18 +04:00
{
mHeaders . Append ( header ) ;
mHeaders . Append ( " : " ) ;
mHeaders . Append ( value ) ;
mHeaders . Append ( ' \n ' ) ;
return NS_OK ;
}
2006-04-20 07:39:18 +04:00
// DOM event class to handle progress notifications
2006-04-20 07:39:26 +04:00
nsXMLHttpProgressEvent : : nsXMLHttpProgressEvent ( nsIDOMEvent * aInner , PRUint64 aCurrentProgress , PRUint64 aMaxProgress )
2006-04-20 07:39:18 +04:00
{
mInner = aInner ;
mCurProgress = aCurrentProgress ;
mMaxProgress = aMaxProgress ;
}
nsXMLHttpProgressEvent : : ~ nsXMLHttpProgressEvent ( )
{ }
// QueryInterface implementation for nsXMLHttpRequest
NS_INTERFACE_MAP_BEGIN ( nsXMLHttpProgressEvent )
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS ( nsISupports , nsIDOMLSProgressEvent )
NS_INTERFACE_MAP_ENTRY ( nsIDOMLSProgressEvent )
NS_INTERFACE_MAP_ENTRY ( nsIDOMEvent )
2006-04-26 13:19:48 +04:00
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO ( XMLHttpProgressEvent )
2006-04-20 07:39:18 +04:00
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF ( nsXMLHttpProgressEvent )
NS_IMPL_RELEASE ( nsXMLHttpProgressEvent )
NS_IMETHODIMP nsXMLHttpProgressEvent : : GetInput ( nsIDOMLSInput * * aInput )
{
* aInput = nsnull ;
return NS_ERROR_NOT_IMPLEMENTED ;
}
NS_IMETHODIMP nsXMLHttpProgressEvent : : GetPosition ( PRUint32 * aPosition )
{
2006-04-20 07:39:26 +04:00
// XXX can we change the iface?
LL_L2UI ( * aPosition , mCurProgress ) ;
2006-04-20 07:39:18 +04:00
return NS_OK ;
}
NS_IMETHODIMP nsXMLHttpProgressEvent : : GetTotalSize ( PRUint32 * aTotalSize )
{
2006-04-20 07:39:26 +04:00
// XXX can we change the iface?
LL_L2UI ( * aTotalSize , mMaxProgress ) ;
2006-04-20 07:39:18 +04:00
return NS_OK ;
}