2007-03-22 10:30:00 -07:00
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version : MPL 1.1 / GPL 2.0 / LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 ( the " License " ) ; you may not use this file except in compliance with
* the License . You may obtain a copy of the License at
* http : //www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an " AS IS " basis ,
* WITHOUT WARRANTY OF ANY KIND , either express or implied . See the License
* for the specific language governing rights and limitations under the
* License .
*
* The Original Code is mozilla . org code .
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation .
* Portions created by the Initial Developer are Copyright ( C ) 1998
* the Initial Developer . All Rights Reserved .
*
* Contributor ( s ) :
*
* Alternatively , the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later ( the " GPL " ) , or
* the GNU Lesser General Public License Version 2.1 or later ( the " LGPL " ) ,
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above . If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL , and not to allow others to
* use your version of this file under the terms of the MPL , indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL . If you do not delete
* the provisions above , a recipient may use your version of this file under
* the terms of any one of the MPL , the GPL or the LGPL .
*
* * * * * * END LICENSE BLOCK * * * * * */
# include "nsXMLHttpRequest.h"
# include "nsISimpleEnumerator.h"
# include "nsIXPConnect.h"
# include "nsICharsetConverterManager.h"
# include "nsLayoutCID.h"
# include "nsXPIDLString.h"
# include "nsReadableUtils.h"
# include "nsIURI.h"
# include "nsILoadGroup.h"
# include "nsNetUtil.h"
2009-09-08 16:29:41 -07:00
# include "nsStreamUtils.h"
2007-03-22 10:30:00 -07:00
# include "nsThreadUtils.h"
# include "nsIUploadChannel.h"
2009-09-08 16:29:41 -07:00
# include "nsIUploadChannel2.h"
2007-03-22 10:30:00 -07:00
# include "nsIDOMSerializer.h"
# include "nsXPCOM.h"
# include "nsISupportsPrimitives.h"
# include "nsGUIEvent.h"
# include "nsIPrivateDOMEvent.h"
# include "prprf.h"
# include "nsIDOMEventListener.h"
# include "nsIJSContextStack.h"
# include "nsIScriptSecurityManager.h"
# include "nsWeakPtr.h"
# include "nsICharsetAlias.h"
# include "nsIScriptGlobalObject.h"
# include "nsIDOMClassInfo.h"
# include "nsIDOMElement.h"
# include "nsIDOMWindow.h"
2009-09-08 16:29:41 -07:00
# include "nsIMIMEService.h"
# include "nsCExternalHandlerService.h"
2007-03-22 10:30:00 -07:00
# include "nsIVariant.h"
2011-05-10 16:18:55 -07:00
# include "xpcprivate.h"
2007-03-22 10:30:00 -07:00
# include "nsIParser.h"
# include "nsLoadListenerProxy.h"
# include "nsStringStream.h"
# include "nsIStreamConverterService.h"
# include "nsICachingChannel.h"
# include "nsContentUtils.h"
# include "nsEventDispatcher.h"
# include "nsDOMJSUtils.h"
# include "nsCOMArray.h"
# include "nsDOMClassInfo.h"
# include "nsIScriptableUConv.h"
# include "nsCycleCollectionParticipant.h"
2007-03-24 22:35:39 -07:00
# include "nsIContentPolicy.h"
# include "nsContentPolicyUtils.h"
# include "nsContentErrors.h"
2007-05-16 10:05:47 -07:00
# include "nsLayoutStatics.h"
2008-09-30 17:49:30 -07:00
# include "nsCrossSiteListenerProxy.h"
2007-07-24 21:53:21 -07:00
# include "nsDOMError.h"
2007-07-26 19:49:18 -07:00
# include "nsIHTMLDocument.h"
2007-07-30 17:42:16 -07:00
# include "nsIMultiPartChannel.h"
2007-12-12 00:33:32 -08:00
# include "nsIScriptObjectPrincipal.h"
2008-03-18 12:49:20 -07:00
# include "nsIStorageStream.h"
2008-04-08 17:27:50 -07:00
# include "nsIPromptFactory.h"
# include "nsIWindowWatcher.h"
2010-05-04 07:43:48 -07:00
# include "nsCharSeparatedTokenizer.h"
2009-11-18 15:21:13 -08:00
# include "nsIConsoleService.h"
2010-04-23 12:54:09 -07:00
# include "nsIChannelPolicy.h"
# include "nsChannelPolicy.h"
# include "nsIContentSecurityPolicy.h"
2010-08-04 19:15:55 -07:00
# include "nsAsyncRedirectVerifyHelper.h"
2010-08-14 10:52:19 -07:00
# include "jstypedarray.h"
2010-11-23 08:49:12 -08:00
# include "nsStringBuffer.h"
2011-05-10 16:18:55 -07:00
# include "nsDOMFile.h"
# include "nsIFileChannel.h"
2007-03-22 10:30:00 -07:00
# define LOAD_STR "load"
# define ERROR_STR "error"
2008-08-14 04:07:46 -07:00
# define ABORT_STR "abort"
# define LOADSTART_STR "loadstart"
2007-03-22 10:30:00 -07:00
# define PROGRESS_STR "progress"
# define UPLOADPROGRESS_STR "uploadprogress"
# define READYSTATE_STR "readystatechange"
2011-03-24 06:22:03 -07:00
# define LOADEND_STR "loadend"
2007-03-22 10:30:00 -07:00
// CIDs
// State
2011-05-10 16:18:55 -07:00
# define XML_HTTP_REQUEST_UNSENT (1 << 0) // 0 UNSENT
# define XML_HTTP_REQUEST_OPENED (1 << 1) // 1 OPENED
# define XML_HTTP_REQUEST_HEADERS_RECEIVED (1 << 2) // 2 HEADERS_RECEIVED
# define XML_HTTP_REQUEST_LOADING (1 << 3) // 3 LOADING
# define XML_HTTP_REQUEST_DONE (1 << 4) // 4 DONE
# define XML_HTTP_REQUEST_SENT (1 << 5) // Internal, OPENED in IE and external view
# define XML_HTTP_REQUEST_STOPPED (1 << 6) // Internal, LOADING in IE and external view
2007-03-22 10:30:00 -07:00
// The above states are mutually exclusive, change with ChangeState() only.
// The states below can be combined.
# define XML_HTTP_REQUEST_ABORTED (1 << 7) // Internal
# define XML_HTTP_REQUEST_ASYNC (1 << 8) // Internal
# define XML_HTTP_REQUEST_PARSEBODY (1 << 9) // Internal
2011-03-17 09:19:13 -07:00
# define XML_HTTP_REQUEST_SYNCLOOPING (1 << 10) // Internal
# define XML_HTTP_REQUEST_MULTIPART (1 << 11) // Internal
# define XML_HTTP_REQUEST_GOT_FINAL_STOP (1 << 12) // Internal
# define XML_HTTP_REQUEST_BACKGROUND (1 << 13) // Internal
2008-09-11 03:44:15 -07:00
// This is set when we've got the headers for a multipart XMLHttpRequest,
// but haven't yet started to process the first part.
2011-03-17 09:19:13 -07:00
# define XML_HTTP_REQUEST_MPART_HEADERS (1 << 14) // Internal
# define XML_HTTP_REQUEST_USE_XSITE_AC (1 << 15) // Internal
# define XML_HTTP_REQUEST_NEED_AC_PREFLIGHT (1 << 16) // Internal
# define XML_HTTP_REQUEST_AC_WITH_CREDENTIALS (1 << 17) // Internal
2007-03-22 10:30:00 -07:00
# define XML_HTTP_REQUEST_LOADSTATES \
2011-05-10 16:18:55 -07:00
( XML_HTTP_REQUEST_UNSENT | \
2007-03-22 10:30:00 -07:00
XML_HTTP_REQUEST_OPENED | \
2011-05-10 16:18:55 -07:00
XML_HTTP_REQUEST_HEADERS_RECEIVED | \
XML_HTTP_REQUEST_LOADING | \
XML_HTTP_REQUEST_DONE | \
2007-03-22 10:30:00 -07:00
XML_HTTP_REQUEST_SENT | \
XML_HTTP_REQUEST_STOPPED )
2008-03-18 17:14:38 -07:00
# define NS_BADCERTHANDLER_CONTRACTID \
" @mozilla.org/content/xmlhttprequest-bad-cert-handler;1 "
2009-01-13 09:38:01 -08:00
# define NS_PROGRESS_EVENT_INTERVAL 50
2008-10-19 14:26:37 -07:00
2009-03-03 12:11:14 -08:00
class nsResumeTimeoutsEvent : public nsRunnable
{
public :
nsResumeTimeoutsEvent ( nsPIDOMWindow * aWindow ) : mWindow ( aWindow ) { }
NS_IMETHOD Run ( )
{
mWindow - > ResumeTimeouts ( PR_FALSE ) ;
return NS_OK ;
}
private :
nsCOMPtr < nsPIDOMWindow > mWindow ;
} ;
2008-08-14 04:04:43 -07:00
2007-03-22 10:30:00 -07: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 ) ;
}
2008-03-18 17:14:38 -07:00
static nsresult IsCapabilityEnabled ( const char * capability , PRBool * enabled )
{
nsIScriptSecurityManager * secMan = nsContentUtils : : GetSecurityManager ( ) ;
if ( ! secMan )
return NS_ERROR_FAILURE ;
return secMan - > IsCapabilityEnabled ( capability , enabled ) ;
}
2007-03-22 10:30:00 -07: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 ) ;
if ( ! contentType . EqualsLiteral ( " multipart/x-mixed-replace " ) ) {
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.
2008-09-11 03:44:15 -07:00
nsCOMPtr < nsIXMLHttpRequest > xhr = do_QueryInterface ( mDestListener ) ;
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsIStreamConverterService > convServ =
do_GetService ( " @mozilla.org/streamConverters;1 " , & rv ) ;
if ( NS_SUCCEEDED ( rv ) ) {
nsCOMPtr < nsIStreamListener > toListener ( mDestListener ) ;
nsCOMPtr < nsIStreamListener > fromListener ;
rv = convServ - > AsyncConvertData ( " multipart/x-mixed-replace " ,
" */* " ,
toListener ,
nsnull ,
getter_AddRefs ( fromListener ) ) ;
NS_ENSURE_TRUE ( NS_SUCCEEDED ( rv ) & & fromListener , NS_ERROR_UNEXPECTED ) ;
mDestListener = fromListener ;
}
2008-09-11 03:44:15 -07:00
if ( xhr ) {
static_cast < nsXMLHttpRequest * > ( xhr . get ( ) ) - > mState | =
XML_HTTP_REQUEST_MPART_HEADERS ;
}
2007-03-22 10:30:00 -07:00
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 ) ;
}
2008-08-14 04:07:46 -07:00
/////////////////////////////////////////////
NS_IMPL_CYCLE_COLLECTION_CLASS ( nsXHREventTarget )
2009-06-15 01:27:29 -07:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED ( nsXHREventTarget ,
2010-06-17 04:27:52 -07:00
nsDOMEventTargetWrapperCache )
2008-08-14 04:07:46 -07:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR ( mOnLoadListener )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR ( mOnErrorListener )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR ( mOnAbortListener )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR ( mOnLoadStartListener )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR ( mOnProgressListener )
2011-03-24 06:22:03 -07:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR ( mOnLoadendListener )
2008-08-14 04:07:46 -07:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
2009-06-15 01:27:29 -07:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED ( nsXHREventTarget ,
2010-06-17 04:27:52 -07:00
nsDOMEventTargetWrapperCache )
2008-08-14 04:07:46 -07:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR ( mOnLoadListener )
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR ( mOnErrorListener )
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR ( mOnAbortListener )
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR ( mOnLoadStartListener )
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR ( mOnProgressListener )
2011-03-24 06:22:03 -07:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR ( mOnLoadendListener )
2008-08-14 04:07:46 -07:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
2009-06-15 01:27:29 -07:00
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED ( nsXHREventTarget )
2008-08-14 04:07:46 -07:00
NS_INTERFACE_MAP_ENTRY ( nsIXMLHttpRequestEventTarget )
2010-06-17 04:27:52 -07:00
NS_INTERFACE_MAP_END_INHERITING ( nsDOMEventTargetWrapperCache )
2008-08-14 04:07:46 -07:00
2010-06-17 04:27:52 -07:00
NS_IMPL_ADDREF_INHERITED ( nsXHREventTarget , nsDOMEventTargetWrapperCache )
NS_IMPL_RELEASE_INHERITED ( nsXHREventTarget , nsDOMEventTargetWrapperCache )
2008-08-14 04:07:46 -07:00
NS_IMETHODIMP
nsXHREventTarget : : GetOnload ( nsIDOMEventListener * * aOnLoad )
{
return GetInnerEventListener ( mOnLoadListener , aOnLoad ) ;
}
NS_IMETHODIMP
nsXHREventTarget : : SetOnload ( nsIDOMEventListener * aOnLoad )
{
return RemoveAddEventListener ( NS_LITERAL_STRING ( LOAD_STR ) ,
mOnLoadListener , aOnLoad ) ;
}
NS_IMETHODIMP
nsXHREventTarget : : GetOnerror ( nsIDOMEventListener * * aOnerror )
{
return GetInnerEventListener ( mOnErrorListener , aOnerror ) ;
}
NS_IMETHODIMP
nsXHREventTarget : : SetOnerror ( nsIDOMEventListener * aOnerror )
{
return RemoveAddEventListener ( NS_LITERAL_STRING ( ERROR_STR ) ,
mOnErrorListener , aOnerror ) ;
}
NS_IMETHODIMP
nsXHREventTarget : : GetOnabort ( nsIDOMEventListener * * aOnabort )
{
return GetInnerEventListener ( mOnAbortListener , aOnabort ) ;
}
NS_IMETHODIMP
nsXHREventTarget : : SetOnabort ( nsIDOMEventListener * aOnabort )
{
return RemoveAddEventListener ( NS_LITERAL_STRING ( ABORT_STR ) ,
mOnAbortListener , aOnabort ) ;
}
NS_IMETHODIMP
nsXHREventTarget : : GetOnloadstart ( nsIDOMEventListener * * aOnloadstart )
{
return GetInnerEventListener ( mOnLoadStartListener , aOnloadstart ) ;
}
NS_IMETHODIMP
nsXHREventTarget : : SetOnloadstart ( nsIDOMEventListener * aOnloadstart )
{
return RemoveAddEventListener ( NS_LITERAL_STRING ( LOADSTART_STR ) ,
mOnLoadStartListener , aOnloadstart ) ;
}
NS_IMETHODIMP
nsXHREventTarget : : GetOnprogress ( nsIDOMEventListener * * aOnprogress )
{
return GetInnerEventListener ( mOnProgressListener , aOnprogress ) ;
}
NS_IMETHODIMP
nsXHREventTarget : : SetOnprogress ( nsIDOMEventListener * aOnprogress )
{
return RemoveAddEventListener ( NS_LITERAL_STRING ( PROGRESS_STR ) ,
mOnProgressListener , aOnprogress ) ;
}
2011-03-24 06:22:03 -07:00
NS_IMETHODIMP
nsXHREventTarget : : GetOnloadend ( nsIDOMEventListener * * aOnLoadend )
{
return GetInnerEventListener ( mOnLoadendListener , aOnLoadend ) ;
}
NS_IMETHODIMP
nsXHREventTarget : : SetOnloadend ( nsIDOMEventListener * aOnLoadend )
{
return RemoveAddEventListener ( NS_LITERAL_STRING ( LOADEND_STR ) ,
mOnLoadendListener , aOnLoadend ) ;
}
2008-09-25 07:40:30 -07:00
/////////////////////////////////////////////
2008-08-14 04:07:46 -07:00
2008-10-08 23:38:04 -07:00
nsXMLHttpRequestUpload : : ~ nsXMLHttpRequestUpload ( )
{
if ( mListenerManager ) {
mListenerManager - > Disconnect ( ) ;
}
}
2010-01-12 05:08:43 -08:00
DOMCI_DATA ( XMLHttpRequestUpload , nsXMLHttpRequestUpload )
2008-09-25 07:40:30 -07:00
NS_INTERFACE_MAP_BEGIN ( nsXMLHttpRequestUpload )
2008-08-14 04:07:46 -07:00
NS_INTERFACE_MAP_ENTRY ( nsIXMLHttpRequestUpload )
2010-03-17 08:09:05 -07:00
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO ( XMLHttpRequestUpload )
2008-08-14 04:07:46 -07:00
NS_INTERFACE_MAP_END_INHERITING ( nsXHREventTarget )
NS_IMPL_ADDREF_INHERITED ( nsXMLHttpRequestUpload , nsXHREventTarget )
NS_IMPL_RELEASE_INHERITED ( nsXMLHttpRequestUpload , nsXHREventTarget )
2007-03-22 10:30:00 -07:00
/////////////////////////////////////////////
//
//
/////////////////////////////////////////////
nsXMLHttpRequest : : nsXMLHttpRequest ( )
2011-05-10 16:18:55 -07:00
: mResponseType ( XML_HTTP_RESPONSE_TYPE_DEFAULT ) ,
mRequestObserver ( nsnull ) , mState ( XML_HTTP_REQUEST_UNSENT ) ,
2008-09-30 16:56:57 -07:00
mUploadTransferred ( 0 ) , mUploadTotal ( 0 ) , mUploadComplete ( PR_TRUE ) ,
2008-10-19 14:26:37 -07:00
mUploadProgress ( 0 ) , mUploadProgressMax ( 0 ) ,
mErrorLoad ( PR_FALSE ) , mTimerIsActive ( PR_FALSE ) ,
mProgressEventWasDelayed ( PR_FALSE ) ,
mLoadLengthComputable ( PR_FALSE ) , mLoadTotal ( 0 ) ,
2011-05-23 18:09:28 -07:00
mFirstStartRequestSeen ( PR_FALSE ) ,
mResultArrayBuffer ( nsnull )
2007-03-22 10:30:00 -07:00
{
2010-04-23 10:37:02 -07:00
mResponseBodyUnicode . SetIsVoid ( PR_TRUE ) ;
2007-05-16 10:05:47 -07:00
nsLayoutStatics : : AddRef ( ) ;
2007-03-22 10:30:00 -07:00
}
nsXMLHttpRequest : : ~ nsXMLHttpRequest ( )
{
2008-08-14 04:04:43 -07:00
if ( mListenerManager ) {
mListenerManager - > Disconnect ( ) ;
}
2007-03-22 10:30:00 -07:00
if ( mState & ( XML_HTTP_REQUEST_STOPPED |
XML_HTTP_REQUEST_SENT |
2011-05-10 16:18:55 -07:00
XML_HTTP_REQUEST_LOADING ) ) {
2007-03-22 10:30:00 -07:00
Abort ( ) ;
}
NS_ABORT_IF_FALSE ( ! ( mState & XML_HTTP_REQUEST_SYNCLOOPING ) , " we rather crash than hang " ) ;
mState & = ~ XML_HTTP_REQUEST_SYNCLOOPING ;
2007-05-16 10:05:47 -07:00
nsLayoutStatics : : Release ( ) ;
2007-03-22 10:30:00 -07:00
}
2011-05-23 18:09:28 -07:00
void
nsXMLHttpRequest : : RootResultArrayBuffer ( )
{
nsContentUtils : : PreserveWrapper ( static_cast < nsPIDOMEventTarget * > ( this ) , this ) ;
}
2008-02-19 15:12:23 -08:00
/**
* This Init method is called from the factory constructor .
*/
2007-12-12 00:33:32 -08:00
nsresult
nsXMLHttpRequest : : Init ( )
{
// Set the original mScriptContext and mPrincipal, if available.
// Get JSContext from stack.
nsCOMPtr < nsIJSContextStack > stack =
do_GetService ( " @mozilla.org/js/xpc/ContextStack;1 " ) ;
if ( ! stack ) {
return NS_OK ;
}
JSContext * cx ;
if ( NS_FAILED ( stack - > Peek ( & cx ) ) | | ! cx ) {
return NS_OK ;
}
nsIScriptSecurityManager * secMan = nsContentUtils : : GetSecurityManager ( ) ;
nsCOMPtr < nsIPrincipal > subjectPrincipal ;
if ( secMan ) {
secMan - > GetSubjectPrincipal ( getter_AddRefs ( subjectPrincipal ) ) ;
}
NS_ENSURE_STATE ( subjectPrincipal ) ;
mPrincipal = subjectPrincipal ;
2008-02-19 15:12:23 -08:00
nsIScriptContext * context = GetScriptContextFromJSContext ( cx ) ;
if ( context ) {
mScriptContext = context ;
nsCOMPtr < nsPIDOMWindow > window =
do_QueryInterface ( context - > GetGlobalObject ( ) ) ;
if ( window ) {
mOwner = window - > GetCurrentInnerWindow ( ) ;
}
}
return NS_OK ;
}
/**
* This Init method should only be called by C + + consumers .
*/
NS_IMETHODIMP
nsXMLHttpRequest : : Init ( nsIPrincipal * aPrincipal ,
nsIScriptContext * aScriptContext ,
2008-12-30 14:24:58 -08:00
nsPIDOMWindow * aOwnerWindow ,
nsIURI * aBaseURI )
2008-02-19 15:12:23 -08:00
{
NS_ENSURE_ARG_POINTER ( aPrincipal ) ;
// This object may have already been initialized in the other Init call above
// if JS was on the stack. Clear the old values for mScriptContext and mOwner
// if new ones are not supplied here.
mPrincipal = aPrincipal ;
mScriptContext = aScriptContext ;
if ( aOwnerWindow ) {
mOwner = aOwnerWindow - > GetCurrentInnerWindow ( ) ;
}
else {
mOwner = nsnull ;
2007-12-12 00:33:32 -08:00
}
2008-12-30 14:24:58 -08:00
mBaseURI = aBaseURI ;
2007-12-12 00:33:32 -08:00
return NS_OK ;
}
2008-02-19 15:12:23 -08:00
/**
* This Initialize method is called from XPConnect via nsIJSNativeInitializer .
*/
2007-12-12 00:33:32 -08:00
NS_IMETHODIMP
nsXMLHttpRequest : : Initialize ( nsISupports * aOwner , JSContext * cx , JSObject * obj ,
PRUint32 argc , jsval * argv )
{
mOwner = do_QueryInterface ( aOwner ) ;
if ( ! mOwner ) {
NS_WARNING ( " Unexpected nsIJSNativeInitializer owner " ) ;
return NS_OK ;
}
// This XHR object is bound to a |window|,
// so re-set principal and script context.
nsCOMPtr < nsIScriptObjectPrincipal > scriptPrincipal = do_QueryInterface ( aOwner ) ;
NS_ENSURE_STATE ( scriptPrincipal ) ;
mPrincipal = scriptPrincipal - > GetPrincipal ( ) ;
nsCOMPtr < nsIScriptGlobalObject > sgo = do_QueryInterface ( aOwner ) ;
NS_ENSURE_STATE ( sgo ) ;
mScriptContext = sgo - > GetContext ( ) ;
NS_ENSURE_STATE ( mScriptContext ) ;
return NS_OK ;
}
2008-09-30 16:56:57 -07:00
void
nsXMLHttpRequest : : SetRequestObserver ( nsIRequestObserver * aObserver )
{
mRequestObserver = aObserver ;
}
2007-03-22 10:30:00 -07:00
NS_IMPL_CYCLE_COLLECTION_CLASS ( nsXMLHttpRequest )
2008-08-14 04:07:46 -07:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED ( nsXMLHttpRequest ,
nsXHREventTarget )
2007-03-22 10:30:00 -07:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR ( mContext )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR ( mChannel )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR ( mReadRequest )
2008-10-28 11:30:10 -07:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR ( mResponseXML )
2011-03-28 13:18:45 -07:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR ( mCORSPreflightChannel )
2007-03-22 10:30:00 -07:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR ( mOnUploadProgressListener )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR ( mOnReadystatechangeListener )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR ( mXMLParserStreamListener )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR ( mChannelEventSink )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR ( mProgressEventSink )
2007-12-12 00:33:32 -08:00
2008-08-14 04:07:46 -07:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS ( mUpload ,
nsIXMLHttpRequestUpload )
2007-03-22 10:30:00 -07:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
2008-08-14 04:07:46 -07:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED ( nsXMLHttpRequest ,
nsXHREventTarget )
2011-05-23 18:09:28 -07:00
tmp - > mResultArrayBuffer = nsnull ;
2007-03-22 10:30:00 -07:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR ( mContext )
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR ( mChannel )
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR ( mReadRequest )
2008-10-28 11:30:10 -07:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR ( mResponseXML )
2011-03-28 13:18:45 -07:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR ( mCORSPreflightChannel )
2007-03-22 10:30:00 -07:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR ( mOnUploadProgressListener )
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR ( mOnReadystatechangeListener )
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR ( mXMLParserStreamListener )
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR ( mChannelEventSink )
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR ( mProgressEventSink )
2007-12-12 00:33:32 -08:00
2008-08-14 04:07:46 -07:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR ( mUpload )
2007-03-22 10:30:00 -07:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
2011-05-23 18:09:28 -07:00
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED ( nsXMLHttpRequest ,
nsXHREventTarget )
if ( tmp - > mResultArrayBuffer ) {
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK ( tmp - > mResultArrayBuffer ,
" mResultArrayBuffer " )
}
NS_IMPL_CYCLE_COLLECTION_TRACE_END
2010-01-12 05:08:43 -08:00
DOMCI_DATA ( XMLHttpRequest , nsXMLHttpRequest )
2007-03-22 10:30:00 -07:00
// QueryInterface implementation for nsXMLHttpRequest
2008-08-14 04:07:46 -07:00
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED ( nsXMLHttpRequest )
2007-03-22 10:30:00 -07:00
NS_INTERFACE_MAP_ENTRY ( nsIXMLHttpRequest )
NS_INTERFACE_MAP_ENTRY ( nsIJSXMLHttpRequest )
NS_INTERFACE_MAP_ENTRY ( nsIDOMLoadListener )
2008-04-07 23:18:35 -07:00
NS_INTERFACE_MAP_ENTRY ( nsIDOMEventListener )
2007-03-22 10:30:00 -07:00
NS_INTERFACE_MAP_ENTRY ( nsIRequestObserver )
NS_INTERFACE_MAP_ENTRY ( nsIStreamListener )
NS_INTERFACE_MAP_ENTRY ( nsIChannelEventSink )
NS_INTERFACE_MAP_ENTRY ( nsIProgressEventSink )
NS_INTERFACE_MAP_ENTRY ( nsIInterfaceRequestor )
NS_INTERFACE_MAP_ENTRY ( nsISupportsWeakReference )
2007-12-12 00:33:32 -08:00
NS_INTERFACE_MAP_ENTRY ( nsIJSNativeInitializer )
2008-10-19 14:26:37 -07:00
NS_INTERFACE_MAP_ENTRY ( nsITimerCallback )
2010-03-17 08:09:05 -07:00
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO ( XMLHttpRequest )
2008-08-14 04:07:46 -07:00
NS_INTERFACE_MAP_END_INHERITING ( nsXHREventTarget )
2007-03-22 10:30:00 -07:00
2008-08-14 04:07:46 -07:00
NS_IMPL_ADDREF_INHERITED ( nsXMLHttpRequest , nsXHREventTarget )
NS_IMPL_RELEASE_INHERITED ( nsXMLHttpRequest , nsXHREventTarget )
2007-03-22 10:30:00 -07:00
NS_IMETHODIMP
nsXMLHttpRequest : : GetOnreadystatechange ( nsIDOMEventListener * * aOnreadystatechange )
{
2008-08-14 04:07:46 -07:00
return
nsXHREventTarget : : GetInnerEventListener ( mOnReadystatechangeListener ,
aOnreadystatechange ) ;
2007-03-22 10:30:00 -07:00
}
NS_IMETHODIMP
nsXMLHttpRequest : : SetOnreadystatechange ( nsIDOMEventListener * aOnreadystatechange )
{
2008-08-14 04:07:46 -07:00
return
nsXHREventTarget : : RemoveAddEventListener ( NS_LITERAL_STRING ( READYSTATE_STR ) ,
mOnReadystatechangeListener ,
aOnreadystatechange ) ;
2007-03-22 10:30:00 -07:00
}
NS_IMETHODIMP
nsXMLHttpRequest : : GetOnuploadprogress ( nsIDOMEventListener * * aOnuploadprogress )
{
2008-08-14 04:07:46 -07:00
return
nsXHREventTarget : : GetInnerEventListener ( mOnUploadProgressListener ,
aOnuploadprogress ) ;
2007-03-22 10:30:00 -07:00
}
NS_IMETHODIMP
nsXMLHttpRequest : : SetOnuploadprogress ( nsIDOMEventListener * aOnuploadprogress )
{
2008-08-14 04:07:46 -07:00
return
nsXHREventTarget : : RemoveAddEventListener ( NS_LITERAL_STRING ( UPLOADPROGRESS_STR ) ,
mOnUploadProgressListener ,
aOnuploadprogress ) ;
2007-03-22 10:30:00 -07:00
}
/* readonly attribute nsIChannel channel; */
NS_IMETHODIMP
nsXMLHttpRequest : : GetChannel ( nsIChannel * * aChannel )
{
NS_ENSURE_ARG_POINTER ( aChannel ) ;
NS_IF_ADDREF ( * aChannel = mChannel ) ;
return NS_OK ;
}
/* readonly attribute nsIDOMDocument responseXML; */
NS_IMETHODIMP
nsXMLHttpRequest : : GetResponseXML ( nsIDOMDocument * * aResponseXML )
{
NS_ENSURE_ARG_POINTER ( aResponseXML ) ;
* aResponseXML = nsnull ;
2011-05-10 16:18:55 -07:00
if ( mResponseType ! = XML_HTTP_RESPONSE_TYPE_DEFAULT & &
mResponseType ! = XML_HTTP_RESPONSE_TYPE_DOCUMENT ) {
return NS_ERROR_DOM_INVALID_STATE_ERR ;
}
if ( ( XML_HTTP_REQUEST_DONE & mState ) & & mResponseXML ) {
2008-10-11 23:30:14 -07:00
* aResponseXML = mResponseXML ;
2007-03-22 10:30:00 -07:00
NS_ADDREF ( * aResponseXML ) ;
}
return NS_OK ;
}
/*
* This piece copied from nsXMLDocument , we try to get the charset
* from HTTP headers .
*/
nsresult
nsXMLHttpRequest : : DetectCharset ( nsACString & aCharset )
{
aCharset . Truncate ( ) ;
nsresult rv ;
nsCAutoString charsetVal ;
nsCOMPtr < nsIChannel > channel ( do_QueryInterface ( mReadRequest ) ) ;
if ( ! channel ) {
channel = mChannel ;
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 ;
}
}
rv = channel - > GetContentCharset ( charsetVal ) ;
if ( NS_SUCCEEDED ( rv ) ) {
nsCOMPtr < nsICharsetAlias > calias ( do_GetService ( NS_CHARSETALIAS_CONTRACTID , & rv ) ) ;
if ( NS_SUCCEEDED ( rv ) & & calias ) {
rv = calias - > GetPreferred ( charsetVal , aCharset ) ;
}
}
return rv ;
}
nsresult
nsXMLHttpRequest : : ConvertBodyToText ( nsAString & aOutBuffer )
{
// This code here is basically a copy of a similar thing in
// nsScanner::Append(const char* aBuffer, PRUint32 aLen).
// If we get illegal characters in the input we replace
// them and don't just fail.
2010-04-23 10:37:02 -07:00
if ( ! mResponseBodyUnicode . IsVoid ( ) ) {
aOutBuffer = mResponseBodyUnicode ;
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
PRInt32 dataLen = mResponseBody . Length ( ) ;
2010-04-23 10:37:02 -07:00
if ( ! dataLen ) {
mResponseBodyUnicode . SetIsVoid ( PR_FALSE ) ;
2007-03-22 10:30:00 -07:00
return NS_OK ;
2010-04-23 10:37:02 -07:00
}
2007-03-22 10:30:00 -07:00
nsresult rv = NS_OK ;
nsCAutoString dataCharset ;
2008-10-11 23:30:14 -07:00
nsCOMPtr < nsIDocument > document ( do_QueryInterface ( mResponseXML ) ) ;
2007-03-22 10:30:00 -07:00
if ( document ) {
2008-08-28 05:56:45 -07:00
dataCharset = document - > GetDocumentCharacterSet ( ) ;
2007-03-22 10:30:00 -07:00
} else {
if ( NS_FAILED ( DetectCharset ( dataCharset ) ) | | dataCharset . IsEmpty ( ) ) {
// MS documentation states UTF-8 is default for responseText
dataCharset . AssignLiteral ( " UTF-8 " ) ;
}
}
2010-05-05 11:18:04 -07:00
// XXXbz is the charset ever "ASCII" as opposed to "us-ascii"?
2007-03-22 10:30:00 -07:00
if ( dataCharset . EqualsLiteral ( " ASCII " ) ) {
2010-04-23 10:37:02 -07:00
CopyASCIItoUTF16 ( mResponseBody , mResponseBodyUnicode ) ;
aOutBuffer = mResponseBodyUnicode ;
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
2010-05-05 11:18:04 -07:00
// can't fast-path UTF-8 using CopyUTF8toUTF16, since above we assumed UTF-8
// by default and CopyUTF8toUTF16 will stop if it encounters bytes that aren't
// valid UTF-8. So we have to do the whole unicode decoder thing.
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsICharsetConverterManager > ccm =
do_GetService ( NS_CHARSETCONVERTERMANAGER_CONTRACTID , & rv ) ;
if ( NS_FAILED ( rv ) )
return rv ;
nsCOMPtr < nsIUnicodeDecoder > decoder ;
rv = ccm - > GetUnicodeDecoderRaw ( dataCharset . get ( ) ,
getter_AddRefs ( decoder ) ) ;
if ( NS_FAILED ( rv ) )
return rv ;
const char * inBuffer = mResponseBody . get ( ) ;
PRInt32 outBufferLength ;
rv = decoder - > GetMaxLength ( inBuffer , dataLen , & outBufferLength ) ;
if ( NS_FAILED ( rv ) )
return rv ;
2010-11-23 08:49:12 -08:00
nsStringBuffer * buf =
nsStringBuffer : : Alloc ( ( outBufferLength + 1 ) * sizeof ( PRUnichar ) ) ;
if ( ! buf ) {
2007-03-22 10:30:00 -07:00
return NS_ERROR_OUT_OF_MEMORY ;
}
2010-11-23 08:49:12 -08:00
PRUnichar * outBuffer = static_cast < PRUnichar * > ( buf - > Data ( ) ) ;
2007-03-22 10:30:00 -07:00
PRInt32 totalChars = 0 ,
outBufferIndex = 0 ,
outLen = outBufferLength ;
do {
PRInt32 inBufferLength = dataLen ;
rv = decoder - > Convert ( inBuffer ,
& inBufferLength ,
& outBuffer [ outBufferIndex ] ,
& outLen ) ;
totalChars + = outLen ;
if ( NS_FAILED ( rv ) ) {
// We consume one byte, replace it with U+FFFD
// and try the conversion again.
outBuffer [ outBufferIndex + outLen + + ] = ( PRUnichar ) 0xFFFD ;
outBufferIndex + = outLen ;
outLen = outBufferLength - ( + + totalChars ) ;
decoder - > Reset ( ) ;
if ( ( inBufferLength + 1 ) > dataLen ) {
inBufferLength = dataLen ;
} else {
inBufferLength + + ;
}
inBuffer = & inBuffer [ inBufferLength ] ;
dataLen - = inBufferLength ;
}
} while ( NS_FAILED ( rv ) & & ( dataLen > 0 ) ) ;
2010-11-23 08:49:12 -08:00
// Use the string buffer if it is small, or doesn't contain
// too much extra data.
if ( outBufferLength < 127 | |
( outBufferLength * 0.9 ) < totalChars ) {
outBuffer [ totalChars ] = PRUnichar ( 0 ) ;
// Move ownership to mResponseBodyUnicode.
buf - > ToString ( totalChars , mResponseBodyUnicode , PR_TRUE ) ;
} else {
mResponseBodyUnicode . Assign ( outBuffer , totalChars ) ;
buf - > Release ( ) ;
}
2010-04-23 10:37:02 -07:00
aOutBuffer = mResponseBodyUnicode ;
2007-03-22 10:30:00 -07:00
return NS_OK ;
}
/* readonly attribute AString responseText; */
NS_IMETHODIMP nsXMLHttpRequest : : GetResponseText ( nsAString & aResponseText )
{
nsresult rv = NS_OK ;
aResponseText . Truncate ( ) ;
2011-05-10 16:18:55 -07:00
if ( mResponseType ! = XML_HTTP_RESPONSE_TYPE_DEFAULT & &
mResponseType ! = XML_HTTP_RESPONSE_TYPE_TEXT ) {
return NS_ERROR_DOM_INVALID_STATE_ERR ;
}
if ( mState & ( XML_HTTP_REQUEST_DONE |
XML_HTTP_REQUEST_LOADING ) ) {
2007-03-22 10:30:00 -07:00
rv = ConvertBodyToText ( aResponseText ) ;
}
return rv ;
}
2011-05-23 18:09:28 -07:00
nsresult nsXMLHttpRequest : : CreateResponseArrayBuffer ( JSContext * aCx )
2010-08-14 10:52:19 -07:00
{
2011-05-23 18:09:28 -07:00
if ( ! aCx )
2010-08-14 10:52:19 -07:00
return NS_ERROR_FAILURE ;
PRInt32 dataLen = mResponseBody . Length ( ) ;
2011-05-23 18:09:28 -07:00
RootResultArrayBuffer ( ) ;
mResultArrayBuffer = js_CreateArrayBuffer ( aCx , dataLen ) ;
if ( ! mResultArrayBuffer ) {
2010-08-14 10:52:19 -07:00
return NS_ERROR_FAILURE ;
2011-05-23 18:09:28 -07:00
}
2010-08-14 10:52:19 -07:00
if ( dataLen > 0 ) {
2011-05-23 18:09:28 -07:00
js : : ArrayBuffer * abuf = js : : ArrayBuffer : : fromJSObject ( mResultArrayBuffer ) ;
2010-08-14 10:52:19 -07:00
NS_ASSERTION ( abuf , " What happened? " ) ;
memcpy ( abuf - > data , mResponseBody . BeginReading ( ) , dataLen ) ;
}
return NS_OK ;
}
2011-05-10 16:18:55 -07:00
/* attribute AString responseType; */
2011-05-18 22:11:51 -07:00
NS_IMETHODIMP nsXMLHttpRequest : : GetResponseType ( nsAString & aResponseType )
2011-05-10 16:18:55 -07:00
{
switch ( mResponseType ) {
case XML_HTTP_RESPONSE_TYPE_DEFAULT :
aResponseType . Truncate ( ) ;
break ;
case XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER :
aResponseType . AssignLiteral ( " arraybuffer " ) ;
break ;
case XML_HTTP_RESPONSE_TYPE_BLOB :
aResponseType . AssignLiteral ( " blob " ) ;
break ;
case XML_HTTP_RESPONSE_TYPE_DOCUMENT :
aResponseType . AssignLiteral ( " document " ) ;
break ;
case XML_HTTP_RESPONSE_TYPE_TEXT :
aResponseType . AssignLiteral ( " text " ) ;
break ;
default :
NS_ERROR ( " Should not happen " ) ;
}
return NS_OK ;
}
/* attribute AString responseType; */
2011-05-18 22:11:51 -07:00
NS_IMETHODIMP nsXMLHttpRequest : : SetResponseType ( const nsAString & aResponseType )
2011-05-10 16:18:55 -07:00
{
// If the state is not OPENED or HEADERS_RECEIVED raise an
// INVALID_STATE_ERR exception and terminate these steps.
if ( ! ( mState & ( XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT |
XML_HTTP_REQUEST_HEADERS_RECEIVED ) ) )
return NS_ERROR_DOM_INVALID_STATE_ERR ;
// Set the responseType attribute's value to the given value.
if ( aResponseType . IsEmpty ( ) ) {
mResponseType = XML_HTTP_RESPONSE_TYPE_DEFAULT ;
} else if ( aResponseType . EqualsLiteral ( " arraybuffer " ) ) {
mResponseType = XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER ;
} else if ( aResponseType . EqualsLiteral ( " blob " ) ) {
mResponseType = XML_HTTP_RESPONSE_TYPE_BLOB ;
} else if ( aResponseType . EqualsLiteral ( " document " ) ) {
mResponseType = XML_HTTP_RESPONSE_TYPE_DOCUMENT ;
} else if ( aResponseType . EqualsLiteral ( " text " ) ) {
mResponseType = XML_HTTP_RESPONSE_TYPE_TEXT ;
}
// If the given value is not the empty string, "arraybuffer",
// "blob", "document", or "text" terminate these steps.
// If the state is OPENED, SetCacheAsFile would have no effect here
// because the channel hasn't initialized the cache entry yet.
// SetCacheAsFile will be called from OnStartRequest.
// If the state is HEADERS_RECEIVED, however, we need to call
// it immediately because OnStartRequest is already dispatched.
if ( mState & XML_HTTP_REQUEST_HEADERS_RECEIVED ) {
nsCOMPtr < nsICachingChannel > cc ( do_QueryInterface ( mChannel ) ) ;
if ( cc ) {
cc - > SetCacheAsFile ( mResponseType = = XML_HTTP_RESPONSE_TYPE_BLOB ) ;
}
}
return NS_OK ;
}
/* readonly attribute jsval response; */
2011-05-18 22:11:51 -07:00
NS_IMETHODIMP nsXMLHttpRequest : : GetResponse ( JSContext * aCx , jsval * aResult )
2011-05-10 16:18:55 -07:00
{
nsresult rv = NS_OK ;
switch ( mResponseType ) {
case XML_HTTP_RESPONSE_TYPE_DEFAULT :
case XML_HTTP_RESPONSE_TYPE_TEXT :
{
nsString str ;
rv = GetResponseText ( str ) ;
if ( NS_FAILED ( rv ) ) return rv ;
nsStringBuffer * buf ;
* aResult = XPCStringConvert : : ReadableToJSVal ( aCx , str , & buf ) ;
if ( buf ) {
str . ForgetSharedBuffer ( ) ;
}
}
break ;
case XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER :
if ( mState & XML_HTTP_REQUEST_DONE ) {
2011-05-23 18:09:28 -07:00
if ( ! mResultArrayBuffer ) {
rv = CreateResponseArrayBuffer ( aCx ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
}
* aResult = OBJECT_TO_JSVAL ( mResultArrayBuffer ) ;
2011-05-10 16:18:55 -07:00
} else {
* aResult = JSVAL_NULL ;
}
break ;
case XML_HTTP_RESPONSE_TYPE_BLOB :
if ( mState & XML_HTTP_REQUEST_DONE & & mResponseBlob ) {
JSObject * scope = JS_GetScopeChain ( aCx ) ;
rv = nsContentUtils : : WrapNative ( aCx , scope , mResponseBlob , aResult ,
nsnull , PR_TRUE ) ;
} else {
* aResult = JSVAL_NULL ;
}
break ;
case XML_HTTP_RESPONSE_TYPE_DOCUMENT :
if ( mState & XML_HTTP_REQUEST_DONE & & mResponseXML ) {
JSObject * scope = JS_GetScopeChain ( aCx ) ;
rv = nsContentUtils : : WrapNative ( aCx , scope , mResponseXML , aResult ,
nsnull , PR_TRUE ) ;
} else {
* aResult = JSVAL_NULL ;
}
break ;
default :
NS_ERROR ( " Should not happen " ) ;
}
return rv ;
}
2007-03-22 10:30:00 -07:00
/* readonly attribute unsigned long status; */
NS_IMETHODIMP
nsXMLHttpRequest : : GetStatus ( PRUint32 * aStatus )
{
2008-09-30 17:50:42 -07:00
* aStatus = 0 ;
if ( mState & XML_HTTP_REQUEST_USE_XSITE_AC ) {
// Make sure we don't leak status information from denied cross-site
// requests.
if ( mChannel ) {
nsresult status ;
mChannel - > GetStatus ( & status ) ;
if ( NS_FAILED ( status ) ) {
return NS_OK ;
}
}
}
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsIHttpChannel > httpChannel = GetCurrentHttpChannel ( ) ;
if ( httpChannel ) {
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
2008-03-21 22:09:41 -07:00
// errored before we got any data; return 0 in that case.
2011-05-10 16:18:55 -07:00
PRUint16 readyState ;
2007-03-22 10:30:00 -07:00
GetReadyState ( & readyState ) ;
2011-05-10 16:18:55 -07:00
if ( readyState > = LOADING ) {
2008-03-21 22:09:41 -07:00
* aStatus = 0 ;
2007-03-22 10:30:00 -07:00
return NS_OK ;
}
}
return rv ;
}
return NS_OK ;
}
/* readonly attribute AUTF8String statusText; */
NS_IMETHODIMP
nsXMLHttpRequest : : GetStatusText ( nsACString & aStatusText )
{
nsCOMPtr < nsIHttpChannel > httpChannel = GetCurrentHttpChannel ( ) ;
aStatusText . Truncate ( ) ;
if ( httpChannel ) {
2010-03-16 16:23:45 -07:00
if ( mState & XML_HTTP_REQUEST_USE_XSITE_AC ) {
// Make sure we don't leak status information from denied cross-site
// requests.
if ( mChannel ) {
nsresult status ;
mChannel - > GetStatus ( & status ) ;
if ( NS_FAILED ( status ) ) {
2010-11-11 13:39:14 -08:00
return NS_OK ;
2010-03-16 16:23:45 -07:00
}
}
}
2010-11-11 13:39:14 -08:00
httpChannel - > GetResponseStatusText ( aStatusText ) ;
2007-03-22 10:30:00 -07:00
}
2010-11-11 13:39:14 -08:00
return NS_OK ;
2007-03-22 10:30:00 -07:00
}
/* void abort (); */
NS_IMETHODIMP
nsXMLHttpRequest : : Abort ( )
{
if ( mReadRequest ) {
mReadRequest - > Cancel ( NS_BINDING_ABORTED ) ;
}
if ( mChannel ) {
mChannel - > Cancel ( NS_BINDING_ABORTED ) ;
}
2011-03-28 13:18:45 -07:00
if ( mCORSPreflightChannel ) {
mCORSPreflightChannel - > Cancel ( NS_BINDING_ABORTED ) ;
2008-09-30 17:49:30 -07:00
}
2008-10-11 23:30:14 -07:00
mResponseXML = nsnull ;
2008-10-19 14:26:37 -07:00
PRUint32 responseLength = mResponseBody . Length ( ) ;
2008-02-06 21:03:01 -08:00
mResponseBody . Truncate ( ) ;
2010-04-23 10:37:02 -07:00
mResponseBodyUnicode . SetIsVoid ( PR_TRUE ) ;
2011-05-10 16:18:55 -07:00
mResponseBlob = nsnull ;
2007-03-22 10:30:00 -07:00
mState | = XML_HTTP_REQUEST_ABORTED ;
2011-05-23 18:09:28 -07:00
mResultArrayBuffer = nsnull ;
2011-05-10 16:18:55 -07:00
if ( ! ( mState & ( XML_HTTP_REQUEST_UNSENT |
2008-02-06 21:03:01 -08:00
XML_HTTP_REQUEST_OPENED |
2011-05-10 16:18:55 -07:00
XML_HTTP_REQUEST_DONE ) ) ) {
ChangeState ( XML_HTTP_REQUEST_DONE , PR_TRUE ) ;
2008-02-06 21:03:01 -08:00
}
2007-03-22 10:30:00 -07:00
2008-08-14 04:07:46 -07:00
if ( ! ( mState & XML_HTTP_REQUEST_SYNCLOOPING ) ) {
NS_NAMED_LITERAL_STRING ( abortStr , ABORT_STR ) ;
2008-10-19 14:26:37 -07:00
DispatchProgressEvent ( this , abortStr , mLoadLengthComputable , responseLength ,
mLoadTotal ) ;
2008-08-14 04:07:46 -07:00
if ( mUpload & & ! mUploadComplete ) {
mUploadComplete = PR_TRUE ;
DispatchProgressEvent ( mUpload , abortStr , PR_TRUE , mUploadTransferred ,
mUploadTotal ) ;
}
}
2007-03-22 10:30:00 -07:00
// The ChangeState call above calls onreadystatechange handlers which
2011-03-28 13:05:52 -07:00
// if they load a new url will cause nsXMLHttpRequest::Open to clear
2007-03-22 10:30:00 -07:00
// the abort state bit. If this occurs we're not uninitialized (bug 361773).
if ( mState & XML_HTTP_REQUEST_ABORTED ) {
2011-05-10 16:18:55 -07:00
ChangeState ( XML_HTTP_REQUEST_UNSENT , PR_FALSE ) ; // IE seems to do it
2007-03-22 10:30:00 -07:00
}
2008-08-25 10:21:28 -07:00
mState & = ~ XML_HTTP_REQUEST_SYNCLOOPING ;
2007-03-22 10:30:00 -07:00
return NS_OK ;
}
/* string getAllResponseHeaders (); */
NS_IMETHODIMP
nsXMLHttpRequest : : GetAllResponseHeaders ( char * * _retval )
{
NS_ENSURE_ARG_POINTER ( _retval ) ;
* _retval = nsnull ;
2008-09-30 17:49:30 -07:00
if ( mState & XML_HTTP_REQUEST_USE_XSITE_AC ) {
2010-11-11 13:39:14 -08:00
* _retval = ToNewCString ( EmptyString ( ) ) ;
2008-09-30 17:49:30 -07:00
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsIHttpChannel > httpChannel = GetCurrentHttpChannel ( ) ;
if ( httpChannel ) {
2010-11-11 13:39:14 -08:00
nsRefPtr < nsHeaderVisitor > visitor = new nsHeaderVisitor ( ) ;
2007-03-22 10:30:00 -07:00
nsresult rv = httpChannel - > VisitResponseHeaders ( visitor ) ;
if ( NS_SUCCEEDED ( rv ) )
* _retval = ToNewCString ( visitor - > Headers ( ) ) ;
2010-11-11 13:39:14 -08:00
}
if ( ! * _retval ) {
* _retval = ToNewCString ( EmptyString ( ) ) ;
2007-03-22 10:30:00 -07:00
}
return NS_OK ;
}
/* ACString getResponseHeader (in AUTF8String header); */
NS_IMETHODIMP
nsXMLHttpRequest : : GetResponseHeader ( const nsACString & header ,
nsACString & _retval )
{
nsresult rv = NS_OK ;
2010-10-04 18:25:44 -07:00
_retval . SetIsVoid ( PR_TRUE ) ;
nsCOMPtr < nsIHttpChannel > httpChannel = GetCurrentHttpChannel ( ) ;
if ( ! httpChannel ) {
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
2008-11-13 18:18:01 -08:00
// See bug #380418. Hide "Set-Cookie" headers from non-chrome scripts.
PRBool chrome = PR_FALSE ; // default to false in case IsCapabilityEnabled fails
IsCapabilityEnabled ( " UniversalXPConnect " , & chrome ) ;
if ( ! chrome & &
( header . LowerCaseEqualsASCII ( " set-cookie " ) | |
header . LowerCaseEqualsASCII ( " set-cookie2 " ) ) ) {
NS_WARNING ( " blocked access to response header " ) ;
return NS_OK ;
}
2008-09-30 17:49:30 -07:00
// Check for dangerous headers
if ( mState & XML_HTTP_REQUEST_USE_XSITE_AC ) {
// Make sure we don't leak header information from denied cross-site
// requests.
if ( mChannel ) {
nsresult status ;
mChannel - > GetStatus ( & status ) ;
if ( NS_FAILED ( status ) ) {
return NS_OK ;
}
}
const char * kCrossOriginSafeHeaders [ ] = {
" cache-control " , " content-language " , " content-type " , " expires " ,
" last-modified " , " pragma "
} ;
PRBool safeHeader = PR_FALSE ;
PRUint32 i ;
for ( i = 0 ; i < NS_ARRAY_LENGTH ( kCrossOriginSafeHeaders ) ; + + i ) {
if ( header . LowerCaseEqualsASCII ( kCrossOriginSafeHeaders [ i ] ) ) {
safeHeader = PR_TRUE ;
break ;
}
}
if ( ! safeHeader ) {
2010-10-04 18:25:44 -07:00
nsCAutoString headerVal ;
// The "Access-Control-Expose-Headers" header contains a comma separated
// list of method names.
httpChannel - >
GetResponseHeader ( NS_LITERAL_CSTRING ( " Access-Control-Expose-Headers " ) ,
headerVal ) ;
nsCCharSeparatedTokenizer exposeTokens ( headerVal , ' , ' ) ;
while ( exposeTokens . hasMoreTokens ( ) ) {
const nsDependentCSubstring & token = exposeTokens . nextToken ( ) ;
if ( token . IsEmpty ( ) ) {
continue ;
}
if ( ! IsValidHTTPToken ( token ) ) {
return NS_OK ;
}
if ( header . Equals ( token , nsCaseInsensitiveCStringComparator ( ) ) ) {
safeHeader = PR_TRUE ;
}
}
2008-09-30 17:49:30 -07:00
}
2007-03-22 10:30:00 -07:00
2010-10-04 18:25:44 -07:00
if ( ! safeHeader ) {
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
}
2010-10-04 18:25:44 -07:00
rv = httpChannel - > GetResponseHeader ( header , _retval ) ;
2007-03-22 10:30:00 -07:00
if ( rv = = NS_ERROR_NOT_AVAILABLE ) {
// Means no header
_retval . SetIsVoid ( PR_TRUE ) ;
rv = NS_OK ;
}
return rv ;
}
2008-10-14 17:12:28 -07:00
nsresult
nsXMLHttpRequest : : GetLoadGroup ( nsILoadGroup * * aLoadGroup )
{
NS_ENSURE_ARG_POINTER ( aLoadGroup ) ;
* aLoadGroup = nsnull ;
if ( mState & XML_HTTP_REQUEST_BACKGROUND ) {
return NS_OK ;
}
2009-06-15 01:27:29 -07:00
nsCOMPtr < nsIDocument > doc =
nsContentUtils : : GetDocumentFromScriptContext ( mScriptContext ) ;
2008-10-14 17:12:28 -07:00
if ( doc ) {
* aLoadGroup = doc - > GetDocumentLoadGroup ( ) . get ( ) ; // already_AddRefed
}
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
nsresult
2008-08-14 04:07:46 -07:00
nsXMLHttpRequest : : CreateReadystatechangeEvent ( nsIDOMEvent * * aDOMEvent )
2007-03-22 10:30:00 -07:00
{
nsresult rv = nsEventDispatcher : : CreateEvent ( nsnull , nsnull ,
NS_LITERAL_STRING ( " Events " ) ,
aDOMEvent ) ;
if ( NS_FAILED ( rv ) ) {
return rv ;
}
nsCOMPtr < nsIPrivateDOMEvent > privevent ( do_QueryInterface ( * aDOMEvent ) ) ;
if ( ! privevent ) {
NS_IF_RELEASE ( * aDOMEvent ) ;
return NS_ERROR_FAILURE ;
}
2008-08-14 04:07:46 -07:00
( * aDOMEvent ) - > InitEvent ( NS_LITERAL_STRING ( READYSTATE_STR ) ,
PR_FALSE , PR_FALSE ) ;
2007-03-22 10:30:00 -07:00
2008-08-14 04:07:46 -07:00
// We assume anyone who managed to call CreateReadystatechangeEvent is trusted
2007-03-22 10:30:00 -07:00
privevent - > SetTrusted ( PR_TRUE ) ;
return NS_OK ;
}
2008-08-14 04:07:46 -07:00
void
nsXMLHttpRequest : : DispatchProgressEvent ( nsPIDOMEventTarget * aTarget ,
const nsAString & aType ,
PRBool aUseLSEventWrapper ,
PRBool aLengthComputable ,
PRUint64 aLoaded , PRUint64 aTotal ,
PRUint64 aPosition , PRUint64 aTotalSize )
{
2008-09-30 17:51:53 -07:00
NS_ASSERTION ( aTarget , " null target " ) ;
if ( aType . IsEmpty ( ) | |
( ! AllowUploadProgress ( ) & &
( aTarget = = mUpload | | aType . EqualsLiteral ( UPLOADPROGRESS_STR ) ) ) ) {
2008-08-14 04:07:46 -07:00
return ;
}
2011-03-24 06:22:03 -07:00
PRBool dispatchLoadend = aType . EqualsLiteral ( LOAD_STR ) | |
aType . EqualsLiteral ( ERROR_STR ) | |
aType . EqualsLiteral ( ABORT_STR ) ;
2008-08-14 04:07:46 -07:00
nsCOMPtr < nsIDOMEvent > event ;
nsresult rv = nsEventDispatcher : : CreateEvent ( nsnull , nsnull ,
NS_LITERAL_STRING ( " ProgressEvent " ) ,
getter_AddRefs ( event ) ) ;
if ( NS_FAILED ( rv ) ) {
return ;
}
nsCOMPtr < nsIPrivateDOMEvent > privevent ( do_QueryInterface ( event ) ) ;
if ( ! privevent ) {
return ;
}
privevent - > SetTrusted ( PR_TRUE ) ;
nsCOMPtr < nsIDOMProgressEvent > progress = do_QueryInterface ( event ) ;
if ( ! progress ) {
return ;
}
progress - > InitProgressEvent ( aType , PR_FALSE , PR_FALSE , aLengthComputable ,
aLoaded , ( aTotal = = LL_MAXUINT ) ? 0 : aTotal ) ;
if ( aUseLSEventWrapper ) {
nsCOMPtr < nsIDOMProgressEvent > xhrprogressEvent =
new nsXMLHttpProgressEvent ( progress , aPosition , aTotalSize ) ;
if ( ! xhrprogressEvent ) {
return ;
}
event = xhrprogressEvent ;
}
aTarget - > DispatchDOMEvent ( nsnull , event , nsnull , nsnull ) ;
2011-03-24 06:22:03 -07:00
if ( dispatchLoadend ) {
DispatchProgressEvent ( aTarget , NS_LITERAL_STRING ( LOADEND_STR ) ,
aUseLSEventWrapper , aLengthComputable ,
aLoaded , aTotal , aPosition , aTotalSize ) ;
}
2008-08-14 04:07:46 -07:00
}
2011-03-24 06:22:03 -07:00
2007-03-22 10:30:00 -07:00
already_AddRefed < nsIHttpChannel >
nsXMLHttpRequest : : GetCurrentHttpChannel ( )
{
nsIHttpChannel * httpChannel = nsnull ;
if ( mReadRequest ) {
CallQueryInterface ( mReadRequest , & httpChannel ) ;
}
if ( ! httpChannel & & mChannel ) {
CallQueryInterface ( mChannel , & httpChannel ) ;
}
return httpChannel ;
}
2008-09-30 17:49:30 -07:00
nsresult
nsXMLHttpRequest : : CheckChannelForCrossSiteRequest ( nsIChannel * aChannel )
{
2011-03-17 09:19:13 -07:00
// First check if cross-site requests are enabled...
if ( IsSystemXHR ( ) ) {
2010-06-17 04:27:52 -07:00
return NS_OK ;
}
2011-03-17 09:19:13 -07:00
// ...or if this is a same-origin request.
2010-06-17 04:27:52 -07:00
if ( nsContentUtils : : CheckMayLoad ( mPrincipal , aChannel ) ) {
2008-09-30 17:49:30 -07:00
return NS_OK ;
}
// This is a cross-site request
mState | = XML_HTTP_REQUEST_USE_XSITE_AC ;
2009-02-24 11:46:51 -08:00
// Check if we need to do a preflight request.
nsCOMPtr < nsIHttpChannel > httpChannel = do_QueryInterface ( aChannel ) ;
NS_ENSURE_TRUE ( httpChannel , NS_ERROR_DOM_BAD_URI ) ;
nsCAutoString method ;
httpChannel - > GetRequestMethod ( method ) ;
2011-03-28 13:18:45 -07:00
if ( ! mCORSUnsafeHeaders . IsEmpty ( ) | |
2009-02-24 11:46:51 -08:00
HasListenersFor ( NS_LITERAL_STRING ( UPLOADPROGRESS_STR ) ) | |
2010-10-04 17:41:07 -07:00
( mUpload & & mUpload - > HasListeners ( ) ) | |
( ! method . LowerCaseEqualsLiteral ( " get " ) & &
! method . LowerCaseEqualsLiteral ( " post " ) & &
! method . LowerCaseEqualsLiteral ( " head " ) ) ) {
2009-02-24 11:46:51 -08:00
mState | = XML_HTTP_REQUEST_NEED_AC_PREFLIGHT ;
}
2008-09-30 17:49:30 -07:00
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
NS_IMETHODIMP
2011-03-28 13:05:52 -07:00
nsXMLHttpRequest : : Open ( const nsACString & method , const nsACString & url ,
PRBool async , const nsAString & user ,
const nsAString & password , PRUint8 optional_argc )
2007-03-22 10:30:00 -07:00
{
NS_ENSURE_ARG ( ! method . IsEmpty ( ) ) ;
2011-03-28 13:05:52 -07:00
if ( ! optional_argc ) {
// No optional arguments were passed in. Default async to true.
async = PR_TRUE ;
}
2008-02-19 15:12:23 -08:00
NS_ENSURE_TRUE ( mPrincipal , NS_ERROR_NOT_INITIALIZED ) ;
2007-06-26 02:28:38 -07:00
// Disallow HTTP/1.1 TRACE method (see bug 302489)
// and MS IIS equivalent TRACK (see bug 381264)
2007-07-26 19:49:18 -07:00
if ( method . LowerCaseEqualsLiteral ( " trace " ) | |
method . LowerCaseEqualsLiteral ( " track " ) ) {
2007-03-22 10:30:00 -07:00
return NS_ERROR_INVALID_ARG ;
}
nsresult rv ;
nsCOMPtr < nsIURI > uri ;
PRBool authp = PR_FALSE ;
2007-11-15 14:18:36 -08:00
if ( mState & ( XML_HTTP_REQUEST_OPENED |
2011-05-10 16:18:55 -07:00
XML_HTTP_REQUEST_HEADERS_RECEIVED |
XML_HTTP_REQUEST_LOADING |
2007-11-15 14:18:36 -08:00
XML_HTTP_REQUEST_SENT |
XML_HTTP_REQUEST_STOPPED ) ) {
2007-03-22 10:30:00 -07:00
// IE aborts as well
Abort ( ) ;
// 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.
2007-11-15 14:18:36 -08:00
}
2007-03-22 10:30:00 -07:00
2007-11-15 14:18:36 -08:00
if ( mState & XML_HTTP_REQUEST_ABORTED ) {
// 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 ;
2007-03-22 10:30:00 -07:00
}
if ( async ) {
mState | = XML_HTTP_REQUEST_ASYNC ;
} else {
mState & = ~ XML_HTTP_REQUEST_ASYNC ;
}
2008-09-11 03:44:15 -07:00
mState & = ~ XML_HTTP_REQUEST_MPART_HEADERS ;
2009-06-15 01:27:29 -07:00
nsCOMPtr < nsIDocument > doc =
nsContentUtils : : GetDocumentFromScriptContext ( mScriptContext ) ;
2008-10-11 23:30:14 -07:00
nsCOMPtr < nsIURI > baseURI ;
2008-12-30 14:24:58 -08:00
if ( mBaseURI ) {
baseURI = mBaseURI ;
}
else if ( doc ) {
2008-10-11 23:30:14 -07:00
baseURI = doc - > GetBaseURI ( ) ;
}
rv = NS_NewURI ( getter_AddRefs ( uri ) , url , nsnull , baseURI ) ;
2007-03-22 10:30:00 -07:00
if ( NS_FAILED ( rv ) ) return rv ;
2007-03-24 22:35:39 -07:00
// mScriptContext should be initialized because of GetBaseURI() above.
// Still need to consider the case that doc is nsnull however.
2007-12-12 00:33:32 -08:00
rv = CheckInnerWindowCorrectness ( ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2007-03-24 22:35:39 -07:00
PRInt16 shouldLoad = nsIContentPolicy : : ACCEPT ;
2007-06-17 06:50:50 -07:00
rv = NS_CheckContentLoadPolicy ( nsIContentPolicy : : TYPE_XMLHTTPREQUEST ,
2007-03-24 22:35:39 -07:00
uri ,
2007-12-12 00:33:32 -08:00
mPrincipal ,
2007-03-24 22:35:39 -07:00
doc ,
EmptyCString ( ) , //mime guess
nsnull , //extra
2007-08-07 18:16:09 -07:00
& shouldLoad ,
nsContentUtils : : GetContentPolicy ( ) ,
nsContentUtils : : GetSecurityManager ( ) ) ;
2007-03-24 22:35:39 -07:00
if ( NS_FAILED ( rv ) ) return rv ;
if ( NS_CP_REJECTED ( shouldLoad ) ) {
// Disallowed by content policy
return NS_ERROR_CONTENT_BLOCKED ;
}
2007-03-22 10:30:00 -07:00
if ( ! user . IsEmpty ( ) ) {
nsCAutoString userpass ;
CopyUTF16toUTF8 ( user , userpass ) ;
if ( ! password . IsEmpty ( ) ) {
userpass . Append ( ' : ' ) ;
AppendUTF16toUTF8 ( password , userpass ) ;
}
uri - > SetUserPass ( userpass ) ;
authp = PR_TRUE ;
}
2008-10-14 17:12:28 -07: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.
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsILoadGroup > loadGroup ;
2008-10-14 17:12:28 -07:00
GetLoadGroup ( getter_AddRefs ( loadGroup ) ) ;
2007-03-22 10:30:00 -07:00
2010-04-23 12:54:09 -07:00
// get Content Security Policy from principal to pass into channel
nsCOMPtr < nsIChannelPolicy > channelPolicy ;
nsCOMPtr < nsIContentSecurityPolicy > csp ;
2010-04-26 12:14:49 -07:00
rv = mPrincipal - > GetCsp ( getter_AddRefs ( csp ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2010-04-23 12:54:09 -07:00
if ( csp ) {
channelPolicy = do_CreateInstance ( " @mozilla.org/nschannelpolicy;1 " ) ;
channelPolicy - > SetContentSecurityPolicy ( csp ) ;
channelPolicy - > SetLoadType ( nsIContentPolicy : : TYPE_XMLHTTPREQUEST ) ;
}
rv = NS_NewChannel ( getter_AddRefs ( mChannel ) ,
uri ,
nsnull , // ioService
loadGroup ,
nsnull , // callbacks
2010-09-08 10:42:08 -07:00
nsIRequest : : LOAD_BACKGROUND ,
2010-04-23 12:54:09 -07:00
channelPolicy ) ;
2008-10-14 17:12:28 -07:00
if ( NS_FAILED ( rv ) ) return rv ;
2007-03-22 10:30:00 -07:00
2009-02-24 11:46:51 -08:00
mState & = ~ ( XML_HTTP_REQUEST_USE_XSITE_AC |
XML_HTTP_REQUEST_NEED_AC_PREFLIGHT ) ;
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsIHttpChannel > httpChannel ( do_QueryInterface ( mChannel ) ) ;
if ( httpChannel ) {
rv = httpChannel - > SetRequestMethod ( method ) ;
2007-07-26 19:49:18 -07:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2007-03-22 10:30:00 -07:00
}
ChangeState ( XML_HTTP_REQUEST_OPENED ) ;
return rv ;
}
/*
* " Copy " from a stream .
*/
NS_METHOD
nsXMLHttpRequest : : StreamReaderFunc ( nsIInputStream * in ,
void * closure ,
const char * fromRawSegment ,
PRUint32 toOffset ,
PRUint32 count ,
PRUint32 * writeCount )
{
2007-07-08 00:08:04 -07:00
nsXMLHttpRequest * xmlHttpRequest = static_cast < nsXMLHttpRequest * > ( closure ) ;
2007-03-22 10:30:00 -07:00
if ( ! xmlHttpRequest | | ! writeCount ) {
NS_WARNING ( " XMLHttpRequest cannot read from stream: no closure or writeCount " ) ;
return NS_ERROR_FAILURE ;
}
2011-05-10 16:18:55 -07:00
if ( xmlHttpRequest - > mResponseType = = XML_HTTP_RESPONSE_TYPE_BLOB & &
xmlHttpRequest - > mResponseBlob ) {
xmlHttpRequest - > ChangeState ( XML_HTTP_REQUEST_LOADING ) ;
* writeCount = count ;
return NS_OK ;
}
if ( xmlHttpRequest - > mResponseType ! = XML_HTTP_RESPONSE_TYPE_DOCUMENT ) {
// Copy for our own use
PRUint32 previousLength = xmlHttpRequest - > mResponseBody . Length ( ) ;
xmlHttpRequest - > mResponseBody . Append ( fromRawSegment , count ) ;
if ( count > 0 & & xmlHttpRequest - > mResponseBody . Length ( ) = = previousLength ) {
return NS_ERROR_OUT_OF_MEMORY ;
}
xmlHttpRequest - > mResponseBodyUnicode . SetIsVoid ( PR_TRUE ) ;
}
2007-03-22 10:30:00 -07:00
nsresult rv = NS_OK ;
if ( xmlHttpRequest - > mState & XML_HTTP_REQUEST_PARSEBODY ) {
// Give the same data to the parser.
// 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.
nsCOMPtr < nsIInputStream > copyStream ;
rv = NS_NewByteInputStream ( getter_AddRefs ( copyStream ) , fromRawSegment , count ) ;
2009-06-15 03:11:04 -07:00
if ( NS_SUCCEEDED ( rv ) & & xmlHttpRequest - > mXMLParserStreamListener ) {
2007-03-22 10:30:00 -07:00
NS_ASSERTION ( copyStream , " NS_NewByteInputStream lied " ) ;
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 ;
}
}
}
2011-05-10 16:18:55 -07:00
xmlHttpRequest - > ChangeState ( XML_HTTP_REQUEST_LOADING ) ;
2007-03-22 10:30:00 -07:00
if ( NS_SUCCEEDED ( rv ) ) {
* writeCount = count ;
} else {
* writeCount = 0 ;
}
return rv ;
}
2011-05-10 16:18:55 -07:00
void nsXMLHttpRequest : : CreateResponseBlob ( nsIRequest * request )
{
nsCOMPtr < nsIFile > file ;
nsCOMPtr < nsICachingChannel > cc ( do_QueryInterface ( request ) ) ;
if ( cc ) {
cc - > GetCacheFile ( getter_AddRefs ( file ) ) ;
if ( ! file ) {
// cacheAsFile returns false if caching is inhibited
PRBool cacheAsFile = PR_FALSE ;
if ( NS_SUCCEEDED ( cc - > GetCacheAsFile ( & cacheAsFile ) ) & & cacheAsFile ) {
}
}
} else {
nsCOMPtr < nsIFileChannel > fc = do_QueryInterface ( request ) ;
if ( fc ) {
fc - > GetFile ( getter_AddRefs ( file ) ) ;
}
}
if ( file ) {
nsCAutoString contentType ;
mChannel - > GetContentType ( contentType ) ;
mResponseBlob = new nsDOMFile ( file ,
NS_ConvertASCIItoUTF16 ( contentType ) ) ;
mResponseBody . Truncate ( ) ;
mResponseBodyUnicode . SetIsVoid ( PR_TRUE ) ;
}
}
2007-03-22 10:30:00 -07:00
/* void onDataAvailable (in nsIRequest request, in nsISupports ctxt, in nsIInputStream inStr, in unsigned long sourceOffset, in unsigned long count); */
NS_IMETHODIMP
nsXMLHttpRequest : : OnDataAvailable ( nsIRequest * request , nsISupports * ctxt , nsIInputStream * inStr , PRUint32 sourceOffset , PRUint32 count )
{
NS_ENSURE_ARG_POINTER ( inStr ) ;
NS_ABORT_IF_FALSE ( mContext . get ( ) = = ctxt , " start context different from OnDataAvailable context " ) ;
2011-05-10 16:18:55 -07:00
if ( mResponseType = = XML_HTTP_RESPONSE_TYPE_BLOB & & ! mResponseBlob ) {
CreateResponseBlob ( request ) ;
}
2007-03-22 10:30:00 -07:00
PRUint32 totalRead ;
return inStr - > ReadSegments ( nsXMLHttpRequest : : StreamReaderFunc , ( void * ) this , count , & totalRead ) ;
}
2007-09-05 20:51:56 -07:00
PRBool
IsSameOrBaseChannel ( nsIRequest * aPossibleBase , nsIChannel * aChannel )
{
nsCOMPtr < nsIMultiPartChannel > mpChannel = do_QueryInterface ( aPossibleBase ) ;
if ( mpChannel ) {
nsCOMPtr < nsIChannel > baseChannel ;
nsresult rv = mpChannel - > GetBaseChannel ( getter_AddRefs ( baseChannel ) ) ;
NS_ENSURE_SUCCESS ( rv , PR_FALSE ) ;
return baseChannel = = aChannel ;
}
return aPossibleBase = = aChannel ;
}
2007-03-22 10:30:00 -07:00
/* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
NS_IMETHODIMP
nsXMLHttpRequest : : OnStartRequest ( nsIRequest * request , nsISupports * ctxt )
{
2008-10-19 14:26:37 -07:00
nsresult rv = NS_OK ;
2008-09-30 16:56:57 -07:00
if ( ! mFirstStartRequestSeen & & mRequestObserver ) {
mFirstStartRequestSeen = PR_TRUE ;
mRequestObserver - > OnStartRequest ( request , ctxt ) ;
}
2007-09-05 20:51:56 -07:00
if ( ! IsSameOrBaseChannel ( request , mChannel ) ) {
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
// Don't do anything if we have been aborted
2011-05-10 16:18:55 -07:00
if ( mState & XML_HTTP_REQUEST_UNSENT )
2007-03-22 10:30:00 -07:00
return NS_OK ;
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 ) ;
2011-03-17 09:19:13 -07:00
nsCOMPtr < nsIPrincipal > documentPrincipal ;
if ( IsSystemXHR ( ) ) {
2008-03-27 20:46:15 -07:00
// Don't give this document the system principal. We need to keep track of
// mPrincipal being system because we use it for various security checks
// that should be passing, but the document data shouldn't get a system
// principal.
nsresult rv ;
documentPrincipal = do_CreateInstance ( " @mozilla.org/nullprincipal;1 " , & rv ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2011-03-17 09:19:13 -07:00
} else {
documentPrincipal = mPrincipal ;
2008-03-27 20:46:15 -07:00
}
channel - > SetOwner ( documentPrincipal ) ;
2007-07-02 06:20:01 -07:00
2007-03-22 10:30:00 -07:00
mReadRequest = request ;
mContext = ctxt ;
mState | = XML_HTTP_REQUEST_PARSEBODY ;
2008-09-11 03:44:15 -07:00
mState & = ~ XML_HTTP_REQUEST_MPART_HEADERS ;
2011-05-10 16:18:55 -07:00
ChangeState ( XML_HTTP_REQUEST_HEADERS_RECEIVED ) ;
if ( mResponseType = = XML_HTTP_RESPONSE_TYPE_BLOB ) {
nsCOMPtr < nsICachingChannel > cc ( do_QueryInterface ( mChannel ) ) ;
if ( cc ) {
cc - > SetCacheAsFile ( PR_TRUE ) ;
}
}
2007-03-22 10:30:00 -07:00
nsresult status ;
request - > GetStatus ( & status ) ;
2008-08-14 04:07:46 -07:00
mErrorLoad = mErrorLoad | | NS_FAILED ( status ) ;
2009-03-03 12:11:14 -08:00
if ( mUpload & & ! mUploadComplete & & ! mErrorLoad & &
( mState & XML_HTTP_REQUEST_ASYNC ) ) {
2008-08-14 04:07:46 -07:00
mUploadComplete = PR_TRUE ;
DispatchProgressEvent ( mUpload , NS_LITERAL_STRING ( LOAD_STR ) ,
PR_TRUE , mUploadTotal , mUploadTotal ) ;
}
2007-03-22 10:30:00 -07:00
2008-10-11 23:30:14 -07:00
// Reset responseBody
mResponseBody . Truncate ( ) ;
2010-04-23 10:37:02 -07:00
mResponseBodyUnicode . SetIsVoid ( PR_TRUE ) ;
2011-05-10 16:18:55 -07:00
mResponseBlob = nsnull ;
2008-10-11 23:30:14 -07:00
// Set up responseXML
2011-05-10 16:18:55 -07:00
PRBool parseBody = mResponseType = = XML_HTTP_RESPONSE_TYPE_DEFAULT | |
mResponseType = = XML_HTTP_RESPONSE_TYPE_DOCUMENT ;
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsIHttpChannel > httpChannel ( do_QueryInterface ( mChannel ) ) ;
2011-05-10 16:18:55 -07:00
if ( parseBody & & httpChannel ) {
2007-03-22 10:30:00 -07:00
nsCAutoString method ;
httpChannel - > GetRequestMethod ( method ) ;
parseBody = ! method . EqualsLiteral ( " HEAD " ) ;
}
if ( parseBody & & NS_SUCCEEDED ( status ) ) {
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.
nsCAutoString type ;
channel - > GetContentType ( type ) ;
if ( type . Find ( " xml " ) = = kNotFound ) {
mState & = ~ XML_HTTP_REQUEST_PARSEBODY ;
}
} else {
// The request failed, so we shouldn't be parsing anyway
mState & = ~ XML_HTTP_REQUEST_PARSEBODY ;
}
if ( mState & XML_HTTP_REQUEST_PARSEBODY ) {
2008-10-11 23:30:14 -07:00
nsCOMPtr < nsIURI > baseURI , docURI ;
2009-06-15 01:27:29 -07:00
nsCOMPtr < nsIDocument > doc =
nsContentUtils : : GetDocumentFromScriptContext ( mScriptContext ) ;
2008-10-11 23:30:14 -07:00
if ( doc ) {
docURI = doc - > GetDocumentURI ( ) ;
baseURI = doc - > GetBaseURI ( ) ;
}
// Create an empty document from it. Here we have to cheat a little bit...
// Setting the base URI to |baseURI| won't work if the document has a null
// principal, so use mPrincipal when creating the document, then reset the
// principal.
const nsAString & emptyStr = EmptyString ( ) ;
nsCOMPtr < nsIScriptGlobalObject > global = do_QueryInterface ( mOwner ) ;
rv = nsContentUtils : : CreateDocument ( emptyStr , emptyStr , nsnull , docURI ,
baseURI , mPrincipal , global ,
getter_AddRefs ( mResponseXML ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
nsCOMPtr < nsIDocument > responseDoc = do_QueryInterface ( mResponseXML ) ;
responseDoc - > SetPrincipal ( documentPrincipal ) ;
2011-03-17 09:19:13 -07:00
if ( IsSystemXHR ( ) ) {
2010-08-25 13:12:28 -07:00
responseDoc - > ForceEnableXULXBL ( ) ;
}
2008-10-11 23:30:14 -07:00
if ( mState & XML_HTTP_REQUEST_USE_XSITE_AC ) {
nsCOMPtr < nsIHTMLDocument > htmlDoc = do_QueryInterface ( mResponseXML ) ;
if ( htmlDoc ) {
htmlDoc - > DisableCookieAccess ( ) ;
}
}
// Register as a load listener on the document
nsCOMPtr < nsPIDOMEventTarget > target ( do_QueryInterface ( mResponseXML ) ) ;
if ( target ) {
nsWeakPtr requestWeak =
do_GetWeakReference ( static_cast < nsIXMLHttpRequest * > ( this ) ) ;
nsCOMPtr < nsIDOMEventListener > proxy = new nsLoadListenerProxy ( requestWeak ) ;
if ( ! proxy ) return NS_ERROR_OUT_OF_MEMORY ;
// This will addref the proxy
rv = target - > AddEventListenerByIID ( static_cast < nsIDOMEventListener * >
( proxy ) ,
NS_GET_IID ( nsIDOMLoadListener ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
}
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsIStreamListener > listener ;
nsCOMPtr < nsILoadGroup > loadGroup ;
channel - > GetLoadGroup ( getter_AddRefs ( loadGroup ) ) ;
2008-10-11 23:30:14 -07:00
rv = responseDoc - > StartDocumentLoad ( kLoadAsData , channel , loadGroup ,
nsnull , getter_AddRefs ( listener ) ,
! ( mState & XML_HTTP_REQUEST_USE_XSITE_AC ) ) ;
2007-03-22 10:30:00 -07:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
mXMLParserStreamListener = listener ;
2008-10-11 23:30:14 -07:00
rv = mXMLParserStreamListener - > OnStartRequest ( request , ctxt ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2007-03-22 10:30:00 -07:00
}
2008-10-19 14:26:37 -07:00
// We won't get any progress events anyway if we didn't have progress
// events when starting the request - so maybe no need to start timer here.
if ( NS_SUCCEEDED ( rv ) & &
( mState & XML_HTTP_REQUEST_ASYNC ) & &
HasListenersFor ( NS_LITERAL_STRING ( PROGRESS_STR ) ) ) {
StartProgressEventTimer ( ) ;
}
2007-03-22 10:30:00 -07:00
return NS_OK ;
}
/* void onStopRequest (in nsIRequest request, in nsISupports ctxt, in nsresult status, in wstring statusArg); */
NS_IMETHODIMP
nsXMLHttpRequest : : OnStopRequest ( nsIRequest * request , nsISupports * ctxt , nsresult status )
{
2007-09-05 20:51:56 -07:00
if ( ! IsSameOrBaseChannel ( request , mChannel ) ) {
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
nsresult rv = NS_OK ;
// 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.
2007-07-30 17:42:16 -07:00
nsCOMPtr < nsIMultiPartChannel > mpChannel = do_QueryInterface ( request ) ;
if ( mpChannel ) {
PRBool last ;
rv = mpChannel - > GetIsLastPart ( & last ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
if ( last ) {
mState | = XML_HTTP_REQUEST_GOT_FINAL_STOP ;
}
}
else {
mState | = XML_HTTP_REQUEST_GOT_FINAL_STOP ;
}
2008-11-26 22:16:37 -08:00
if ( mRequestObserver & & mState & XML_HTTP_REQUEST_GOT_FINAL_STOP ) {
NS_ASSERTION ( mFirstStartRequestSeen , " Inconsistent state! " ) ;
mFirstStartRequestSeen = PR_FALSE ;
mRequestObserver - > OnStopRequest ( request , ctxt , status ) ;
}
2010-05-02 01:27:20 -07:00
// make sure to notify the listener if we were aborted
// XXX in fact, why don't we do the cleanup below in this case??
2011-05-10 16:18:55 -07:00
if ( mState & XML_HTTP_REQUEST_UNSENT ) {
2010-05-02 01:27:20 -07:00
if ( mXMLParserStreamListener )
( void ) mXMLParserStreamListener - > OnStopRequest ( request , ctxt , status ) ;
2008-11-26 22:16:37 -08:00
return NS_OK ;
2010-05-02 01:27:20 -07:00
}
2008-11-26 22:16:37 -08:00
nsCOMPtr < nsIParser > parser ;
// Is this good enough here?
if ( mState & XML_HTTP_REQUEST_PARSEBODY & & mXMLParserStreamListener ) {
parser = do_QueryInterface ( mXMLParserStreamListener ) ;
NS_ABORT_IF_FALSE ( parser , " stream listener was expected to be a parser " ) ;
rv = mXMLParserStreamListener - > OnStopRequest ( request , ctxt , status ) ;
}
2007-03-22 10:30:00 -07:00
mXMLParserStreamListener = nsnull ;
mReadRequest = nsnull ;
mContext = nsnull ;
nsCOMPtr < nsIChannel > channel ( do_QueryInterface ( request ) ) ;
NS_ENSURE_TRUE ( channel , NS_ERROR_UNEXPECTED ) ;
2011-05-10 16:18:55 -07:00
if ( NS_SUCCEEDED ( status ) & & mResponseType = = XML_HTTP_RESPONSE_TYPE_BLOB ) {
if ( ! mResponseBlob ) {
CreateResponseBlob ( request ) ;
}
if ( ! mResponseBlob ) {
// Smaller files may be written in cache map instead of separate files.
// Also, no-store response cannot be written in persistent cache.
nsCAutoString contentType ;
mChannel - > GetContentType ( contentType ) ;
// XXX We should change mResponseBody to be a raw malloc'ed buffer
// to avoid copying the data.
PRUint32 blobLen = mResponseBody . Length ( ) ;
void * blobData = PR_Malloc ( blobLen ) ;
if ( blobData ) {
memcpy ( blobData , mResponseBody . BeginReading ( ) , blobLen ) ;
mResponseBlob =
new nsDOMMemoryFile ( blobData , blobLen , EmptyString ( ) ,
NS_ConvertASCIItoUTF16 ( contentType ) ) ;
mResponseBody . Truncate ( ) ;
}
NS_ASSERTION ( mResponseBodyUnicode . IsVoid ( ) ,
" mResponseBodyUnicode should be empty " ) ;
}
}
2007-03-22 10:30:00 -07:00
channel - > SetNotificationCallbacks ( nsnull ) ;
mNotificationCallbacks = nsnull ;
mChannelEventSink = nsnull ;
mProgressEventSink = nsnull ;
if ( NS_FAILED ( status ) ) {
// This can happen if the server is unreachable. Other possible
// reasons are that the user leaves the page or hits the ESC key.
Error ( nsnull ) ;
// 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.
// This matches what IE does.
mChannel = nsnull ;
} 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.
RequestCompleted ( ) ;
} else {
ChangeState ( XML_HTTP_REQUEST_STOPPED , PR_FALSE ) ;
}
mState & = ~ XML_HTTP_REQUEST_SYNCLOOPING ;
return rv ;
}
nsresult
nsXMLHttpRequest : : RequestCompleted ( )
{
nsresult rv = NS_OK ;
mState & = ~ XML_HTTP_REQUEST_SYNCLOOPING ;
// If we're uninitialized at this point, we encountered an error
// earlier and listeners have already been notified. Also we do
// not want to do this if we already completed.
2011-05-10 16:18:55 -07:00
if ( mState & ( XML_HTTP_REQUEST_UNSENT |
XML_HTTP_REQUEST_DONE ) ) {
2007-03-22 10:30:00 -07:00
return NS_OK ;
}
// 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...
2008-10-11 23:30:14 -07:00
if ( mResponseXML ) {
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsIDOMElement > root ;
2008-10-11 23:30:14 -07:00
mResponseXML - > GetDocumentElement ( getter_AddRefs ( root ) ) ;
2007-03-22 10:30:00 -07:00
if ( ! root ) {
2008-10-11 23:30:14 -07:00
mResponseXML = nsnull ;
2007-03-22 10:30:00 -07:00
}
}
2011-05-10 16:18:55 -07:00
ChangeState ( XML_HTTP_REQUEST_DONE , PR_TRUE ) ;
2007-03-22 10:30:00 -07:00
2008-08-14 04:07:46 -07:00
PRUint32 responseLength = mResponseBody . Length ( ) ;
NS_NAMED_LITERAL_STRING ( errorStr , ERROR_STR ) ;
NS_NAMED_LITERAL_STRING ( loadStr , LOAD_STR ) ;
DispatchProgressEvent ( this ,
mErrorLoad ? errorStr : loadStr ,
! mErrorLoad ,
responseLength ,
mErrorLoad ? 0 : responseLength ) ;
if ( mErrorLoad & & mUpload & & ! mUploadComplete ) {
DispatchProgressEvent ( mUpload , errorStr , PR_TRUE ,
mUploadTransferred , mUploadTotal ) ;
2007-03-22 10:30:00 -07:00
}
2007-07-30 17:42:16 -07:00
if ( ! ( mState & XML_HTTP_REQUEST_GOT_FINAL_STOP ) ) {
2007-03-22 10:30:00 -07:00
// We're a multipart request, so we're not done. Reset to opened.
ChangeState ( XML_HTTP_REQUEST_OPENED ) ;
}
return rv ;
}
2007-07-24 21:53:21 -07:00
NS_IMETHODIMP
nsXMLHttpRequest : : SendAsBinary ( const nsAString & aBody )
{
char * data = static_cast < char * > ( NS_Alloc ( aBody . Length ( ) + 1 ) ) ;
if ( ! data )
return NS_ERROR_OUT_OF_MEMORY ;
nsAString : : const_iterator iter , end ;
aBody . BeginReading ( iter ) ;
aBody . EndReading ( end ) ;
char * p = data ;
while ( iter ! = end ) {
if ( * iter & 0xFF00 ) {
NS_Free ( data ) ;
return NS_ERROR_DOM_INVALID_CHARACTER_ERR ;
}
* p + + = static_cast < char > ( * iter + + ) ;
}
* p = ' \0 ' ;
nsCOMPtr < nsIInputStream > stream ;
nsresult rv = NS_NewByteInputStream ( getter_AddRefs ( stream ) , data ,
aBody . Length ( ) , NS_ASSIGNMENT_ADOPT ) ;
if ( NS_FAILED ( rv ) )
NS_Free ( data ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
nsCOMPtr < nsIWritableVariant > variant = new nsVariant ( ) ;
if ( ! variant ) return NS_ERROR_OUT_OF_MEMORY ;
rv = variant - > SetAsISupports ( stream ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
return Send ( variant ) ;
}
2010-02-24 21:58:17 -08:00
static nsresult
GetRequestBody ( nsIVariant * aBody , nsIInputStream * * aResult ,
nsACString & aContentType , nsACString & aCharset )
{
* aResult = nsnull ;
aContentType . AssignLiteral ( " text/plain " ) ;
aCharset . AssignLiteral ( " UTF-8 " ) ;
PRUint16 dataType ;
nsresult rv = aBody - > GetDataType ( & dataType ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
if ( dataType = = nsIDataType : : VTYPE_INTERFACE | |
dataType = = nsIDataType : : VTYPE_INTERFACE_IS ) {
nsCOMPtr < nsISupports > supports ;
nsID * iid ;
rv = aBody - > GetAsInterface ( & iid , getter_AddRefs ( supports ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
nsMemory : : Free ( iid ) ;
// document?
nsCOMPtr < nsIDOMDocument > doc = do_QueryInterface ( supports ) ;
if ( doc ) {
aContentType . AssignLiteral ( " application/xml " ) ;
2011-03-26 09:06:27 -07:00
nsAutoString inputEncoding ;
doc - > GetInputEncoding ( inputEncoding ) ;
if ( ! DOMStringIsNull ( inputEncoding ) ) {
CopyUTF16toUTF8 ( inputEncoding , aCharset ) ;
2010-02-24 21:58:17 -08:00
}
// Serialize to a stream so that the encoding used will
// match the document's.
nsCOMPtr < nsIDOMSerializer > serializer =
do_CreateInstance ( NS_XMLSERIALIZER_CONTRACTID , & rv ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
nsCOMPtr < nsIStorageStream > storStream ;
rv = NS_NewStorageStream ( 4096 , PR_UINT32_MAX ,
getter_AddRefs ( storStream ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
nsCOMPtr < nsIOutputStream > output ;
rv = storStream - > GetOutputStream ( 0 , getter_AddRefs ( output ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
// Make sure to use the encoding we'll send
rv = serializer - > SerializeToStream ( doc , output , aCharset ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
output - > Close ( ) ;
return storStream - > NewInputStream ( 0 , aResult ) ;
}
// nsISupportsString?
nsCOMPtr < nsISupportsString > wstr = do_QueryInterface ( supports ) ;
if ( wstr ) {
nsAutoString string ;
wstr - > GetData ( string ) ;
return NS_NewCStringInputStream ( aResult ,
NS_ConvertUTF16toUTF8 ( string ) ) ;
}
// nsIInputStream?
nsCOMPtr < nsIInputStream > stream = do_QueryInterface ( supports ) ;
if ( stream ) {
* aResult = stream . forget ( ) . get ( ) ;
aCharset . Truncate ( ) ;
return NS_OK ;
}
2010-02-24 21:58:18 -08:00
// nsIXHRSendable?
nsCOMPtr < nsIXHRSendable > sendable = do_QueryInterface ( supports ) ;
if ( sendable ) {
return sendable - > GetSendInfo ( aResult , aContentType , aCharset ) ;
}
2010-02-24 21:58:17 -08:00
}
else if ( dataType = = nsIDataType : : VTYPE_VOID | |
dataType = = nsIDataType : : VTYPE_EMPTY ) {
// Makes us act as if !aBody, don't upload anything
return NS_OK ;
}
PRUnichar * data = nsnull ;
PRUint32 len = 0 ;
rv = aBody - > GetAsWStringWithSize ( & len , & data ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
nsString string ;
string . Adopt ( data , len ) ;
return NS_NewCStringInputStream ( aResult , NS_ConvertUTF16toUTF8 ( string ) ) ;
}
2007-03-22 10:30:00 -07:00
/* void send (in nsIVariant aBody); */
NS_IMETHODIMP
nsXMLHttpRequest : : Send ( nsIVariant * aBody )
{
2008-02-19 15:12:23 -08:00
NS_ENSURE_TRUE ( mPrincipal , NS_ERROR_NOT_INITIALIZED ) ;
2007-12-12 00:33:32 -08:00
nsresult rv = CheckInnerWindowCorrectness ( ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2007-03-22 10:30:00 -07:00
// Return error if we're already processing a request
if ( XML_HTTP_REQUEST_SENT & mState ) {
return NS_ERROR_FAILURE ;
}
// Make sure we've been opened
if ( ! mChannel | | ! ( XML_HTTP_REQUEST_OPENED & mState ) ) {
return NS_ERROR_NOT_INITIALIZED ;
}
2010-09-08 10:42:08 -07: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.
if ( HasListenersFor ( NS_LITERAL_STRING ( PROGRESS_STR ) ) | |
HasListenersFor ( NS_LITERAL_STRING ( UPLOADPROGRESS_STR ) ) | |
( mUpload & & mUpload - > HasListenersFor ( NS_LITERAL_STRING ( PROGRESS_STR ) ) ) ) {
nsLoadFlags loadFlags ;
mChannel - > GetLoadFlags ( & loadFlags ) ;
loadFlags & = ~ nsIRequest : : LOAD_BACKGROUND ;
loadFlags | = nsIRequest : : LOAD_NORMAL ;
mChannel - > SetLoadFlags ( loadFlags ) ;
}
2007-03-22 10:30:00 -07: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.
// Ignore argument if method is GET, there is no point in trying to
// upload anything
nsCAutoString method ;
nsCOMPtr < nsIHttpChannel > httpChannel ( do_QueryInterface ( mChannel ) ) ;
if ( httpChannel ) {
2008-10-14 17:12:28 -07:00
httpChannel - > GetRequestMethod ( method ) ; // If GET, method name will be uppercase
2007-03-22 10:30:00 -07:00
2011-03-17 09:19:13 -07:00
if ( ! IsSystemXHR ( ) ) {
2011-01-30 13:46:34 -08:00
// Get the referrer for the request.
//
// If it weren't for history.push/replaceState, we could just use the
// principal's URI here. But since we want changes to the URI effected
// by push/replaceState to be reflected in the XHR referrer, we have to
// be more clever.
//
// If the document's original URI (before any push/replaceStates) matches
// our principal, then we use the document's current URI (after
// push/replaceStates). Otherwise (if the document is, say, a data:
// URI), we just use the principal's URI.
nsCOMPtr < nsIURI > principalURI ;
mPrincipal - > GetURI ( getter_AddRefs ( principalURI ) ) ;
nsCOMPtr < nsIDocument > doc =
nsContentUtils : : GetDocumentFromScriptContext ( mScriptContext ) ;
nsCOMPtr < nsIURI > docCurURI ;
nsCOMPtr < nsIURI > docOrigURI ;
if ( doc ) {
docCurURI = doc - > GetDocumentURI ( ) ;
docOrigURI = doc - > GetOriginalURI ( ) ;
}
nsCOMPtr < nsIURI > referrerURI ;
if ( principalURI & & docCurURI & & docOrigURI ) {
PRBool equal = PR_FALSE ;
principalURI - > Equals ( docOrigURI , & equal ) ;
if ( equal ) {
referrerURI = docCurURI ;
}
}
if ( ! referrerURI )
referrerURI = principalURI ;
2007-03-22 10:30:00 -07:00
2011-01-30 13:46:34 -08:00
httpChannel - > SetReferrer ( referrerURI ) ;
2008-03-13 04:43:06 -07:00
}
2009-11-18 15:21:13 -08:00
// Some extensions override the http protocol handler and provide their own
// implementation. The channels returned from that implementation doesn't
// seem to always implement the nsIUploadChannel2 interface, presumably
// because it's a new interface.
// Eventually we should remove this and simply require that http channels
// implement the new interface.
// See bug 529041
nsCOMPtr < nsIUploadChannel2 > uploadChannel2 =
do_QueryInterface ( httpChannel ) ;
if ( ! uploadChannel2 ) {
nsCOMPtr < nsIConsoleService > consoleService =
do_GetService ( NS_CONSOLESERVICE_CONTRACTID ) ;
if ( consoleService ) {
consoleService - > LogStringMessage ( NS_LITERAL_STRING (
2009-11-18 16:22:25 -08:00
" Http channel implementation doesn't support nsIUploadChannel2. An extension has supplied a non-functional http protocol handler. This will break behavior and in future releases not work at all. "
) . get ( ) ) ;
2009-11-18 15:21:13 -08:00
}
}
2007-03-22 10:30:00 -07:00
}
2008-08-14 04:07:46 -07:00
mUploadTransferred = 0 ;
mUploadTotal = 0 ;
// By default we don't have any upload, so mark upload complete.
mUploadComplete = PR_TRUE ;
mErrorLoad = PR_FALSE ;
2008-10-19 14:26:37 -07:00
mLoadLengthComputable = PR_FALSE ;
mLoadTotal = 0 ;
mUploadProgress = 0 ;
mUploadProgressMax = 0 ;
2007-03-22 10:30:00 -07:00
if ( aBody & & httpChannel & & ! method . EqualsLiteral ( " GET " ) ) {
2008-10-14 17:12:28 -07:00
2010-02-24 21:58:17 -08:00
nsCAutoString charset ;
nsCAutoString defaultContentType ;
nsCOMPtr < nsIInputStream > postDataStream ;
2008-10-14 17:12:28 -07:00
2010-02-24 21:58:17 -08:00
rv = GetRequestBody ( aBody , getter_AddRefs ( postDataStream ) ,
defaultContentType , charset ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2008-10-14 17:12:28 -07:00
if ( postDataStream ) {
// If no content type header was set by the client, we set it to
// application/xml.
nsCAutoString contentType ;
if ( NS_FAILED ( httpChannel - >
GetRequestHeader ( NS_LITERAL_CSTRING ( " Content-Type " ) ,
contentType ) ) | |
contentType . IsEmpty ( ) ) {
2009-01-13 22:53:43 -08:00
contentType = defaultContentType ;
2008-10-14 17:12:28 -07:00
}
// We don't want to set a charset for streams.
if ( ! charset . IsEmpty ( ) ) {
nsCAutoString specifiedCharset ;
PRBool haveCharset ;
PRInt32 charsetStart , charsetEnd ;
rv = NS_ExtractCharsetFromContentType ( contentType , specifiedCharset ,
& haveCharset , & charsetStart ,
& charsetEnd ) ;
2009-01-13 22:53:43 -08:00
if ( NS_SUCCEEDED ( rv ) ) {
// If the content-type the page set already has a charset parameter,
// and it's the same charset, up to case, as |charset|, just send the
// page-set content-type header. Apparently at least
// google-web-toolkit is broken and relies on the exact case of its
// charset parameter, which makes things break if we use |charset|
// (which is always a fully resolved charset per our charset alias
// table, hence might be differently cased).
if ( ! specifiedCharset . Equals ( charset ,
nsCaseInsensitiveCStringComparator ( ) ) ) {
nsCAutoString newCharset ( " ; charset= " ) ;
newCharset . Append ( charset ) ;
contentType . Replace ( charsetStart , charsetEnd - charsetStart ,
newCharset ) ;
}
2008-10-14 17:12:28 -07:00
}
}
2009-09-08 16:29:41 -07:00
// If necessary, wrap the stream in a buffered stream so as to guarantee
// support for our upload when calling ExplicitSetUploadStream.
if ( ! NS_InputStreamIsBuffered ( postDataStream ) ) {
nsCOMPtr < nsIInputStream > bufferedStream ;
rv = NS_NewBufferedInputStream ( getter_AddRefs ( bufferedStream ) ,
postDataStream ,
4096 ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
postDataStream = bufferedStream ;
}
2008-10-14 17:12:28 -07:00
mUploadComplete = PR_FALSE ;
2008-10-21 02:06:53 -07:00
PRUint32 uploadTotal = 0 ;
postDataStream - > Available ( & uploadTotal ) ;
mUploadTotal = uploadTotal ;
2009-09-08 16:29:41 -07:00
// We want to use a newer version of the upload channel that won't
// ignore the necessary headers for an empty Content-Type.
2009-11-18 15:21:13 -08:00
nsCOMPtr < nsIUploadChannel2 > uploadChannel2 ( do_QueryInterface ( httpChannel ) ) ;
// This assertion will fire if buggy extensions are installed
2010-10-04 17:41:07 -07:00
NS_ASSERTION ( uploadChannel2 , " http must support nsIUploadChannel2 " ) ;
2009-11-18 15:21:13 -08:00
if ( uploadChannel2 ) {
uploadChannel2 - > ExplicitSetUploadStream ( postDataStream , contentType ,
- 1 , method , PR_FALSE ) ;
}
else {
// http channel doesn't support the new nsIUploadChannel2. Emulate
// as best we can using nsIUploadChannel
if ( contentType . IsEmpty ( ) ) {
contentType . AssignLiteral ( " application/octet-stream " ) ;
}
nsCOMPtr < nsIUploadChannel > uploadChannel =
do_QueryInterface ( httpChannel ) ;
uploadChannel - > SetUploadStream ( postDataStream , contentType , - 1 ) ;
// Reset the method to its original value
httpChannel - > SetRequestMethod ( method ) ;
}
2008-10-14 17:12:28 -07:00
}
}
2008-10-14 14:05:41 -07:00
2010-10-04 17:41:07 -07:00
if ( httpChannel ) {
nsCAutoString contentTypeHeader ;
rv = httpChannel - > GetRequestHeader ( NS_LITERAL_CSTRING ( " Content-Type " ) ,
contentTypeHeader ) ;
if ( NS_SUCCEEDED ( rv ) ) {
nsCAutoString contentType , charset ;
rv = NS_ParseContentType ( contentTypeHeader , contentType , charset ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
if ( ! contentType . LowerCaseEqualsLiteral ( " text/plain " ) & &
! contentType . LowerCaseEqualsLiteral ( " application/x-www-form-urlencoded " ) & &
! contentType . LowerCaseEqualsLiteral ( " multipart/form-data " ) ) {
2011-03-28 13:18:45 -07:00
mCORSUnsafeHeaders . AppendElement ( NS_LITERAL_CSTRING ( " Content-Type " ) ) ;
2010-10-04 17:41:07 -07:00
}
}
}
2007-03-22 10:30:00 -07:00
// Reset responseBody
mResponseBody . Truncate ( ) ;
2010-04-23 10:37:02 -07:00
mResponseBodyUnicode . SetIsVoid ( PR_TRUE ) ;
2011-05-10 16:18:55 -07:00
mResponseBlob = nsnull ;
2007-03-22 10:30:00 -07:00
// Reset responseXML
2008-10-11 23:30:14 -07:00
mResponseXML = nsnull ;
2007-03-22 10:30:00 -07:00
2008-09-30 17:49:30 -07:00
rv = CheckChannelForCrossSiteRequest ( mChannel ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2008-09-30 17:52:52 -07:00
PRBool withCredentials = ! ! ( mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS ) ;
2007-03-22 10:30:00 -07:00
// Hook us up to listen to redirects and the like
mChannel - > GetNotificationCallbacks ( getter_AddRefs ( mNotificationCallbacks ) ) ;
mChannel - > SetNotificationCallbacks ( this ) ;
2007-07-26 19:49:18 -07:00
// Create our listener
nsCOMPtr < nsIStreamListener > listener = this ;
2007-03-22 10:30:00 -07:00
if ( mState & XML_HTTP_REQUEST_MULTIPART ) {
2007-07-26 19:49:18 -07:00
listener = new nsMultipartProxyListener ( listener ) ;
2007-03-22 10:30:00 -07:00
if ( ! listener ) {
return NS_ERROR_OUT_OF_MEMORY ;
}
}
2011-03-17 09:19:13 -07:00
if ( ! IsSystemXHR ( ) ) {
2011-03-28 13:18:45 -07:00
// Always create a nsCORSListenerProxy here even if it's
2008-09-30 17:49:30 -07:00
// a same-origin request right now, since it could be redirected.
2011-03-28 13:18:45 -07:00
listener = new nsCORSListenerProxy ( listener , mPrincipal , mChannel ,
withCredentials , & rv ) ;
2008-09-30 17:49:30 -07:00
NS_ENSURE_TRUE ( listener , NS_ERROR_OUT_OF_MEMORY ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
}
2008-10-14 17:12:28 -07: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 " ) ) {
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_ASYNC ) ) {
AddLoadFlags ( mChannel ,
nsICachingChannel : : LOAD_BYPASS_LOCAL_CACHE_IF_BUSY ) ;
}
2007-03-22 10:30:00 -07:00
2008-10-14 17:12:28 -07: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 " ) ) ;
2007-03-22 10:30:00 -07:00
2011-03-28 13:11:09 -07:00
// Set up the preflight if needed
if ( mState & XML_HTTP_REQUEST_NEED_AC_PREFLIGHT ) {
// Check to see if this initial OPTIONS request has already been cached
// in our special Access Control Cache.
2008-09-30 17:49:30 -07:00
2011-03-28 13:11:09 -07:00
rv = NS_StartCORSPreflight ( mChannel , listener ,
mPrincipal , withCredentials ,
2011-03-28 13:18:45 -07:00
mCORSUnsafeHeaders ,
getter_AddRefs ( mCORSPreflightChannel ) ) ;
2011-03-28 13:11:09 -07:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2008-09-30 17:49:30 -07:00
}
else {
// Start reading from the channel
rv = mChannel - > AsyncOpen ( listener , nsnull ) ;
}
2007-03-22 10:30:00 -07:00
if ( NS_FAILED ( rv ) ) {
// Drop our ref to the channel to avoid cycles
mChannel = nsnull ;
2011-03-28 13:18:45 -07:00
mCORSPreflightChannel = nsnull ;
2007-03-22 10:30:00 -07:00
return rv ;
}
// If we're synchronous, spin an event loop here and wait
if ( ! ( mState & XML_HTTP_REQUEST_ASYNC ) ) {
2008-10-08 04:08:01 -07:00
mState | = XML_HTTP_REQUEST_SYNCLOOPING ;
2009-02-17 12:07:39 -08:00
2009-03-03 12:11:14 -08:00
nsCOMPtr < nsIDocument > suspendedDoc ;
2009-02-17 12:07:39 -08:00
nsCOMPtr < nsIRunnable > resumeTimeoutRunnable ;
if ( mOwner ) {
nsCOMPtr < nsIDOMWindow > topWindow ;
if ( NS_SUCCEEDED ( mOwner - > GetTop ( getter_AddRefs ( topWindow ) ) ) ) {
nsCOMPtr < nsPIDOMWindow > suspendedWindow ( do_QueryInterface ( topWindow ) ) ;
2009-03-03 12:11:14 -08:00
if ( suspendedWindow & &
( suspendedWindow = suspendedWindow - > GetCurrentInnerWindow ( ) ) ) {
suspendedDoc = do_QueryInterface ( suspendedWindow - > GetExtantDocument ( ) ) ;
if ( suspendedDoc ) {
suspendedDoc - > SuppressEventHandling ( ) ;
}
suspendedWindow - > SuspendTimeouts ( 1 , PR_FALSE ) ;
resumeTimeoutRunnable = new nsResumeTimeoutsEvent ( suspendedWindow ) ;
2009-02-17 12:07:39 -08:00
}
}
}
2010-09-17 02:30:35 -07:00
ChangeState ( XML_HTTP_REQUEST_SENT ) ;
// Note, calling ChangeState may have cleared
// XML_HTTP_REQUEST_SYNCLOOPING flag.
2007-03-22 10:30:00 -07:00
nsIThread * thread = NS_GetCurrentThread ( ) ;
while ( mState & XML_HTTP_REQUEST_SYNCLOOPING ) {
if ( ! NS_ProcessNextEvent ( thread ) ) {
rv = NS_ERROR_UNEXPECTED ;
break ;
}
}
2009-02-17 12:07:39 -08:00
2009-03-03 12:11:14 -08:00
if ( suspendedDoc ) {
2009-03-25 07:11:11 -07:00
suspendedDoc - > UnsuppressEventHandlingAndFireEvents ( PR_TRUE ) ;
2009-03-03 12:11:14 -08:00
}
2009-02-17 12:07:39 -08:00
if ( resumeTimeoutRunnable ) {
NS_DispatchToCurrentThread ( resumeTimeoutRunnable ) ;
}
2008-08-14 04:07:46 -07:00
} else {
2010-09-17 02:30:35 -07:00
// Now that we've successfully opened the channel, we can change state. Note
// that this needs to come after the AsyncOpen() and rv check, because this
// can run script that would try to restart this request, and that could end
// up doing our AsyncOpen on a null channel if the reentered AsyncOpen fails.
ChangeState ( XML_HTTP_REQUEST_SENT ) ;
2008-10-19 14:26:37 -07:00
if ( ! mUploadComplete & &
HasListenersFor ( NS_LITERAL_STRING ( UPLOADPROGRESS_STR ) ) | |
( mUpload & & mUpload - > HasListenersFor ( NS_LITERAL_STRING ( PROGRESS_STR ) ) ) ) {
StartProgressEventTimer ( ) ;
}
2008-08-14 04:07:46 -07:00
DispatchProgressEvent ( this , NS_LITERAL_STRING ( LOADSTART_STR ) , PR_FALSE ,
0 , 0 ) ;
if ( mUpload & & ! mUploadComplete ) {
DispatchProgressEvent ( mUpload , NS_LITERAL_STRING ( LOADSTART_STR ) , PR_TRUE ,
0 , mUploadTotal ) ;
}
2007-03-22 10:30:00 -07:00
}
if ( ! mChannel ) {
return NS_ERROR_FAILURE ;
}
return rv ;
}
/* void setRequestHeader (in AUTF8String header, in AUTF8String value); */
NS_IMETHODIMP
nsXMLHttpRequest : : SetRequestHeader ( const nsACString & header ,
const nsACString & value )
{
2007-07-26 19:49:18 -07:00
nsresult rv ;
2011-03-28 13:18:45 -07:00
// Make sure we don't store an invalid header name in mCORSUnsafeHeaders
2008-09-30 17:50:42 -07:00
if ( ! IsValidHTTPToken ( header ) ) {
return NS_ERROR_FAILURE ;
}
2008-09-30 17:49:30 -07:00
// Check that we haven't already opened the channel. We can't rely on
// the channel throwing from mChannel->SetRequestHeader since we might
2011-03-28 13:18:45 -07:00
// still be waiting for mCORSPreflightChannel to actually open mChannel
if ( mCORSPreflightChannel ) {
2008-09-30 17:49:30 -07:00
PRBool pending ;
2011-03-28 13:18:45 -07:00
rv = mCORSPreflightChannel - > IsPending ( & pending ) ;
2008-09-30 17:49:30 -07:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2008-10-14 17:12:28 -07:00
2008-09-30 17:49:30 -07:00
if ( pending ) {
return NS_ERROR_IN_PROGRESS ;
}
}
2007-07-30 17:42:16 -07:00
if ( ! mChannel ) // open() initializes mChannel, and open()
2007-03-22 10:30:00 -07:00
return NS_ERROR_FAILURE ; // must be called before first setRequestHeader()
2007-07-30 17:42:16 -07:00
nsCOMPtr < nsIHttpChannel > httpChannel ( do_QueryInterface ( mChannel ) ) ;
if ( ! httpChannel ) {
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
// Prevent modification to certain HTTP headers (see bug 302263), unless
// the executing script has UniversalBrowserWrite permission.
PRBool privileged ;
2008-03-18 17:14:38 -07:00
rv = IsCapabilityEnabled ( " UniversalBrowserWrite " , & privileged ) ;
2007-03-22 10:30:00 -07:00
if ( NS_FAILED ( rv ) )
return NS_ERROR_FAILURE ;
if ( ! privileged ) {
2007-07-26 19:49:18 -07:00
// Check for dangerous headers
2007-03-22 10:30:00 -07:00
const char * kInvalidHeaders [ ] = {
2010-11-15 03:55:30 -08:00
" accept-charset " , " accept-encoding " , " access-control-request-headers " ,
" access-control-request-method " , " connection " , " content-length " ,
" cookie " , " cookie2 " , " content-transfer-encoding " , " date " , " expect " ,
" host " , " keep-alive " , " origin " , " referer " , " te " , " trailer " ,
" transfer-encoding " , " upgrade " , " user-agent " , " via "
2007-03-22 10:30:00 -07:00
} ;
2007-07-26 19:49:18 -07:00
PRUint32 i ;
for ( i = 0 ; i < NS_ARRAY_LENGTH ( kInvalidHeaders ) ; + + i ) {
2007-03-22 10:30:00 -07:00
if ( header . LowerCaseEqualsASCII ( kInvalidHeaders [ i ] ) ) {
NS_WARNING ( " refusing to set request header " ) ;
return NS_OK ;
}
}
2008-07-12 16:06:36 -07:00
if ( StringBeginsWith ( header , NS_LITERAL_CSTRING ( " proxy- " ) ,
nsCaseInsensitiveCStringComparator ( ) ) | |
StringBeginsWith ( header , NS_LITERAL_CSTRING ( " sec- " ) ,
nsCaseInsensitiveCStringComparator ( ) ) ) {
NS_WARNING ( " refusing to set request header " ) ;
return NS_OK ;
}
2008-09-30 17:49:30 -07:00
// Check for dangerous cross-site headers
2011-03-17 09:19:13 -07:00
bool safeHeader = IsSystemXHR ( ) ;
2008-09-30 17:49:30 -07:00
if ( ! safeHeader ) {
2010-10-04 17:41:07 -07:00
// Content-Type isn't always safe, but we'll deal with it in Send()
2008-09-30 17:49:30 -07:00
const char * kCrossOriginSafeHeaders [ ] = {
2010-10-04 17:41:07 -07:00
" accept " , " accept-language " , " content-language " , " content-type " ,
" last-event-id "
2008-09-30 17:49:30 -07:00
} ;
for ( i = 0 ; i < NS_ARRAY_LENGTH ( kCrossOriginSafeHeaders ) ; + + i ) {
if ( header . LowerCaseEqualsASCII ( kCrossOriginSafeHeaders [ i ] ) ) {
2011-03-17 09:19:13 -07:00
safeHeader = true ;
2008-09-30 17:49:30 -07:00
break ;
}
}
}
if ( ! safeHeader ) {
2011-03-28 13:18:45 -07:00
mCORSUnsafeHeaders . AppendElement ( header ) ;
2008-09-30 17:49:30 -07:00
}
2007-03-22 10:30:00 -07:00
}
2007-07-26 19:49:18 -07:00
// We need to set, not add to, the header.
return httpChannel - > SetRequestHeader ( header , value , PR_FALSE ) ;
2007-03-22 10:30:00 -07:00
}
/* readonly attribute long readyState; */
NS_IMETHODIMP
2011-05-10 16:18:55 -07:00
nsXMLHttpRequest : : GetReadyState ( PRUint16 * aState )
2007-03-22 10:30:00 -07:00
{
NS_ENSURE_ARG_POINTER ( aState ) ;
// Translate some of our internal states for external consumers
2011-05-10 16:18:55 -07:00
if ( mState & XML_HTTP_REQUEST_UNSENT ) {
* aState = UNSENT ;
2007-03-22 10:30:00 -07:00
} else if ( mState & ( XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT ) ) {
2011-05-10 16:18:55 -07:00
* aState = OPENED ;
} else if ( mState & XML_HTTP_REQUEST_HEADERS_RECEIVED ) {
* aState = HEADERS_RECEIVED ;
} else if ( mState & ( XML_HTTP_REQUEST_LOADING | XML_HTTP_REQUEST_STOPPED ) ) {
* aState = LOADING ;
} else if ( mState & XML_HTTP_REQUEST_DONE ) {
* aState = DONE ;
2007-03-22 10:30:00 -07:00
} else {
NS_ERROR ( " Should not happen " ) ;
}
return NS_OK ;
}
/* void overrideMimeType(in AUTF8String mimetype); */
NS_IMETHODIMP
nsXMLHttpRequest : : OverrideMimeType ( const nsACString & aMimeType )
{
// XXX Should we do some validation here?
mOverrideMimeType . Assign ( aMimeType ) ;
return NS_OK ;
}
/* attribute boolean multipart; */
NS_IMETHODIMP
nsXMLHttpRequest : : GetMultipart ( PRBool * _retval )
{
2008-02-09 22:16:30 -08:00
* _retval = ! ! ( mState & XML_HTTP_REQUEST_MULTIPART ) ;
2007-03-22 10:30:00 -07:00
return NS_OK ;
}
/* attribute boolean multipart; */
NS_IMETHODIMP
nsXMLHttpRequest : : SetMultipart ( PRBool aMultipart )
{
2011-05-10 16:18:55 -07:00
if ( ! ( mState & XML_HTTP_REQUEST_UNSENT ) ) {
2007-03-22 10:30:00 -07:00
// 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 ;
}
2008-03-18 17:14:38 -07:00
/* attribute boolean mozBackgroundRequest; */
NS_IMETHODIMP
nsXMLHttpRequest : : GetMozBackgroundRequest ( PRBool * _retval )
{
* _retval = ! ! ( mState & XML_HTTP_REQUEST_BACKGROUND ) ;
return NS_OK ;
}
/* attribute boolean mozBackgroundRequest; */
NS_IMETHODIMP
nsXMLHttpRequest : : SetMozBackgroundRequest ( PRBool aMozBackgroundRequest )
{
PRBool privileged ;
nsresult rv = IsCapabilityEnabled ( " UniversalXPConnect " , & privileged ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
if ( ! privileged )
return NS_ERROR_DOM_SECURITY_ERR ;
2011-05-10 16:18:55 -07:00
if ( ! ( mState & XML_HTTP_REQUEST_UNSENT ) ) {
2008-03-18 17:14:38 -07:00
// Can't change this while we're in the middle of something.
return NS_ERROR_IN_PROGRESS ;
}
if ( aMozBackgroundRequest ) {
mState | = XML_HTTP_REQUEST_BACKGROUND ;
} else {
mState & = ~ XML_HTTP_REQUEST_BACKGROUND ;
}
return NS_OK ;
}
2008-09-30 17:52:52 -07:00
/* attribute boolean withCredentials; */
NS_IMETHODIMP
nsXMLHttpRequest : : GetWithCredentials ( PRBool * _retval )
{
* _retval = ! ! ( mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS ) ;
return NS_OK ;
}
/* attribute boolean withCredentials; */
NS_IMETHODIMP
nsXMLHttpRequest : : SetWithCredentials ( PRBool aWithCredentials )
{
// Return error if we're already processing a request
if ( XML_HTTP_REQUEST_SENT & mState ) {
return NS_ERROR_FAILURE ;
}
if ( aWithCredentials ) {
mState | = XML_HTTP_REQUEST_AC_WITH_CREDENTIALS ;
}
else {
mState & = ~ XML_HTTP_REQUEST_AC_WITH_CREDENTIALS ;
}
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
// nsIDOMEventListener
nsresult
nsXMLHttpRequest : : HandleEvent ( nsIDOMEvent * aEvent )
{
return NS_OK ;
}
// nsIDOMLoadListener
nsresult
nsXMLHttpRequest : : Load ( nsIDOMEvent * aEvent )
{
// 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.
//
// 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().
if ( mState & XML_HTTP_REQUEST_STOPPED ) {
RequestCompleted ( ) ;
}
return NS_OK ;
}
nsresult
nsXMLHttpRequest : : Unload ( nsIDOMEvent * aEvent )
{
return NS_OK ;
}
nsresult
nsXMLHttpRequest : : BeforeUnload ( nsIDOMEvent * aEvent )
{
return NS_OK ;
}
nsresult
nsXMLHttpRequest : : Abort ( nsIDOMEvent * aEvent )
{
Abort ( ) ;
return NS_OK ;
}
nsresult
nsXMLHttpRequest : : Error ( nsIDOMEvent * aEvent )
{
2008-10-11 23:30:14 -07:00
mResponseXML = nsnull ;
2011-05-10 16:18:55 -07:00
ChangeState ( XML_HTTP_REQUEST_DONE ) ;
2007-03-22 10:30:00 -07:00
mState & = ~ XML_HTTP_REQUEST_SYNCLOOPING ;
2008-08-14 04:07:46 -07:00
DispatchProgressEvent ( this , NS_LITERAL_STRING ( ERROR_STR ) , PR_FALSE ,
mResponseBody . Length ( ) , 0 ) ;
if ( mUpload & & ! mUploadComplete ) {
mUploadComplete = PR_TRUE ;
DispatchProgressEvent ( mUpload , NS_LITERAL_STRING ( ERROR_STR ) , PR_TRUE ,
mUploadTransferred , mUploadTotal ) ;
2007-03-22 10:30:00 -07:00
}
return NS_OK ;
}
nsresult
2008-08-14 04:04:43 -07:00
nsXMLHttpRequest : : ChangeState ( PRUint32 aState , PRBool aBroadcast )
2007-03-22 10:30:00 -07:00
{
// If we are setting one of the mutually exclusive states,
// unset those state bits first.
if ( aState & XML_HTTP_REQUEST_LOADSTATES ) {
mState & = ~ XML_HTTP_REQUEST_LOADSTATES ;
}
mState | = aState ;
nsresult rv = NS_OK ;
2008-10-19 14:26:37 -07:00
if ( mProgressNotifier & &
2011-05-10 16:18:55 -07:00
! ( aState & ( XML_HTTP_REQUEST_HEADERS_RECEIVED | XML_HTTP_REQUEST_LOADING ) ) ) {
2008-10-19 14:26:37 -07:00
mTimerIsActive = PR_FALSE ;
mProgressNotifier - > Cancel ( ) ;
}
2010-09-17 02:30:35 -07:00
if ( ( aState & XML_HTTP_REQUEST_LOADSTATES ) & & // Broadcast load states only
aBroadcast & &
( mState & XML_HTTP_REQUEST_ASYNC | |
aState & XML_HTTP_REQUEST_OPENED | |
2011-05-10 16:18:55 -07:00
aState & XML_HTTP_REQUEST_DONE ) ) {
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsIDOMEvent > event ;
2008-08-14 04:07:46 -07:00
rv = CreateReadystatechangeEvent ( getter_AddRefs ( event ) ) ;
2007-03-22 10:30:00 -07:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2008-08-14 04:04:43 -07:00
DispatchDOMEvent ( nsnull , event , nsnull , nsnull ) ;
2007-03-22 10:30:00 -07:00
}
return rv ;
}
2010-08-04 19:15:55 -07:00
/*
* Simple helper class that just forwards the redirect callback back
* to the nsXMLHttpRequest .
*/
class AsyncVerifyRedirectCallbackForwarder : public nsIAsyncVerifyRedirectCallback
{
public :
AsyncVerifyRedirectCallbackForwarder ( nsXMLHttpRequest * xhr )
: mXHR ( xhr )
{
}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS ( AsyncVerifyRedirectCallbackForwarder )
// nsIAsyncVerifyRedirectCallback implementation
NS_IMETHOD OnRedirectVerifyCallback ( nsresult result )
{
mXHR - > OnRedirectVerifyCallback ( result ) ;
return NS_OK ;
}
private :
nsRefPtr < nsXMLHttpRequest > mXHR ;
} ;
NS_IMPL_CYCLE_COLLECTION_CLASS ( AsyncVerifyRedirectCallbackForwarder )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN ( AsyncVerifyRedirectCallbackForwarder )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS ( mXHR , nsIDOMEventListener )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN ( AsyncVerifyRedirectCallbackForwarder )
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR ( mXHR )
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION ( AsyncVerifyRedirectCallbackForwarder )
NS_INTERFACE_MAP_ENTRY ( nsISupports )
NS_INTERFACE_MAP_ENTRY ( nsIAsyncVerifyRedirectCallback )
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF ( AsyncVerifyRedirectCallbackForwarder )
NS_IMPL_CYCLE_COLLECTING_RELEASE ( AsyncVerifyRedirectCallbackForwarder )
2007-03-22 10:30:00 -07:00
/////////////////////////////////////////////////////
// nsIChannelEventSink methods:
//
NS_IMETHODIMP
2010-08-04 19:15:55 -07:00
nsXMLHttpRequest : : AsyncOnChannelRedirect ( nsIChannel * aOldChannel ,
nsIChannel * aNewChannel ,
PRUint32 aFlags ,
nsIAsyncVerifyRedirectCallback * callback )
2007-03-22 10:30:00 -07:00
{
NS_PRECONDITION ( aNewChannel , " Redirect without a channel? " ) ;
2007-07-26 19:49:18 -07:00
nsresult rv ;
2008-04-04 02:01:22 -07:00
2009-01-21 14:50:28 -08:00
if ( ! NS_IsInternalSameURIRedirect ( aOldChannel , aNewChannel , aFlags ) ) {
rv = CheckChannelForCrossSiteRequest ( aNewChannel ) ;
2010-08-04 19:15:55 -07:00
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " nsXMLHttpRequest::OnChannelRedirect: "
" CheckChannelForCrossSiteRequest returned failure " ) ;
return rv ;
}
2008-04-04 02:01:22 -07:00
2009-01-21 14:50:28 -08:00
// Disable redirects for preflighted cross-site requests entirely for now
// Note, do this after the call to CheckChannelForCrossSiteRequest
// to make sure that XML_HTTP_REQUEST_USE_XSITE_AC is up-to-date
if ( ( mState & XML_HTTP_REQUEST_NEED_AC_PREFLIGHT ) ) {
return NS_ERROR_DOM_BAD_URI ;
}
2008-04-04 02:01:22 -07:00
}
2010-08-04 19:15:55 -07:00
// Prepare to receive callback
mRedirectCallback = callback ;
mNewRedirectChannel = aNewChannel ;
2007-03-22 10:30:00 -07:00
if ( mChannelEventSink ) {
2010-08-04 19:15:55 -07:00
nsRefPtr < AsyncVerifyRedirectCallbackForwarder > fwd =
new AsyncVerifyRedirectCallbackForwarder ( this ) ;
rv = mChannelEventSink - > AsyncOnChannelRedirect ( aOldChannel ,
aNewChannel ,
aFlags , fwd ) ;
2008-08-14 04:07:46 -07:00
if ( NS_FAILED ( rv ) ) {
2010-08-04 19:15:55 -07:00
mRedirectCallback = nsnull ;
mNewRedirectChannel = nsnull ;
2008-08-14 04:07:46 -07:00
}
2010-08-04 19:15:55 -07:00
return rv ;
2007-03-22 10:30:00 -07:00
}
2010-08-04 19:15:55 -07:00
OnRedirectVerifyCallback ( NS_OK ) ;
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
2010-08-04 19:15:55 -07:00
void
nsXMLHttpRequest : : OnRedirectVerifyCallback ( nsresult result )
{
NS_ASSERTION ( mRedirectCallback , " mRedirectCallback not set in callback " ) ;
NS_ASSERTION ( mNewRedirectChannel , " mNewRedirectChannel not set in callback " ) ;
2007-07-26 19:49:18 -07:00
2010-08-04 19:15:55 -07:00
if ( NS_SUCCEEDED ( result ) )
mChannel = mNewRedirectChannel ;
else
mErrorLoad = PR_TRUE ;
mNewRedirectChannel = nsnull ;
mRedirectCallback - > OnRedirectVerifyCallback ( result ) ;
mRedirectCallback = nsnull ;
2007-03-22 10:30:00 -07:00
}
/////////////////////////////////////////////////////
// nsIProgressEventSink methods:
//
NS_IMETHODIMP
nsXMLHttpRequest : : OnProgress ( nsIRequest * aRequest , nsISupports * aContext , PRUint64 aProgress , PRUint64 aProgressMax )
{
2008-09-11 03:44:15 -07:00
// We're in middle of processing multipart headers and we don't want to report
// any progress because upload's 'load' is dispatched when we start to load
// the first response.
if ( XML_HTTP_REQUEST_MPART_HEADERS & mState ) {
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
// We're uploading if our state is XML_HTTP_REQUEST_OPENED or
// XML_HTTP_REQUEST_SENT
2008-08-14 04:07:46 -07:00
PRBool upload = ! ! ( ( XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT ) & mState ) ;
PRUint64 loaded = aProgress ;
PRUint64 total = aProgressMax ;
// When uploading, OnProgress reports also headers in aProgress and aProgressMax.
// So, try to remove the headers, if possible.
PRBool lengthComputable = ( aProgressMax ! = LL_MAXUINT ) ;
if ( upload ) {
if ( lengthComputable ) {
2008-10-21 02:06:53 -07:00
PRUint64 headerSize = aProgressMax - mUploadTotal ;
2008-08-14 04:07:46 -07:00
loaded - = headerSize ;
total - = headerSize ;
}
mUploadTransferred = loaded ;
2008-10-19 14:26:37 -07:00
mUploadProgress = aProgress ;
mUploadProgressMax = aProgressMax ;
} else {
mLoadLengthComputable = lengthComputable ;
mLoadTotal = mLoadLengthComputable ? total : 0 ;
}
if ( mTimerIsActive ) {
// The progress event will be dispatched when the notifier calls Notify().
mProgressEventWasDelayed = PR_TRUE ;
return NS_OK ;
2008-08-14 04:07:46 -07:00
}
2007-03-22 10:30:00 -07:00
2009-03-03 12:11:14 -08:00
if ( ! mErrorLoad & & ( mState & XML_HTTP_REQUEST_ASYNC ) ) {
2008-10-19 14:26:37 -07:00
StartProgressEventTimer ( ) ;
2008-08-14 04:07:46 -07:00
NS_NAMED_LITERAL_STRING ( progress , PROGRESS_STR ) ;
NS_NAMED_LITERAL_STRING ( uploadprogress , UPLOADPROGRESS_STR ) ;
DispatchProgressEvent ( this , upload ? uploadprogress : progress , PR_TRUE ,
lengthComputable , loaded , lengthComputable ? total : 0 ,
aProgress , aProgressMax ) ;
2008-08-14 04:04:43 -07:00
2008-10-19 14:26:37 -07:00
if ( upload & & mUpload & & ! mUploadComplete ) {
2008-10-21 02:06:53 -07:00
NS_WARN_IF_FALSE ( mUploadTotal = = total , " Wrong upload total? " ) ;
2008-08-14 04:07:46 -07:00
DispatchProgressEvent ( mUpload , progress , PR_TRUE , lengthComputable , loaded ,
lengthComputable ? total : 0 , aProgress , aProgressMax ) ;
}
}
2007-03-22 10:30:00 -07:00
if ( mProgressEventSink ) {
mProgressEventSink - > OnProgress ( aRequest , aContext , aProgress ,
aProgressMax ) ;
}
return NS_OK ;
}
NS_IMETHODIMP
nsXMLHttpRequest : : OnStatus ( nsIRequest * aRequest , nsISupports * aContext , nsresult aStatus , const PRUnichar * aStatusArg )
{
if ( mProgressEventSink ) {
mProgressEventSink - > OnStatus ( aRequest , aContext , aStatus , aStatusArg ) ;
}
return NS_OK ;
}
2008-09-30 17:51:53 -07:00
PRBool
nsXMLHttpRequest : : AllowUploadProgress ( )
{
return ! ( mState & XML_HTTP_REQUEST_USE_XSITE_AC ) | |
( mState & XML_HTTP_REQUEST_NEED_AC_PREFLIGHT ) ;
}
2007-03-22 10:30:00 -07:00
/////////////////////////////////////////////////////
// nsIInterfaceRequestor methods:
//
NS_IMETHODIMP
nsXMLHttpRequest : : GetInterface ( const nsIID & aIID , void * * aResult )
{
2008-04-08 17:27:50 -07:00
nsresult rv ;
2007-03-22 10:30:00 -07: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 ) ;
2007-07-08 00:08:04 -07:00
* aResult = static_cast < nsIChannelEventSink * > ( this ) ;
2007-03-22 10:30:00 -07:00
NS_ADDREF_THIS ( ) ;
return NS_OK ;
} else if ( aIID . Equals ( NS_GET_IID ( nsIProgressEventSink ) ) ) {
mProgressEventSink = do_GetInterface ( mNotificationCallbacks ) ;
2007-07-08 00:08:04 -07:00
* aResult = static_cast < nsIProgressEventSink * > ( this ) ;
2007-03-22 10:30:00 -07:00
NS_ADDREF_THIS ( ) ;
return NS_OK ;
}
// Now give mNotificationCallbacks (if non-null) a chance to return the
2008-03-18 11:18:29 -07:00
// desired interface.
2007-03-22 10:30:00 -07:00
if ( mNotificationCallbacks ) {
2008-04-08 17:27:50 -07:00
rv = mNotificationCallbacks - > GetInterface ( aIID , aResult ) ;
2007-03-22 10:30:00 -07:00
if ( NS_SUCCEEDED ( rv ) ) {
NS_ASSERTION ( * aResult , " Lying nsIInterfaceRequestor implementation! " ) ;
return rv ;
}
}
2008-03-18 17:14:38 -07:00
if ( mState & XML_HTTP_REQUEST_BACKGROUND ) {
nsCOMPtr < nsIInterfaceRequestor > badCertHandler ( do_CreateInstance ( NS_BADCERTHANDLER_CONTRACTID , & rv ) ) ;
// Ignore failure to get component, we may not have all its dependencies
// available
if ( NS_SUCCEEDED ( rv ) ) {
rv = badCertHandler - > GetInterface ( aIID , aResult ) ;
if ( NS_SUCCEEDED ( rv ) )
return rv ;
}
}
2008-04-08 17:27:50 -07:00
else if ( aIID . Equals ( NS_GET_IID ( nsIAuthPrompt ) ) | |
aIID . Equals ( NS_GET_IID ( nsIAuthPrompt2 ) ) ) {
nsCOMPtr < nsIPromptFactory > wwatch =
do_GetService ( NS_WINDOWWATCHER_CONTRACTID , & rv ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
// Get the an auth prompter for our window so that the parenting
// of the dialogs works as it should when using tabs.
nsCOMPtr < nsIDOMWindow > window ;
if ( mOwner ) {
window = mOwner - > GetOuterWindow ( ) ;
}
return wwatch - > GetPrompt ( window , aIID ,
reinterpret_cast < void * * > ( aResult ) ) ;
}
2008-03-18 17:14:38 -07:00
2007-03-22 10:30:00 -07:00
return QueryInterface ( aIID , aResult ) ;
}
2008-08-14 04:07:46 -07:00
NS_IMETHODIMP
nsXMLHttpRequest : : GetUpload ( nsIXMLHttpRequestUpload * * aUpload )
2008-08-14 04:04:43 -07:00
{
2008-08-14 04:07:46 -07:00
* aUpload = nsnull ;
2009-04-24 02:18:37 -07:00
nsresult rv ;
nsIScriptContext * scriptContext =
GetContextForEventHandlers ( & rv ) ;
2008-09-25 07:40:30 -07:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2008-08-14 04:07:46 -07:00
if ( ! mUpload ) {
2008-09-25 07:40:30 -07:00
mUpload = new nsXMLHttpRequestUpload ( mOwner , scriptContext ) ;
2008-08-14 04:07:46 -07:00
NS_ENSURE_TRUE ( mUpload , NS_ERROR_OUT_OF_MEMORY ) ;
2008-08-14 04:04:43 -07:00
}
2008-08-14 04:07:46 -07:00
NS_ADDREF ( * aUpload = mUpload ) ;
2008-08-14 04:04:43 -07:00
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
2008-10-19 14:26:37 -07:00
NS_IMETHODIMP
nsXMLHttpRequest : : Notify ( nsITimer * aTimer )
{
mTimerIsActive = PR_FALSE ;
2009-03-03 12:11:14 -08:00
if ( NS_SUCCEEDED ( CheckInnerWindowCorrectness ( ) ) & & ! mErrorLoad & &
( mState & XML_HTTP_REQUEST_ASYNC ) ) {
2008-10-19 14:26:37 -07:00
if ( mProgressEventWasDelayed ) {
mProgressEventWasDelayed = PR_FALSE ;
if ( ! ( XML_HTTP_REQUEST_MPART_HEADERS & mState ) ) {
StartProgressEventTimer ( ) ;
// We're uploading if our state is XML_HTTP_REQUEST_OPENED or
// XML_HTTP_REQUEST_SENT
if ( ( XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT ) & mState ) {
DispatchProgressEvent ( this , NS_LITERAL_STRING ( UPLOADPROGRESS_STR ) ,
PR_TRUE , PR_TRUE , mUploadTransferred ,
mUploadTotal , mUploadProgress ,
mUploadProgressMax ) ;
if ( mUpload & & ! mUploadComplete ) {
DispatchProgressEvent ( mUpload , NS_LITERAL_STRING ( PROGRESS_STR ) ,
PR_TRUE , PR_TRUE , mUploadTransferred ,
mUploadTotal , mUploadProgress ,
mUploadProgressMax ) ;
}
} else {
DispatchProgressEvent ( this , NS_LITERAL_STRING ( PROGRESS_STR ) ,
mLoadLengthComputable , mResponseBody . Length ( ) ,
mLoadTotal ) ;
}
}
}
} else if ( mProgressNotifier ) {
mProgressNotifier - > Cancel ( ) ;
}
return NS_OK ;
}
void
nsXMLHttpRequest : : StartProgressEventTimer ( )
{
if ( ! mProgressNotifier ) {
mProgressNotifier = do_CreateInstance ( NS_TIMER_CONTRACTID ) ;
}
if ( mProgressNotifier ) {
mProgressEventWasDelayed = PR_FALSE ;
mTimerIsActive = PR_TRUE ;
mProgressNotifier - > Cancel ( ) ;
mProgressNotifier - > InitWithCallback ( this , NS_PROGRESS_EVENT_INTERVAL ,
nsITimer : : TYPE_ONE_SHOT ) ;
}
}
2007-03-22 10:30:00 -07:00
NS_IMPL_ISUPPORTS1 ( nsXMLHttpRequest : : nsHeaderVisitor , nsIHttpHeaderVisitor )
NS_IMETHODIMP nsXMLHttpRequest : :
nsHeaderVisitor : : VisitHeader ( const nsACString & header , const nsACString & value )
{
2008-11-13 18:18:01 -08:00
// See bug #380418. Hide "Set-Cookie" headers from non-chrome scripts.
PRBool chrome = PR_FALSE ; // default to false in case IsCapabilityEnabled fails
IsCapabilityEnabled ( " UniversalXPConnect " , & chrome ) ;
if ( ! chrome & &
( header . LowerCaseEqualsASCII ( " set-cookie " ) | |
header . LowerCaseEqualsASCII ( " set-cookie2 " ) ) ) {
NS_WARNING ( " blocked access to response header " ) ;
} else {
mHeaders . Append ( header ) ;
mHeaders . Append ( " : " ) ;
mHeaders . Append ( value ) ;
mHeaders . Append ( ' \n ' ) ;
}
2007-03-22 10:30:00 -07:00
return NS_OK ;
}
// DOM event class to handle progress notifications
2008-08-14 04:07:46 -07:00
nsXMLHttpProgressEvent : : nsXMLHttpProgressEvent ( nsIDOMProgressEvent * aInner ,
PRUint64 aCurrentProgress ,
PRUint64 aMaxProgress )
2007-03-22 10:30:00 -07:00
{
2008-08-14 04:07:46 -07:00
mInner = static_cast < nsDOMProgressEvent * > ( aInner ) ;
2007-03-22 10:30:00 -07:00
mCurProgress = aCurrentProgress ;
mMaxProgress = aMaxProgress ;
}
nsXMLHttpProgressEvent : : ~ nsXMLHttpProgressEvent ( )
{ }
2008-08-14 04:07:46 -07:00
NS_IMPL_CYCLE_COLLECTION_CLASS ( nsXMLHttpProgressEvent )
2010-01-12 05:08:43 -08:00
DOMCI_DATA ( XMLHttpProgressEvent , nsXMLHttpProgressEvent )
2008-08-14 04:07:46 -07:00
// QueryInterface implementation for nsXMLHttpProgressEvent
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION ( nsXMLHttpProgressEvent )
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS ( nsISupports , nsIDOMProgressEvent )
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS ( nsIDOMEvent , nsIDOMProgressEvent )
NS_INTERFACE_MAP_ENTRY ( nsIDOMNSEvent )
NS_INTERFACE_MAP_ENTRY ( nsIPrivateDOMEvent )
NS_INTERFACE_MAP_ENTRY ( nsIDOMProgressEvent )
2007-03-22 10:30:00 -07:00
NS_INTERFACE_MAP_ENTRY ( nsIDOMLSProgressEvent )
2010-03-17 08:09:05 -07:00
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO ( XMLHttpProgressEvent )
2007-03-22 10:30:00 -07:00
NS_INTERFACE_MAP_END
2008-08-14 04:07:46 -07:00
NS_IMPL_CYCLE_COLLECTING_ADDREF ( nsXMLHttpProgressEvent )
NS_IMPL_CYCLE_COLLECTING_RELEASE ( nsXMLHttpProgressEvent )
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN ( nsXMLHttpProgressEvent )
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR ( mInner ) ;
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN ( nsXMLHttpProgressEvent )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS ( mInner ,
nsIDOMProgressEvent )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
2007-03-22 10:30:00 -07:00
NS_IMETHODIMP nsXMLHttpProgressEvent : : GetInput ( nsIDOMLSInput * * aInput )
{
* aInput = nsnull ;
return NS_ERROR_NOT_IMPLEMENTED ;
}
NS_IMETHODIMP nsXMLHttpProgressEvent : : GetPosition ( PRUint32 * aPosition )
{
// XXX can we change the iface?
LL_L2UI ( * aPosition , mCurProgress ) ;
return NS_OK ;
}
NS_IMETHODIMP nsXMLHttpProgressEvent : : GetTotalSize ( PRUint32 * aTotalSize )
{
// XXX can we change the iface?
LL_L2UI ( * aTotalSize , mMaxProgress ) ;
return NS_OK ;
}
2008-08-14 04:07:46 -07:00