2013-01-17 21:21:43 -08:00
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
2012-05-21 04:12:37 -07:00
/* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2.0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/. */
2007-03-22 10:30:00 -07:00
2013-08-21 23:29:30 -07:00
# include "nsXMLHttpRequest.h"
# include "mozilla/dom/XMLHttpRequestUploadBinding.h"
2013-06-23 05:03:39 -07:00
# include "mozilla/MemoryReporting.h"
2011-10-10 22:50:08 -07:00
# include "mozilla/Util.h"
2013-08-21 23:29:30 -07:00
# include "nsDOMBlobBuilder.h"
2007-03-22 10:30:00 -07:00
# include "nsICharsetConverterManager.h"
2013-08-21 23:30:55 -07:00
# include "nsIDOMDocument.h"
2013-08-21 23:29:30 -07:00
# include "nsIDOMProgressEvent.h"
# include "nsIJARChannel.h"
2007-03-22 10:30:00 -07:00
# include "nsLayoutCID.h"
# include "nsReadableUtils.h"
2013-08-21 23:29:30 -07:00
2007-03-22 10:30:00 -07:00
# 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 "nsIDOMEventListener.h"
# include "nsIScriptSecurityManager.h"
# include "nsIDOMWindow.h"
# include "nsIVariant.h"
2011-12-24 00:27:04 -08:00
# include "nsVariant.h"
# include "nsIScriptError.h"
2007-03-22 10:30:00 -07:00
# include "nsIStreamConverterService.h"
# include "nsICachingChannel.h"
# include "nsContentUtils.h"
2013-05-22 09:05:26 -07:00
# include "nsCxPusher.h"
2007-03-22 10:30:00 -07:00
# include "nsEventDispatcher.h"
# include "nsCycleCollectionParticipant.h"
2007-03-24 22:35:39 -07:00
# include "nsIContentPolicy.h"
# include "nsContentPolicyUtils.h"
2012-07-27 07:03:27 -07:00
# include "nsError.h"
2008-09-30 17:49:30 -07:00
# include "nsCrossSiteListenerProxy.h"
2007-07-26 19:49:18 -07:00
# include "nsIHTMLDocument.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"
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-11-23 08:49:12 -08:00
# include "nsStringBuffer.h"
2011-05-10 16:18:55 -07:00
# include "nsDOMFile.h"
# include "nsIFileChannel.h"
2011-11-19 10:50:17 -08:00
# include "mozilla/Telemetry.h"
2012-01-14 09:43:00 -08:00
# include "jsfriendapi.h"
2013-03-18 07:25:50 -07:00
# include "GeckoProfiler.h"
2012-11-07 15:04:22 -08:00
# include "mozilla/dom/EncodingUtils.h"
2012-05-02 21:35:38 -07:00
# include "mozilla/dom/XMLHttpRequestBinding.h"
2012-06-18 19:30:09 -07:00
# include "mozilla/Attributes.h"
2012-08-17 17:42:00 -07:00
# include "nsIPermissionManager.h"
2012-08-27 16:34:30 -07:00
# include "nsMimeTypes.h"
2012-12-04 15:06:29 -08:00
# include "nsIHttpChannelInternal.h"
2013-08-22 02:22:03 -07:00
# include "nsCharSeparatedTokenizer.h"
2012-12-11 10:09:56 -08:00
# include "nsFormData.h"
# include "nsStreamListenerWrapper.h"
2013-09-06 10:50:24 -07:00
# include "xpcjsid.h"
2012-03-26 08:38:06 -07:00
2012-01-26 07:55:30 -08:00
# include "nsWrapperCacheInlines.h"
2007-03-22 10:30:00 -07:00
2011-10-10 22:50:08 -07:00
using namespace mozilla ;
2012-03-26 08:38:06 -07:00
using namespace mozilla : : dom ;
2011-10-10 22:50:08 -07:00
2013-04-27 12:25:24 -07:00
// Maximum size that we'll grow an ArrayBuffer instead of doubling,
// once doubling reaches this threshold
# define XML_HTTP_REQUEST_ARRAYBUFFER_MAX_GROWTH (32*1024*1024)
// start at 32k to avoid lots of doubling right at the start
# define XML_HTTP_REQUEST_ARRAYBUFFER_MIN_SIZE (32*1024)
2013-05-15 11:42:10 -07:00
// the maximum Content-Length that we'll preallocate. 1GB. Must fit
// in an int32_t!
# define XML_HTTP_REQUEST_MAX_CONTENT_LENGTH_PREALLOCATE (1*1024*1024*1024LL)
2013-04-27 12:25:24 -07:00
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"
2012-01-26 02:02:22 -08:00
# define TIMEOUT_STR "timeout"
2008-08-14 04:07:46 -07:00
# define LOADSTART_STR "loadstart"
2007-03-22 10:30:00 -07:00
# define PROGRESS_STR "progress"
# 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
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_BACKGROUND (1 << 13) // Internal
2013-03-04 01:06:15 -08:00
# define XML_HTTP_REQUEST_USE_XSITE_AC (1 << 14) // Internal
# define XML_HTTP_REQUEST_NEED_AC_PREFLIGHT (1 << 15) // Internal
# define XML_HTTP_REQUEST_AC_WITH_CREDENTIALS (1 << 16) // Internal
# define XML_HTTP_REQUEST_TIMED_OUT (1 << 17) // Internal
# define XML_HTTP_REQUEST_DELETED (1 << 18) // 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 | \
2012-11-21 22:25:01 -08:00
XML_HTTP_REQUEST_SENT )
2007-03-22 10:30:00 -07:00
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
2013-06-12 22:20:10 -07:00
# define IMPL_CSTRING_GETTER(_name) \
2012-03-26 08:38:06 -07:00
NS_IMETHODIMP \
2013-06-12 22:20:10 -07:00
nsXMLHttpRequest : : _name ( nsACString & aOut ) \
2012-03-26 08:38:06 -07:00
{ \
2013-06-12 22:20:10 -07:00
nsCString tmp ; \
2012-03-26 08:38:06 -07:00
_name ( tmp ) ; \
aOut = tmp ; \
return NS_OK ; \
}
2011-11-15 23:38:51 -08:00
NS_IMPL_ISUPPORTS1 ( nsXHRParseEndListener , nsIDOMEventListener )
2009-03-03 12:11:14 -08:00
class nsResumeTimeoutsEvent : public nsRunnable
{
public :
nsResumeTimeoutsEvent ( nsPIDOMWindow * aWindow ) : mWindow ( aWindow ) { }
NS_IMETHOD Run ( )
{
2011-10-17 07:59:28 -07:00
mWindow - > ResumeTimeouts ( false ) ;
2009-03-03 12:11:14 -08:00
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 ) ;
}
2012-10-07 04:40:10 -07:00
//-----------------------------------------------------------------------------
// XMLHttpRequestAuthPrompt
//-----------------------------------------------------------------------------
class XMLHttpRequestAuthPrompt : public nsIAuthPrompt
{
public :
NS_DECL_ISUPPORTS
NS_DECL_NSIAUTHPROMPT
XMLHttpRequestAuthPrompt ( ) ;
virtual ~ XMLHttpRequestAuthPrompt ( ) ;
} ;
NS_IMPL_ISUPPORTS1 ( XMLHttpRequestAuthPrompt , nsIAuthPrompt )
XMLHttpRequestAuthPrompt : : XMLHttpRequestAuthPrompt ( )
{
MOZ_COUNT_CTOR ( XMLHttpRequestAuthPrompt ) ;
}
XMLHttpRequestAuthPrompt : : ~ XMLHttpRequestAuthPrompt ( )
{
MOZ_COUNT_DTOR ( XMLHttpRequestAuthPrompt ) ;
}
NS_IMETHODIMP
XMLHttpRequestAuthPrompt : : Prompt ( const PRUnichar * aDialogTitle ,
const PRUnichar * aText ,
const PRUnichar * aPasswordRealm ,
uint32_t aSavePassword ,
const PRUnichar * aDefaultText ,
PRUnichar * * aResult ,
bool * aRetval )
{
* aRetval = false ;
return NS_OK ;
}
NS_IMETHODIMP
XMLHttpRequestAuthPrompt : : PromptUsernameAndPassword ( const PRUnichar * aDialogTitle ,
const PRUnichar * aDialogText ,
const PRUnichar * aPasswordRealm ,
uint32_t aSavePassword ,
PRUnichar * * aUser ,
PRUnichar * * aPwd ,
bool * aRetval )
{
* aRetval = false ;
return NS_OK ;
}
NS_IMETHODIMP
XMLHttpRequestAuthPrompt : : PromptPassword ( const PRUnichar * aDialogTitle ,
const PRUnichar * aText ,
const PRUnichar * aPasswordRealm ,
uint32_t aSavePassword ,
PRUnichar * * aPwd ,
bool * aRetval )
{
* aRetval = false ;
return NS_OK ;
}
2008-08-14 04:07:46 -07:00
/////////////////////////////////////////////
2013-08-01 18:29:05 -07:00
NS_IMPL_CYCLE_COLLECTION_CLASS ( nsXHREventTarget )
2009-06-15 01:27:29 -07:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED ( nsXHREventTarget ,
2012-02-07 18:53:33 -08:00
nsDOMEventTargetHelper )
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 ,
2012-02-07 18:53:33 -08:00
nsDOMEventTargetHelper )
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 )
2012-02-07 18:53:33 -08:00
NS_INTERFACE_MAP_END_INHERITING ( nsDOMEventTargetHelper )
2008-08-14 04:07:46 -07:00
2012-02-07 18:53:33 -08:00
NS_IMPL_ADDREF_INHERITED ( nsXHREventTarget , nsDOMEventTargetHelper )
NS_IMPL_RELEASE_INHERITED ( nsXHREventTarget , nsDOMEventTargetHelper )
2008-08-14 04:07:46 -07:00
2012-08-30 20:45:16 -07:00
NS_IMPL_EVENT_HANDLER ( nsXHREventTarget , loadstart )
NS_IMPL_EVENT_HANDLER ( nsXHREventTarget , progress )
NS_IMPL_EVENT_HANDLER ( nsXHREventTarget , abort )
NS_IMPL_EVENT_HANDLER ( nsXHREventTarget , error )
NS_IMPL_EVENT_HANDLER ( nsXHREventTarget , load )
NS_IMPL_EVENT_HANDLER ( nsXHREventTarget , timeout )
NS_IMPL_EVENT_HANDLER ( nsXHREventTarget , loadend )
2012-03-12 17:56:07 -07:00
void
nsXHREventTarget : : DisconnectFromOwner ( )
{
nsDOMEventTargetHelper : : DisconnectFromOwner ( ) ;
2011-03-24 06:22:03 -07:00
}
2008-09-25 07:40:30 -07:00
/////////////////////////////////////////////
2008-08-14 04:07:46 -07:00
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 )
NS_INTERFACE_MAP_END_INHERITING ( nsXHREventTarget )
NS_IMPL_ADDREF_INHERITED ( nsXMLHttpRequestUpload , nsXHREventTarget )
NS_IMPL_RELEASE_INHERITED ( nsXMLHttpRequestUpload , nsXHREventTarget )
2013-08-21 23:29:30 -07:00
/* virtual */ JSObject *
nsXMLHttpRequestUpload : : WrapObject ( JSContext * aCx , JS : : Handle < JSObject * > aScope )
{
return XMLHttpRequestUploadBinding : : Wrap ( aCx , aScope , this ) ;
}
2007-03-22 10:30:00 -07:00
/////////////////////////////////////////////
//
//
/////////////////////////////////////////////
nsXMLHttpRequest : : nsXMLHttpRequest ( )
2011-09-23 18:57:36 -07:00
: mResponseBodyDecodedPos ( 0 ) ,
mResponseType ( XML_HTTP_RESPONSE_TYPE_DEFAULT ) ,
2012-07-30 07:20:58 -07:00
mRequestObserver ( nullptr ) , mState ( XML_HTTP_REQUEST_UNSENT ) ,
2011-10-17 07:59:28 -07:00
mUploadTransferred ( 0 ) , mUploadTotal ( 0 ) , mUploadComplete ( true ) ,
mProgressSinceLastProgressEvent ( false ) ,
2012-01-26 02:02:22 -08:00
mRequestSentTime ( 0 ) , mTimeoutMilliseconds ( 0 ) ,
2012-02-16 08:45:25 -08:00
mErrorLoad ( false ) , mWaitingForOnStopRequest ( false ) ,
2013-08-21 07:59:08 -07:00
mProgressTimerIsActive ( false ) ,
2011-11-15 23:38:51 -08:00
mIsHtml ( false ) ,
mWarnAboutSyncHtml ( false ) ,
2012-01-26 02:02:22 -08:00
mLoadLengthComputable ( false ) , mLoadTotal ( 0 ) ,
2012-07-08 18:09:51 -07:00
mIsSystem ( false ) ,
mIsAnon ( false ) ,
2011-10-17 07:59:28 -07:00
mFirstStartRequestSeen ( false ) ,
mInLoadProgressEvent ( false ) ,
2011-09-23 18:57:22 -07:00
mResultJSON ( JSVAL_VOID ) ,
2012-09-07 07:51:35 -07:00
mResultArrayBuffer ( nullptr ) ,
mXPCOMifier ( nullptr )
2007-03-22 10:30:00 -07:00
{
2012-03-30 21:42:20 -07:00
SetIsDOMBinding ( ) ;
2012-03-26 08:38:06 -07:00
# ifdef DEBUG
StaticAssertions ( ) ;
# endif
2007-03-22 10:30:00 -07:00
}
nsXMLHttpRequest : : ~ nsXMLHttpRequest ( )
{
2012-02-14 10:05:43 -08:00
mState | = XML_HTTP_REQUEST_DELETED ;
2012-11-21 22:25:01 -08:00
if ( mState & ( 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 ;
2013-05-15 04:48:55 -07:00
mResultJSON = JSVAL_VOID ;
mResultArrayBuffer = nullptr ;
2013-08-16 13:10:17 -07:00
mozilla : : DropJSObjects ( this ) ;
2007-03-22 10:30:00 -07:00
}
2011-05-23 18:09:28 -07:00
void
2012-08-05 08:41:13 -07:00
nsXMLHttpRequest : : RootJSResultObjects ( )
2011-05-23 18:09:28 -07:00
{
2013-08-16 13:10:17 -07:00
mozilla : : HoldJSObjects ( this ) ;
2011-05-23 18:09:28 -07:00
}
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 ( )
{
2012-06-08 13:45:13 -07:00
nsIScriptSecurityManager * secMan = nsContentUtils : : GetSecurityManager ( ) ;
2007-12-12 00:33:32 -08:00
nsCOMPtr < nsIPrincipal > subjectPrincipal ;
if ( secMan ) {
2012-06-08 13:45:13 -07:00
secMan - > GetSystemPrincipal ( getter_AddRefs ( subjectPrincipal ) ) ;
2007-12-12 00:33:32 -08:00
}
NS_ENSURE_STATE ( subjectPrincipal ) ;
2013-04-04 02:30:36 -07:00
// Instead of grabbing some random global from the context stack,
2013-07-16 06:04:28 -07:00
// let's use the default one (junk scope) for now.
2013-04-04 02:30:36 -07:00
// We should move away from this Init...
2013-07-16 06:04:28 -07:00
nsCOMPtr < nsIGlobalObject > global = xpc : : GetJunkScopeGlobal ( ) ;
NS_ENSURE_TRUE ( global , NS_ERROR_FAILURE ) ;
Construct ( subjectPrincipal , global ) ;
2008-02-19 15:12:23 -08:00
return NS_OK ;
}
2012-06-08 13:45:13 -07:00
2008-02-19 15:12:23 -08:00
/**
* This Init method should only be called by C + + consumers .
*/
NS_IMETHODIMP
nsXMLHttpRequest : : Init ( nsIPrincipal * aPrincipal ,
nsIScriptContext * aScriptContext ,
2013-04-04 02:30:36 -07:00
nsIGlobalObject * aGlobalObject ,
2008-12-30 14:24:58 -08:00
nsIURI * aBaseURI )
2008-02-19 15:12:23 -08:00
{
NS_ENSURE_ARG_POINTER ( aPrincipal ) ;
2013-04-04 02:30:36 -07:00
if ( nsCOMPtr < nsPIDOMWindow > win = do_QueryInterface ( aGlobalObject ) ) {
if ( win - > IsOuterWindow ( ) ) {
// Must be bound to inner window, innerize if necessary.
nsCOMPtr < nsIGlobalObject > inner = do_QueryInterface (
win - > GetCurrentInnerWindow ( ) ) ;
aGlobalObject = inner . get ( ) ;
}
}
Construct ( aPrincipal , aGlobalObject , aBaseURI ) ;
2007-12-12 00:33:32 -08:00
return NS_OK ;
}
2012-06-21 00:21:55 -07:00
void
nsXMLHttpRequest : : InitParameters ( bool aAnon , bool aSystem )
{
2012-09-16 17:20:16 -07:00
if ( ! aAnon & & ! aSystem ) {
return ;
}
2012-06-07 11:28:33 -07:00
// Check for permissions.
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( GetOwner ( ) ) ;
2012-06-21 00:21:55 -07:00
if ( ! window | | ! window - > GetDocShell ( ) ) {
return ;
}
2012-06-07 11:28:33 -07:00
// Chrome is always allowed access, so do the permission check only
// for non-chrome pages.
2013-07-03 14:04:43 -07:00
if ( ! IsSystemXHR ( ) ) {
2013-04-23 21:22:37 -07:00
nsCOMPtr < nsIDocument > doc = window - > GetExtantDoc ( ) ;
2012-06-21 00:21:55 -07:00
if ( ! doc ) {
return ;
}
2012-06-07 11:28:33 -07:00
2012-08-17 17:42:00 -07:00
nsCOMPtr < nsIPrincipal > principal = doc - > NodePrincipal ( ) ;
nsCOMPtr < nsIPermissionManager > permMgr =
do_GetService ( NS_PERMISSIONMANAGER_CONTRACTID ) ;
if ( ! permMgr )
return ;
2012-08-22 08:56:38 -07:00
uint32_t permission ;
2012-08-17 17:42:00 -07:00
nsresult rv =
permMgr - > TestPermissionFromPrincipal ( principal , " systemXHR " , & permission ) ;
if ( NS_FAILED ( rv ) | | permission ! = nsIPermissionManager : : ALLOW_ACTION ) {
2012-06-21 00:21:55 -07:00
return ;
2012-06-07 11:28:33 -07:00
}
}
2012-09-16 17:20:16 -07:00
SetParameters ( aAnon , aSystem ) ;
2007-12-12 00:33:32 -08:00
}
2011-09-23 18:57:22 -07:00
void
nsXMLHttpRequest : : ResetResponse ( )
{
2012-07-30 07:20:58 -07:00
mResponseXML = nullptr ;
2011-09-23 18:57:22 -07:00
mResponseBody . Truncate ( ) ;
2011-09-23 18:57:36 -07:00
mResponseText . Truncate ( ) ;
2012-07-30 07:20:58 -07:00
mResponseBlob = nullptr ;
mDOMFile = nullptr ;
2012-09-20 00:55:36 -07:00
mBlobSet = nullptr ;
2012-07-30 07:20:58 -07:00
mResultArrayBuffer = nullptr ;
2013-05-15 11:42:10 -07:00
mArrayBufferBuilder . reset ( ) ;
2011-09-23 18:57:22 -07:00
mResultJSON = JSVAL_VOID ;
mLoadTransferred = 0 ;
2011-09-23 18:57:36 -07:00
mResponseBodyDecodedPos = 0 ;
2011-09-23 18:57:22 -07:00
}
2008-09-30 16:56:57 -07:00
void
nsXMLHttpRequest : : SetRequestObserver ( nsIRequestObserver * aObserver )
{
mRequestObserver = aObserver ;
}
2013-08-01 18:29:05 -07:00
NS_IMPL_CYCLE_COLLECTION_CLASS ( nsXMLHttpRequest )
2012-01-26 07:55:30 -08:00
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN ( nsXMLHttpRequest )
2012-02-16 08:45:25 -08:00
bool isBlack = tmp - > IsBlack ( ) ;
if ( isBlack | | tmp - > mWaitingForOnStopRequest ) {
2012-01-26 07:55:30 -08:00
if ( tmp - > mListenerManager ) {
2012-10-16 18:22:02 -07:00
tmp - > mListenerManager - > MarkForCC ( ) ;
2012-01-26 07:55:30 -08:00
}
2012-03-14 07:22:10 -07:00
if ( ! isBlack & & tmp - > PreservingWrapper ( ) ) {
2013-09-08 20:28:48 -07:00
// This marks the wrapper black.
tmp - > GetWrapper ( ) ;
2012-02-16 08:45:25 -08:00
}
2012-01-26 07:55:30 -08:00
return true ;
}
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN ( nsXMLHttpRequest )
2012-09-28 15:29:37 -07:00
return tmp - >
IsBlackAndDoesNotNeedTracing ( static_cast < nsDOMEventTargetHelper * > ( tmp ) ) ;
2012-01-26 07:55:30 -08:00
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN ( nsXMLHttpRequest )
return tmp - > IsBlack ( ) ;
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
2008-08-14 04:07:46 -07:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED ( nsXMLHttpRequest ,
nsXHREventTarget )
2012-11-14 23:32:40 -08:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mContext )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mChannel )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mResponseXML )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mCORSPreflightChannel )
2007-03-22 10:30:00 -07:00
2012-11-14 23:32:40 -08:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mXMLParserStreamListener )
2007-03-22 10:30:00 -07:00
2012-11-14 23:32:40 -08:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mChannelEventSink )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mProgressEventSink )
2007-12-12 00:33:32 -08:00
2012-11-14 23:32:40 -08:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mUpload )
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 )
2012-07-30 07:20:58 -07:00
tmp - > mResultArrayBuffer = nullptr ;
2013-05-15 11:42:10 -07:00
tmp - > mArrayBufferBuilder . reset ( ) ;
2011-09-08 15:12:18 -07:00
tmp - > mResultJSON = JSVAL_VOID ;
2012-11-14 23:32:40 -08:00
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mContext )
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mChannel )
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mResponseXML )
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mCORSPreflightChannel )
2007-03-22 10:30:00 -07:00
2012-11-14 23:32:40 -08:00
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mXMLParserStreamListener )
2007-03-22 10:30:00 -07:00
2012-11-14 23:32:40 -08:00
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mChannelEventSink )
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mProgressEventSink )
2007-12-12 00:33:32 -08:00
2012-11-14 23:32:40 -08:00
NS_IMPL_CYCLE_COLLECTION_UNLINK ( 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 )
2012-05-15 09:56:39 -07:00
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK ( mResultArrayBuffer )
NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK ( mResultJSON )
2011-05-23 18:09:28 -07:00
NS_IMPL_CYCLE_COLLECTION_TRACE_END
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 ( 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 )
2008-10-19 14:26:37 -07:00
NS_INTERFACE_MAP_ENTRY ( nsITimerCallback )
2013-01-17 21:21:43 -08:00
NS_INTERFACE_MAP_ENTRY ( nsISizeOfEventTarget )
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
2012-08-30 20:45:16 -07:00
NS_IMPL_EVENT_HANDLER ( nsXMLHttpRequest , readystatechange )
2012-03-12 17:56:07 -07:00
void
nsXMLHttpRequest : : DisconnectFromOwner ( )
{
nsXHREventTarget : : DisconnectFromOwner ( ) ;
2012-03-12 17:56:20 -07:00
Abort ( ) ;
2012-03-12 17:56:07 -07:00
}
2013-01-17 21:21:43 -08:00
size_t
nsXMLHttpRequest : : SizeOfEventTargetIncludingThis (
2013-06-23 05:03:39 -07:00
MallocSizeOf aMallocSizeOf ) const
2013-01-17 21:21:43 -08:00
{
size_t n = aMallocSizeOf ( this ) ;
n + = mResponseBody . SizeOfExcludingThisIfUnshared ( aMallocSizeOf ) ;
// Why is this safe? Because no-one else will report this string. The
// other possible sharers of this string are as follows.
//
// - The JS engine could hold copies if the JS code holds references, e.g.
// |var text = XHR.responseText|. However, those references will be via JS
// external strings, for which the JS memory reporter does *not* report the
// chars.
//
// - Binary extensions, but they're *extremely* unlikely to do any memory
// reporting.
//
n + = mResponseText . SizeOfExcludingThisEvenIfShared ( aMallocSizeOf ) ;
return n ;
// Measurement of the following members may be added later if DMD finds it is
// worthwhile:
// - lots
}
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 ;
}
2011-12-08 05:54:05 -08:00
static void LogMessage ( const char * aWarning , nsPIDOMWindow * aWindow )
{
nsCOMPtr < nsIDocument > doc ;
if ( aWindow ) {
2013-04-23 21:22:37 -07:00
doc = aWindow - > GetExtantDoc ( ) ;
2011-12-08 05:54:05 -08:00
}
2011-12-15 06:47:03 -08:00
nsContentUtils : : ReportToConsole ( nsIScriptError : : warningFlag ,
2013-08-21 12:28:26 -07:00
NS_LITERAL_CSTRING ( " DOM " ) , doc ,
2011-12-15 06:47:03 -08:00
nsContentUtils : : eDOM_PROPERTIES ,
aWarning ) ;
2011-12-08 05:54:05 -08:00
}
2007-03-22 10:30:00 -07:00
/* readonly attribute nsIDOMDocument responseXML; */
NS_IMETHODIMP
nsXMLHttpRequest : : GetResponseXML ( nsIDOMDocument * * aResponseXML )
{
2012-05-05 18:15:11 -07:00
ErrorResult rv ;
2012-03-26 08:38:06 -07:00
nsIDocument * responseXML = GetResponseXML ( rv ) ;
2012-05-05 18:15:11 -07:00
if ( rv . Failed ( ) ) {
return rv . ErrorCode ( ) ;
}
2012-03-26 08:38:06 -07:00
if ( ! responseXML ) {
2012-07-30 07:20:58 -07:00
* aResponseXML = nullptr ;
2012-03-26 08:38:06 -07:00
return NS_OK ;
}
return CallQueryInterface ( responseXML , aResponseXML ) ;
}
nsIDocument *
2012-05-05 18:15:11 -07:00
nsXMLHttpRequest : : GetResponseXML ( ErrorResult & aRv )
2012-03-26 08:38:06 -07:00
{
2011-05-10 16:18:55 -07:00
if ( mResponseType ! = XML_HTTP_RESPONSE_TYPE_DEFAULT & &
mResponseType ! = XML_HTTP_RESPONSE_TYPE_DOCUMENT ) {
2012-05-05 18:15:11 -07:00
aRv . Throw ( NS_ERROR_DOM_INVALID_STATE_ERR ) ;
2012-07-30 07:20:58 -07:00
return nullptr ;
2007-03-22 10:30:00 -07:00
}
2011-11-15 23:38:51 -08:00
if ( mWarnAboutSyncHtml ) {
mWarnAboutSyncHtml = false ;
2012-03-12 17:56:07 -07:00
LogMessage ( " HTMLSyncXHRWarning " , GetOwner ( ) ) ;
2011-11-15 23:38:51 -08:00
}
2012-07-30 07:20:58 -07:00
return ( XML_HTTP_REQUEST_DONE & mState ) ? mResponseXML : nullptr ;
2007-03-22 10:30:00 -07:00
}
/*
2013-03-20 09:22:26 -07:00
* This piece copied from XMLDocument , we try to get the charset
2007-03-22 10:30:00 -07:00
* from HTTP headers .
*/
nsresult
2011-09-23 18:57:36 -07:00
nsXMLHttpRequest : : DetectCharset ( )
2007-03-22 10:30:00 -07:00
{
2011-09-23 18:57:36 -07:00
mResponseCharset . Truncate ( ) ;
2012-07-30 07:20:58 -07:00
mDecoder = nullptr ;
2007-03-22 10:30:00 -07:00
2011-09-23 18:57:36 -07:00
if ( mResponseType ! = XML_HTTP_RESPONSE_TYPE_DEFAULT & &
mResponseType ! = XML_HTTP_RESPONSE_TYPE_TEXT & &
2011-09-23 18:57:36 -07:00
mResponseType ! = XML_HTTP_RESPONSE_TYPE_JSON & &
mResponseType ! = XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT ) {
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
2012-09-01 19:35:17 -07:00
nsAutoCString charsetVal ;
2013-03-04 01:06:15 -08:00
bool ok = mChannel & &
NS_SUCCEEDED ( mChannel - > GetContentCharset ( charsetVal ) ) & &
2012-11-07 15:04:22 -08:00
EncodingUtils : : FindEncodingForLabel ( charsetVal , mResponseCharset ) ;
if ( ! ok | | mResponseCharset . IsEmpty ( ) ) {
2011-09-23 18:57:36 -07:00
// MS documentation states UTF-8 is default for responseText
mResponseCharset . AssignLiteral ( " UTF-8 " ) ;
2010-04-23 10:37:02 -07:00
}
2007-03-22 10:30:00 -07:00
2011-12-08 05:56:14 -08:00
if ( mResponseType = = XML_HTTP_RESPONSE_TYPE_JSON & &
! mResponseCharset . EqualsLiteral ( " UTF-8 " ) ) {
// The XHR spec says only UTF-8 is supported for responseType == "json"
2012-03-12 17:56:07 -07:00
LogMessage ( " JSONCharsetWarning " , GetOwner ( ) ) ;
2011-12-08 05:56:14 -08:00
mResponseCharset . AssignLiteral ( " UTF-8 " ) ;
}
2012-11-07 15:04:22 -08:00
nsresult rv ;
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsICharsetConverterManager > ccm =
do_GetService ( NS_CHARSETCONVERTERMANAGER_CONTRACTID , & rv ) ;
2011-09-23 18:57:36 -07:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2007-03-22 10:30:00 -07:00
2011-09-23 18:57:36 -07:00
return ccm - > GetUnicodeDecoderRaw ( mResponseCharset . get ( ) ,
getter_AddRefs ( mDecoder ) ) ;
}
2007-03-22 10:30:00 -07:00
2011-09-23 18:57:36 -07:00
nsresult
nsXMLHttpRequest : : AppendToResponseText ( const char * aSrcBuffer ,
2012-08-22 08:56:38 -07:00
uint32_t aSrcBufferLen )
2011-09-23 18:57:36 -07:00
{
NS_ENSURE_STATE ( mDecoder ) ;
2012-08-22 08:56:38 -07:00
int32_t destBufferLen ;
2011-09-23 18:57:36 -07:00
nsresult rv = mDecoder - > GetMaxLength ( aSrcBuffer , aSrcBufferLen ,
& destBufferLen ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2007-03-22 10:30:00 -07:00
2012-05-08 10:55:24 -07:00
if ( ! mResponseText . SetCapacity ( mResponseText . Length ( ) + destBufferLen , fallible_t ( ) ) ) {
2007-03-22 10:30:00 -07:00
return NS_ERROR_OUT_OF_MEMORY ;
}
2011-09-23 18:57:36 -07:00
PRUnichar * destBuffer = mResponseText . BeginWriting ( ) + mResponseText . Length ( ) ;
2010-11-23 08:49:12 -08:00
2012-08-22 08:56:38 -07:00
int32_t totalChars = mResponseText . Length ( ) ;
2007-03-22 10:30:00 -07:00
2011-09-23 18:57:36 -07:00
// This code here is basically a copy of a similar thing in
2012-08-22 08:56:38 -07:00
// nsScanner::Append(const char* aBuffer, uint32_t aLen).
2012-12-10 06:11:15 -08:00
int32_t srclen = ( int32_t ) aSrcBufferLen ;
int32_t destlen = ( int32_t ) destBufferLen ;
rv = mDecoder - > Convert ( aSrcBuffer ,
& srclen ,
destBuffer ,
& destlen ) ;
MOZ_ASSERT ( NS_SUCCEEDED ( rv ) ) ;
totalChars + = destlen ;
2011-09-23 18:57:36 -07:00
mResponseText . SetLength ( totalChars ) ;
2007-03-22 10:30:00 -07:00
return NS_OK ;
}
/* readonly attribute AString responseText; */
2012-03-26 08:38:06 -07:00
NS_IMETHODIMP
nsXMLHttpRequest : : GetResponseText ( nsAString & aResponseText )
{
2012-05-05 18:15:11 -07:00
ErrorResult rv ;
2012-03-26 08:38:06 -07:00
nsString responseText ;
GetResponseText ( responseText , rv ) ;
aResponseText = responseText ;
2012-05-05 18:15:11 -07:00
return rv . ErrorCode ( ) ;
2012-03-26 08:38:06 -07:00
}
void
2012-05-05 18:15:11 -07:00
nsXMLHttpRequest : : GetResponseText ( nsString & aResponseText , ErrorResult & aRv )
2007-03-22 10:30:00 -07:00
{
aResponseText . Truncate ( ) ;
2011-05-10 16:18:55 -07:00
if ( mResponseType ! = XML_HTTP_RESPONSE_TYPE_DEFAULT & &
2011-09-23 18:57:36 -07:00
mResponseType ! = XML_HTTP_RESPONSE_TYPE_TEXT & &
mResponseType ! = XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT ) {
2012-05-05 18:15:11 -07:00
aRv . Throw ( NS_ERROR_DOM_INVALID_STATE_ERR ) ;
2012-03-26 08:38:06 -07:00
return ;
2011-05-10 16:18:55 -07:00
}
2011-09-23 18:57:36 -07:00
if ( mResponseType = = XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT & &
! mInLoadProgressEvent ) {
2011-10-17 07:59:28 -07:00
aResponseText . SetIsVoid ( true ) ;
2012-03-26 08:38:06 -07:00
return ;
2011-09-23 18:57:36 -07:00
}
2011-09-23 18:57:36 -07:00
if ( ! ( mState & ( XML_HTTP_REQUEST_DONE | XML_HTTP_REQUEST_LOADING ) ) ) {
2012-03-26 08:38:06 -07:00
return ;
2007-03-22 10:30:00 -07:00
}
2011-09-23 18:57:36 -07:00
// We only decode text lazily if we're also parsing to a doc.
// Also, if we've decoded all current data already, then no need to decode
// more.
2011-11-24 07:28:12 -08:00
if ( ! mResponseXML | |
2011-09-23 18:57:36 -07:00
mResponseBodyDecodedPos = = mResponseBody . Length ( ) ) {
aResponseText = mResponseText ;
2012-03-26 08:38:06 -07:00
return ;
2011-09-23 18:57:36 -07:00
}
2012-03-26 08:38:06 -07:00
if ( mResponseCharset ! = mResponseXML - > GetDocumentCharacterSet ( ) ) {
mResponseCharset = mResponseXML - > GetDocumentCharacterSet ( ) ;
2011-09-23 18:57:36 -07:00
mResponseText . Truncate ( ) ;
mResponseBodyDecodedPos = 0 ;
2012-05-05 18:15:11 -07:00
nsresult rv ;
2011-09-23 18:57:36 -07:00
nsCOMPtr < nsICharsetConverterManager > ccm =
2012-05-05 18:15:11 -07:00
do_GetService ( NS_CHARSETCONVERTERMANAGER_CONTRACTID , & rv ) ;
if ( NS_FAILED ( rv ) ) {
aRv . Throw ( rv ) ;
2012-03-26 08:38:06 -07:00
return ;
}
2011-09-23 18:57:36 -07:00
2012-03-26 08:38:06 -07:00
aRv = ccm - > GetUnicodeDecoderRaw ( mResponseCharset . get ( ) ,
getter_AddRefs ( mDecoder ) ) ;
2012-05-05 18:15:11 -07:00
if ( aRv . Failed ( ) ) {
2012-03-26 08:38:06 -07:00
return ;
}
2011-09-23 18:57:36 -07:00
}
NS_ASSERTION ( mResponseBodyDecodedPos < mResponseBody . Length ( ) ,
" Unexpected mResponseBodyDecodedPos " ) ;
2012-03-26 08:38:06 -07:00
aRv = AppendToResponseText ( mResponseBody . get ( ) + mResponseBodyDecodedPos ,
mResponseBody . Length ( ) - mResponseBodyDecodedPos ) ;
2012-05-05 18:15:11 -07:00
if ( aRv . Failed ( ) ) {
2012-03-26 08:38:06 -07:00
return ;
}
2011-09-23 18:57:36 -07:00
mResponseBodyDecodedPos = mResponseBody . Length ( ) ;
if ( mState & XML_HTTP_REQUEST_DONE ) {
// Free memory buffer which we no longer need
mResponseBody . Truncate ( ) ;
mResponseBodyDecodedPos = 0 ;
}
aResponseText = mResponseText ;
2007-03-22 10:30:00 -07:00
}
2011-09-08 15:12:18 -07:00
nsresult
nsXMLHttpRequest : : CreateResponseParsedJSON ( JSContext * aCx )
2010-08-14 10:52:19 -07:00
{
2011-09-08 15:12:18 -07:00
if ( ! aCx ) {
return NS_ERROR_FAILURE ;
}
2012-08-05 08:41:13 -07:00
RootJSResultObjects ( ) ;
2012-08-03 09:29:53 -07:00
2011-12-08 05:56:14 -08:00
// The Unicode converter has already zapped the BOM if there was one
2013-06-18 03:00:37 -07:00
JS : : Rooted < JS : : Value > value ( aCx ) ;
2011-09-08 15:12:18 -07:00
if ( ! JS_ParseJSON ( aCx ,
2013-05-29 01:29:39 -07:00
static_cast < const jschar * > ( mResponseText . get ( ) ) , mResponseText . Length ( ) ,
2013-06-18 03:00:37 -07:00
& value ) ) {
2010-08-14 10:52:19 -07:00
return NS_ERROR_FAILURE ;
2011-09-08 15:12:18 -07:00
}
2013-06-18 03:00:37 -07:00
mResultJSON = value ;
2011-09-08 15:12:18 -07:00
return NS_OK ;
}
2012-09-20 00:55:36 -07:00
void
2012-01-30 02:33:59 -08:00
nsXMLHttpRequest : : CreatePartialBlob ( )
{
if ( mDOMFile ) {
if ( mLoadTotal = = mLoadTransferred ) {
mResponseBlob = mDOMFile ;
} else {
mResponseBlob =
mDOMFile - > CreateSlice ( 0 , mLoadTransferred , EmptyString ( ) ) ;
}
2012-09-20 00:55:36 -07:00
return ;
2012-01-30 02:33:59 -08:00
}
2012-09-20 00:55:36 -07:00
// mBlobSet can be null if the request has been canceled
if ( ! mBlobSet ) {
return ;
2012-04-30 15:49:15 -07:00
}
2012-09-01 19:35:17 -07:00
nsAutoCString contentType ;
2012-01-30 02:33:59 -08:00
if ( mLoadTotal = = mLoadTransferred ) {
mChannel - > GetContentType ( contentType ) ;
}
2012-09-20 00:55:36 -07:00
mResponseBlob = mBlobSet - > GetBlobInternal ( contentType ) ;
2012-01-30 02:33:59 -08:00
}
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 ;
2011-09-08 15:12:18 -07:00
case XML_HTTP_RESPONSE_TYPE_JSON :
2011-12-08 05:56:14 -08:00
aResponseType . AssignLiteral ( " json " ) ;
2011-09-08 15:12:18 -07:00
break ;
2011-09-23 18:57:36 -07:00
case XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT :
aResponseType . AssignLiteral ( " moz-chunked-text " ) ;
break ;
case XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER :
aResponseType . AssignLiteral ( " moz-chunked-arraybuffer " ) ;
break ;
2012-01-30 02:33:59 -08:00
case XML_HTTP_RESPONSE_TYPE_MOZ_BLOB :
aResponseType . AssignLiteral ( " moz-blob " ) ;
break ;
2011-05-10 16:18:55 -07:00
default :
NS_ERROR ( " Should not happen " ) ;
}
return NS_OK ;
}
2012-03-26 08:38:06 -07:00
# ifdef DEBUG
void
nsXMLHttpRequest : : StaticAssertions ( )
{
# define ASSERT_ENUM_EQUAL(_lc, _uc) \
2013-07-18 10:59:53 -07:00
static_assert ( \
2013-05-06 12:28:13 -07:00
static_cast < int > ( XMLHttpRequestResponseType : : _lc ) \
= = XML_HTTP_RESPONSE_TYPE_ # # _uc , \
2012-03-26 08:38:06 -07:00
# _uc " should match")
2012-03-30 21:42:20 -07:00
ASSERT_ENUM_EQUAL ( _empty , DEFAULT ) ;
2012-06-15 13:25:51 -07:00
ASSERT_ENUM_EQUAL ( Arraybuffer , ARRAYBUFFER ) ;
ASSERT_ENUM_EQUAL ( Blob , BLOB ) ;
ASSERT_ENUM_EQUAL ( Document , DOCUMENT ) ;
ASSERT_ENUM_EQUAL ( Json , JSON ) ;
ASSERT_ENUM_EQUAL ( Text , TEXT ) ;
ASSERT_ENUM_EQUAL ( Moz_chunked_text , CHUNKED_TEXT ) ;
ASSERT_ENUM_EQUAL ( Moz_chunked_arraybuffer , CHUNKED_ARRAYBUFFER ) ;
ASSERT_ENUM_EQUAL ( Moz_blob , MOZ_BLOB ) ;
2012-03-26 08:38:06 -07:00
# undef ASSERT_ENUM_EQUAL
}
# endif
2011-05-10 16:18:55 -07:00
/* attribute AString responseType; */
2011-05-18 22:11:51 -07:00
NS_IMETHODIMP nsXMLHttpRequest : : SetResponseType ( const nsAString & aResponseType )
2012-03-26 08:38:06 -07:00
{
2012-09-11 12:08:24 -07:00
nsXMLHttpRequest : : ResponseTypeEnum responseType ;
2012-03-26 08:38:06 -07:00
if ( aResponseType . IsEmpty ( ) ) {
responseType = XML_HTTP_RESPONSE_TYPE_DEFAULT ;
} else if ( aResponseType . EqualsLiteral ( " arraybuffer " ) ) {
responseType = XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER ;
} else if ( aResponseType . EqualsLiteral ( " blob " ) ) {
responseType = XML_HTTP_RESPONSE_TYPE_BLOB ;
} else if ( aResponseType . EqualsLiteral ( " document " ) ) {
responseType = XML_HTTP_RESPONSE_TYPE_DOCUMENT ;
} else if ( aResponseType . EqualsLiteral ( " text " ) ) {
responseType = XML_HTTP_RESPONSE_TYPE_TEXT ;
} else if ( aResponseType . EqualsLiteral ( " json " ) ) {
responseType = XML_HTTP_RESPONSE_TYPE_JSON ;
} else if ( aResponseType . EqualsLiteral ( " moz-chunked-text " ) ) {
responseType = XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT ;
} else if ( aResponseType . EqualsLiteral ( " moz-chunked-arraybuffer " ) ) {
responseType = XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER ;
} else if ( aResponseType . EqualsLiteral ( " moz-blob " ) ) {
responseType = XML_HTTP_RESPONSE_TYPE_MOZ_BLOB ;
} else {
return NS_OK ;
}
2012-05-05 18:15:11 -07:00
ErrorResult rv ;
2012-03-26 08:38:06 -07:00
SetResponseType ( responseType , rv ) ;
2012-05-05 18:15:11 -07:00
return rv . ErrorCode ( ) ;
2012-03-26 08:38:06 -07:00
}
2012-03-30 21:42:20 -07:00
void
nsXMLHttpRequest : : SetResponseType ( XMLHttpRequestResponseType aType ,
2012-05-05 18:15:11 -07:00
ErrorResult & aRv )
2012-03-30 21:42:20 -07:00
{
2013-05-06 12:28:13 -07:00
SetResponseType ( ResponseTypeEnum ( static_cast < int > ( aType ) ) , aRv ) ;
2012-03-30 21:42:20 -07:00
}
2012-03-26 08:38:06 -07:00
void
2012-09-11 12:08:24 -07:00
nsXMLHttpRequest : : SetResponseType ( nsXMLHttpRequest : : ResponseTypeEnum aResponseType ,
2012-05-05 18:15:11 -07:00
ErrorResult & aRv )
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 |
2012-03-26 08:38:06 -07:00
XML_HTTP_REQUEST_HEADERS_RECEIVED ) ) ) {
2012-05-05 18:15:11 -07:00
aRv . Throw ( NS_ERROR_DOM_INVALID_STATE_ERR ) ;
2012-03-26 08:38:06 -07:00
return ;
}
2011-05-10 16:18:55 -07:00
2011-12-08 05:54:05 -08:00
// sync request is not allowed setting responseType in window context
2012-03-12 17:56:07 -07:00
if ( HasOrHasHadOwner ( ) & &
2011-12-08 05:54:05 -08:00
! ( mState & ( XML_HTTP_REQUEST_UNSENT | XML_HTTP_REQUEST_ASYNC ) ) ) {
2012-03-12 17:56:07 -07:00
LogMessage ( " ResponseTypeSyncXHRWarning " , GetOwner ( ) ) ;
2012-05-05 18:15:11 -07:00
aRv . Throw ( NS_ERROR_DOM_INVALID_ACCESS_ERR ) ;
2012-03-26 08:38:06 -07:00
return ;
2011-12-08 05:54:05 -08:00
}
2012-03-26 08:38:06 -07:00
if ( ! ( mState & XML_HTTP_REQUEST_ASYNC ) & &
( aResponseType = = XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT | |
aResponseType = = XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER ) ) {
2012-05-05 18:15:11 -07:00
aRv . Throw ( NS_ERROR_DOM_INVALID_STATE_ERR ) ;
2012-03-26 08:38:06 -07:00
return ;
2011-05-10 16:18:55 -07:00
}
2012-03-26 08:38:06 -07:00
// Set the responseType attribute's value to the given value.
mResponseType = aResponseType ;
2011-05-10 16:18:55 -07:00
}
/* readonly attribute jsval response; */
2012-03-26 08:38:06 -07:00
NS_IMETHODIMP
2013-03-22 22:11:52 -07:00
nsXMLHttpRequest : : GetResponse ( JSContext * aCx , JS : : Value * aResult )
2011-05-10 16:18:55 -07:00
{
2012-05-05 18:15:11 -07:00
ErrorResult rv ;
2012-03-26 08:38:06 -07:00
* aResult = GetResponse ( aCx , rv ) ;
2012-05-05 18:15:11 -07:00
return rv . ErrorCode ( ) ;
2012-03-26 08:38:06 -07:00
}
2011-05-10 16:18:55 -07:00
2012-03-26 08:38:06 -07:00
JS : : Value
2012-05-05 18:15:11 -07:00
nsXMLHttpRequest : : GetResponse ( JSContext * aCx , ErrorResult & aRv )
2012-03-26 08:38:06 -07:00
{
2011-05-10 16:18:55 -07:00
switch ( mResponseType ) {
case XML_HTTP_RESPONSE_TYPE_DEFAULT :
case XML_HTTP_RESPONSE_TYPE_TEXT :
2011-09-23 18:57:36 -07:00
case XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT :
2012-03-26 08:38:06 -07:00
{
nsString str ;
aRv = GetResponseText ( str ) ;
2012-05-05 18:15:11 -07:00
if ( aRv . Failed ( ) ) {
2012-03-26 08:38:06 -07:00
return JSVAL_NULL ;
2011-05-10 16:18:55 -07:00
}
2012-03-26 08:38:06 -07:00
JS : : Value result ;
if ( ! xpc : : StringToJsval ( aCx , str , & result ) ) {
2012-05-05 18:15:11 -07:00
aRv . Throw ( NS_ERROR_OUT_OF_MEMORY ) ;
2012-03-26 08:38:06 -07:00
return JSVAL_NULL ;
}
return result ;
}
2011-05-10 16:18:55 -07:00
case XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER :
2011-09-23 18:57:36 -07:00
case XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER :
2012-03-26 08:38:06 -07:00
{
if ( ! ( mResponseType = = XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER & &
mState & XML_HTTP_REQUEST_DONE ) & &
! ( mResponseType = = XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER & &
mInLoadProgressEvent ) ) {
return JSVAL_NULL ;
}
if ( ! mResultArrayBuffer ) {
2012-08-05 08:41:13 -07:00
RootJSResultObjects ( ) ;
2013-04-27 12:25:24 -07:00
mResultArrayBuffer = mArrayBufferBuilder . getArrayBuffer ( aCx ) ;
if ( ! mResultArrayBuffer ) {
aRv . Throw ( NS_ERROR_OUT_OF_MEMORY ) ;
2012-03-26 08:38:06 -07:00
return JSVAL_NULL ;
2011-05-23 18:09:28 -07:00
}
2011-05-10 16:18:55 -07:00
}
2012-03-26 08:38:06 -07:00
return OBJECT_TO_JSVAL ( mResultArrayBuffer ) ;
}
2011-05-10 16:18:55 -07:00
case XML_HTTP_RESPONSE_TYPE_BLOB :
2012-01-30 02:33:59 -08:00
case XML_HTTP_RESPONSE_TYPE_MOZ_BLOB :
2012-03-26 08:38:06 -07:00
{
if ( ! ( mState & XML_HTTP_REQUEST_DONE ) ) {
if ( mResponseType ! = XML_HTTP_RESPONSE_TYPE_MOZ_BLOB ) {
return JSVAL_NULL ;
}
2012-01-30 02:33:59 -08:00
if ( ! mResponseBlob ) {
2012-09-20 00:55:36 -07:00
CreatePartialBlob ( ) ;
2012-01-30 02:33:59 -08:00
}
}
2012-03-26 08:38:06 -07:00
if ( ! mResponseBlob ) {
return JSVAL_NULL ;
2011-05-10 16:18:55 -07:00
}
2013-05-07 19:34:56 -07:00
JS : : Rooted < JS : : Value > result ( aCx , JSVAL_NULL ) ;
2013-07-29 16:45:27 -07:00
JS : : Rooted < JSObject * > scope ( aCx , JS : : CurrentGlobalOrNull ( aCx ) ) ;
2013-05-07 19:34:56 -07:00
aRv = nsContentUtils : : WrapNative ( aCx , scope , mResponseBlob , result . address ( ) ,
2012-07-30 07:20:58 -07:00
nullptr , true ) ;
2012-03-26 08:38:06 -07:00
return result ;
}
2011-05-10 16:18:55 -07:00
case XML_HTTP_RESPONSE_TYPE_DOCUMENT :
2012-03-26 08:38:06 -07:00
{
if ( ! ( mState & XML_HTTP_REQUEST_DONE ) | | ! mResponseXML ) {
return JSVAL_NULL ;
2011-05-10 16:18:55 -07:00
}
2013-07-29 16:45:27 -07:00
JS : : Rooted < JSObject * > scope ( aCx , JS : : CurrentGlobalOrNull ( aCx ) ) ;
2013-05-07 19:34:56 -07:00
JS : : Rooted < JS : : Value > result ( aCx , JSVAL_NULL ) ;
aRv = nsContentUtils : : WrapNative ( aCx , scope , mResponseXML , result . address ( ) ,
2012-07-30 07:20:58 -07:00
nullptr , true ) ;
2012-03-26 08:38:06 -07:00
return result ;
}
2011-09-08 15:12:18 -07:00
case XML_HTTP_RESPONSE_TYPE_JSON :
2012-03-26 08:38:06 -07:00
{
if ( ! ( mState & XML_HTTP_REQUEST_DONE ) ) {
return JSVAL_NULL ;
2011-09-08 15:12:18 -07:00
}
2012-03-26 08:38:06 -07:00
if ( mResultJSON = = JSVAL_VOID ) {
aRv = CreateResponseParsedJSON ( aCx ) ;
mResponseText . Truncate ( ) ;
2012-05-05 18:15:11 -07:00
if ( aRv . Failed ( ) ) {
2012-03-26 08:38:06 -07:00
// Per spec, errors aren't propagated. null is returned instead.
aRv = NS_OK ;
// It would be nice to log the error to the console. That's hard to
// do without calling window.onerror as a side effect, though.
JS_ClearPendingException ( aCx ) ;
mResultJSON = JSVAL_NULL ;
}
}
return mResultJSON ;
}
2011-05-10 16:18:55 -07:00
default :
NS_ERROR ( " Should not happen " ) ;
}
2012-03-26 08:38:06 -07:00
return JSVAL_NULL ;
2011-05-10 16:18:55 -07:00
}
2007-03-22 10:30:00 -07:00
/* readonly attribute unsigned long status; */
NS_IMETHODIMP
2012-08-22 08:56:38 -07:00
nsXMLHttpRequest : : GetStatus ( uint32_t * aStatus )
2007-03-22 10:30:00 -07:00
{
2012-09-11 12:08:24 -07:00
* aStatus = Status ( ) ;
2012-03-26 08:38:06 -07:00
return NS_OK ;
}
2008-09-30 17:50:42 -07:00
2012-03-26 08:38:06 -07:00
uint32_t
2012-09-11 12:08:24 -07:00
nsXMLHttpRequest : : Status ( )
2012-03-26 08:38:06 -07:00
{
2008-09-30 17:50:42 -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 ) ) {
2012-03-26 08:38:06 -07:00
return 0 ;
2008-09-30 17:50:42 -07:00
}
}
}
2012-08-22 08:56:38 -07:00
uint16_t readyState ;
2012-03-26 01:40:09 -07:00
GetReadyState ( & readyState ) ;
2012-10-25 18:57:57 -07:00
if ( readyState = = UNSENT | | readyState = = OPENED ) {
return 0 ;
}
if ( mErrorLoad ) {
// Let's simulate the http protocol for jar/app requests:
nsCOMPtr < nsIJARChannel > jarChannel = GetCurrentJARChannel ( ) ;
if ( jarChannel ) {
nsresult status ;
mChannel - > GetStatus ( & status ) ;
if ( status = = NS_ERROR_FILE_NOT_FOUND ) {
return 404 ; // Not Found
} else {
return 500 ; // Internal Error
}
}
2012-03-26 08:38:06 -07:00
return 0 ;
2012-03-26 01:40:09 -07:00
}
2007-03-22 10:30:00 -07:00
2012-03-26 01:40:09 -07:00
nsCOMPtr < nsIHttpChannel > httpChannel = GetCurrentHttpChannel ( ) ;
2012-03-26 08:38:06 -07:00
if ( ! httpChannel ) {
2012-10-25 18:57:57 -07:00
// Let's simulate the http protocol for jar/app requests:
nsCOMPtr < nsIJARChannel > jarChannel = GetCurrentJARChannel ( ) ;
if ( jarChannel ) {
return 200 ; // Ok
}
2012-03-26 08:38:06 -07:00
return 0 ;
2007-03-22 10:30:00 -07:00
}
2012-08-22 08:56:38 -07:00
uint32_t status ;
2012-03-26 08:38:06 -07:00
nsresult rv = httpChannel - > GetResponseStatus ( & status ) ;
if ( NS_FAILED ( rv ) ) {
status = 0 ;
}
return status ;
2007-03-22 10:30:00 -07:00
}
2013-06-12 22:20:10 -07:00
IMPL_CSTRING_GETTER ( GetStatusText )
2012-03-26 08:38:06 -07:00
void
2013-06-12 22:20:10 -07:00
nsXMLHttpRequest : : GetStatusText ( nsCString & aStatusText )
2007-03-22 10:30:00 -07:00
{
nsCOMPtr < nsIHttpChannel > httpChannel = GetCurrentHttpChannel ( ) ;
aStatusText . Truncate ( ) ;
2012-03-26 08:38:06 -07:00
if ( ! httpChannel ) {
return ;
}
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 ;
2010-03-16 16:23:45 -07:00
}
}
2007-03-22 10:30:00 -07:00
}
2013-06-12 22:20:10 -07:00
httpChannel - > GetResponseStatusText ( aStatusText ) ;
2007-03-22 10:30:00 -07:00
}
2012-01-26 02:02:22 -08:00
void
nsXMLHttpRequest : : CloseRequestWithError ( const nsAString & aType ,
2012-08-22 08:56:38 -07:00
const uint32_t aFlag )
2007-03-22 10:30:00 -07:00
{
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
}
2012-01-26 02:02:22 -08:00
if ( mTimeoutTimer ) {
mTimeoutTimer - > Cancel ( ) ;
}
2012-08-22 08:56:38 -07:00
uint32_t responseLength = mResponseBody . Length ( ) ;
2011-09-23 18:57:22 -07:00
ResetResponse ( ) ;
2012-01-26 02:02:22 -08:00
mState | = aFlag ;
2012-02-14 10:05:43 -08:00
// If we're in the destructor, don't risk dispatching an event.
2012-02-20 12:02:47 -08:00
if ( mState & XML_HTTP_REQUEST_DELETED ) {
mState & = ~ XML_HTTP_REQUEST_SYNCLOOPING ;
2012-02-14 10:05:43 -08:00
return ;
2012-02-20 12:02:47 -08:00
}
2012-02-14 10:05:43 -08:00
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 ) ) ) {
2011-10-17 07:59:28 -07:00
ChangeState ( XML_HTTP_REQUEST_DONE , true ) ;
2007-03-22 10:30:00 -07:00
2011-11-21 10:07:12 -08:00
if ( ! ( mState & XML_HTTP_REQUEST_SYNCLOOPING ) ) {
2012-01-26 02:02:22 -08:00
DispatchProgressEvent ( this , aType , mLoadLengthComputable , responseLength ,
2011-11-21 10:07:12 -08:00
mLoadTotal ) ;
if ( mUpload & & ! mUploadComplete ) {
mUploadComplete = true ;
2012-01-26 02:02:22 -08:00
DispatchProgressEvent ( mUpload , aType , true , mUploadTransferred ,
2011-11-21 10:07:12 -08:00
mUploadTotal ) ;
}
2008-08-14 04:07:46 -07:00
}
}
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-10-17 07:59:28 -07:00
ChangeState ( XML_HTTP_REQUEST_UNSENT , 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 ;
2012-01-26 02:02:22 -08:00
}
2008-08-25 10:21:28 -07:00
2012-01-26 02:02:22 -08:00
/* void abort (); */
2012-03-26 08:38:06 -07:00
void
2012-01-26 02:02:22 -08:00
nsXMLHttpRequest : : Abort ( )
{
CloseRequestWithError ( NS_LITERAL_STRING ( ABORT_STR ) , XML_HTTP_REQUEST_ABORTED ) ;
2012-03-26 08:38:06 -07:00
}
NS_IMETHODIMP
nsXMLHttpRequest : : SlowAbort ( )
{
Abort ( ) ;
2007-03-22 10:30:00 -07:00
return NS_OK ;
}
2013-01-10 14:47:43 -08:00
/*Method that checks if it is safe to expose a header value to the client.
It is used to check what headers are exposed for CORS requests . */
bool
nsXMLHttpRequest : : IsSafeHeader ( const nsACString & header , nsIHttpChannel * httpChannel )
{
// See bug #380418. Hide "Set-Cookie" headers from non-chrome scripts.
2013-07-03 14:04:43 -07:00
if ( ! IsSystemXHR ( ) & &
2013-01-10 14:47:43 -08:00
( header . LowerCaseEqualsASCII ( " set-cookie " ) | |
header . LowerCaseEqualsASCII ( " set-cookie2 " ) ) ) {
NS_WARNING ( " blocked access to response header " ) ;
return false ;
}
// if this is not a CORS call all headers are safe
if ( ! ( mState & XML_HTTP_REQUEST_USE_XSITE_AC ) ) {
return true ;
}
// Check for dangerous headers
// 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 false ;
}
}
const char * kCrossOriginSafeHeaders [ ] = {
" cache-control " , " content-language " , " content-type " , " expires " ,
" last-modified " , " pragma "
} ;
for ( uint32_t i = 0 ; i < ArrayLength ( kCrossOriginSafeHeaders ) ; + + i ) {
if ( header . LowerCaseEqualsASCII ( kCrossOriginSafeHeaders [ i ] ) ) {
return true ;
}
}
nsAutoCString 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 , ' , ' ) ;
bool isSafe = false ;
while ( exposeTokens . hasMoreTokens ( ) ) {
const nsDependentCSubstring & token = exposeTokens . nextToken ( ) ;
if ( token . IsEmpty ( ) ) {
continue ;
}
if ( ! IsValidHTTPToken ( token ) ) {
return false ;
}
if ( header . Equals ( token , nsCaseInsensitiveCStringComparator ( ) ) ) {
isSafe = true ;
}
}
return isSafe ;
}
2013-06-12 22:20:10 -07:00
/* ByteString getAllResponseHeaders(); */
IMPL_CSTRING_GETTER ( GetAllResponseHeaders )
2012-03-26 08:38:06 -07:00
void
2013-06-12 22:20:10 -07:00
nsXMLHttpRequest : : GetAllResponseHeaders ( nsCString & aResponseHeaders )
2007-03-22 10:30:00 -07:00
{
2012-02-21 01:34:01 -08:00
aResponseHeaders . Truncate ( ) ;
2007-03-22 10:30:00 -07:00
2012-02-19 03:58:24 -08:00
// If the state is UNSENT or OPENED,
// return the empty string and terminate these steps.
if ( mState & ( XML_HTTP_REQUEST_UNSENT |
XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT ) ) {
2012-03-26 08:38:06 -07:00
return ;
2012-02-19 03:58:24 -08:00
}
2012-02-21 01:34:01 -08:00
if ( nsCOMPtr < nsIHttpChannel > httpChannel = GetCurrentHttpChannel ( ) ) {
2013-01-10 14:47:43 -08:00
nsRefPtr < nsHeaderVisitor > visitor = new nsHeaderVisitor ( this , httpChannel ) ;
2012-02-21 01:34:01 -08:00
if ( NS_SUCCEEDED ( httpChannel - > VisitResponseHeaders ( visitor ) ) ) {
2013-06-12 22:20:10 -07:00
aResponseHeaders = visitor - > Headers ( ) ;
2012-02-19 03:58:24 -08:00
}
2012-03-26 08:38:06 -07:00
return ;
2010-11-11 13:39:14 -08:00
}
2012-02-19 03:58:24 -08:00
2012-02-21 01:34:01 -08:00
if ( ! mChannel ) {
2012-03-26 08:38:06 -07:00
return ;
2007-03-22 10:30:00 -07:00
}
2012-02-21 01:34:01 -08:00
// Even non-http channels supply content type.
2012-09-01 19:35:17 -07:00
nsAutoCString value ;
2012-02-21 01:34:01 -08:00
if ( NS_SUCCEEDED ( mChannel - > GetContentType ( value ) ) ) {
aResponseHeaders . AppendLiteral ( " Content-Type: " ) ;
2013-06-12 22:20:10 -07:00
aResponseHeaders . Append ( value ) ;
2012-03-26 08:38:06 -07:00
if ( NS_SUCCEEDED ( mChannel - > GetContentCharset ( value ) ) & & ! value . IsEmpty ( ) ) {
2012-02-21 01:34:01 -08:00
aResponseHeaders . AppendLiteral ( " ;charset= " ) ;
2013-06-12 22:20:10 -07:00
aResponseHeaders . Append ( value ) ;
2012-02-21 01:34:01 -08:00
}
2012-07-26 08:55:23 -07:00
aResponseHeaders . AppendLiteral ( " \r \n " ) ;
2012-02-21 01:34:01 -08:00
}
2012-08-27 16:34:29 -07:00
2012-10-22 10:51:07 -07:00
int64_t length ;
2012-08-27 16:34:29 -07:00
if ( NS_SUCCEEDED ( mChannel - > GetContentLength ( & length ) ) ) {
aResponseHeaders . AppendLiteral ( " Content-Length: " ) ;
aResponseHeaders . AppendInt ( length ) ;
aResponseHeaders . AppendLiteral ( " \r \n " ) ;
}
2007-03-22 10:30:00 -07:00
}
NS_IMETHODIMP
2012-03-26 08:38:06 -07:00
nsXMLHttpRequest : : GetResponseHeader ( const nsACString & aHeader ,
nsACString & aResult )
2007-03-22 10:30:00 -07:00
{
2012-05-05 18:15:11 -07:00
ErrorResult rv ;
2012-03-26 08:38:06 -07:00
GetResponseHeader ( aHeader , aResult , rv ) ;
2012-05-05 18:15:11 -07:00
return rv . ErrorCode ( ) ;
2012-03-26 08:38:06 -07:00
}
void
nsXMLHttpRequest : : GetResponseHeader ( const nsACString & header ,
2012-05-05 18:15:11 -07:00
nsACString & _retval , ErrorResult & aRv )
2012-03-26 08:38:06 -07:00
{
2011-10-17 07:59:28 -07:00
_retval . SetIsVoid ( true ) ;
2010-10-04 18:25:44 -07:00
nsCOMPtr < nsIHttpChannel > httpChannel = GetCurrentHttpChannel ( ) ;
if ( ! httpChannel ) {
2012-02-19 03:58:24 -08:00
// If the state is UNSENT or OPENED,
// return null and terminate these steps.
if ( mState & ( XML_HTTP_REQUEST_UNSENT |
XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT ) ) {
2012-03-26 08:38:06 -07:00
return ;
2012-02-19 03:58:24 -08:00
}
2012-08-27 16:34:29 -07:00
// Even non-http channels supply content type and content length.
2012-02-19 03:58:24 -08:00
// Remember we don't leak header information from denied cross-site
// requests.
nsresult status ;
if ( ! mChannel | |
NS_FAILED ( mChannel - > GetStatus ( & status ) ) | |
2012-08-27 16:34:29 -07:00
NS_FAILED ( status ) ) {
2012-03-26 08:38:06 -07:00
return ;
2012-02-19 03:58:24 -08:00
}
2012-08-27 16:34:29 -07:00
// Content Type:
if ( header . LowerCaseEqualsASCII ( " content-type " ) ) {
if ( NS_FAILED ( mChannel - > GetContentType ( _retval ) ) ) {
// Means no content type
_retval . SetIsVoid ( true ) ;
return ;
}
nsCString value ;
if ( NS_SUCCEEDED ( mChannel - > GetContentCharset ( value ) ) & &
! value . IsEmpty ( ) ) {
_retval . Append ( " ;charset= " ) ;
_retval . Append ( value ) ;
}
2012-02-19 03:58:24 -08:00
}
2012-08-27 16:34:29 -07:00
// Content Length:
else if ( header . LowerCaseEqualsASCII ( " content-length " ) ) {
2012-10-22 10:51:07 -07:00
int64_t length ;
2012-08-27 16:34:29 -07:00
if ( NS_SUCCEEDED ( mChannel - > GetContentLength ( & length ) ) ) {
_retval . AppendInt ( length ) ;
}
2012-02-19 03:58:24 -08:00
}
2012-03-26 08:38:06 -07:00
return ;
2010-10-04 18:25:44 -07:00
}
2007-03-22 10:30:00 -07:00
2008-09-30 17:49:30 -07:00
// Check for dangerous headers
2013-01-10 14:47:43 -08:00
if ( ! IsSafeHeader ( header , httpChannel ) ) {
return ;
2007-03-22 10:30:00 -07:00
}
2012-03-26 08:38:06 -07:00
aRv = httpChannel - > GetResponseHeader ( header , _retval ) ;
2012-05-05 18:15:11 -07:00
if ( aRv . ErrorCode ( ) = = NS_ERROR_NOT_AVAILABLE ) {
2007-03-22 10:30:00 -07:00
// Means no header
2011-10-17 07:59:28 -07:00
_retval . SetIsVoid ( true ) ;
2012-03-26 08:38:06 -07:00
aRv = NS_OK ;
2007-03-22 10:30:00 -07:00
}
}
2011-08-24 10:46:53 -07:00
already_AddRefed < nsILoadGroup >
nsXMLHttpRequest : : GetLoadGroup ( ) const
2008-10-14 17:12:28 -07:00
{
2012-03-12 17:56:07 -07:00
if ( mState & XML_HTTP_REQUEST_BACKGROUND ) {
2012-07-30 07:20:58 -07:00
return nullptr ;
2008-10-14 17:12:28 -07:00
}
2012-03-12 17:56:07 -07:00
nsresult rv = NS_ERROR_FAILURE ;
nsIScriptContext * sc =
const_cast < nsXMLHttpRequest * > ( this ) - > GetContextForEventHandlers ( & rv ) ;
2009-06-15 01:27:29 -07:00
nsCOMPtr < nsIDocument > doc =
2012-03-12 17:56:07 -07:00
nsContentUtils : : GetDocumentFromScriptContext ( sc ) ;
2008-10-14 17:12:28 -07:00
if ( doc ) {
2011-08-24 10:46:53 -07:00
return doc - > GetDocumentLoadGroup ( ) ;
2008-10-14 17:12:28 -07:00
}
2012-07-30 07:20:58 -07:00
return nullptr ;
2008-10-14 17:12:28 -07:00
}
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
{
2013-03-09 03:34:29 -08:00
nsresult rv = nsEventDispatcher : : CreateEvent ( this , nullptr , nullptr ,
2007-03-22 10:30:00 -07:00
NS_LITERAL_STRING ( " Events " ) ,
aDOMEvent ) ;
if ( NS_FAILED ( rv ) ) {
return rv ;
}
2008-08-14 04:07:46 -07:00
( * aDOMEvent ) - > InitEvent ( NS_LITERAL_STRING ( READYSTATE_STR ) ,
2011-10-17 07:59:28 -07:00
false , 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
2012-06-10 11:14:30 -07:00
( * aDOMEvent ) - > SetTrusted ( true ) ;
2007-03-22 10:30:00 -07:00
return NS_OK ;
}
2008-08-14 04:07:46 -07:00
void
2011-06-23 19:17:58 -07:00
nsXMLHttpRequest : : DispatchProgressEvent ( nsDOMEventTargetHelper * aTarget ,
2008-08-14 04:07:46 -07:00
const nsAString & aType ,
2011-09-28 23:19:26 -07:00
bool aLengthComputable ,
2013-02-28 10:53:04 -08:00
uint64_t aLoaded , uint64_t aTotal )
2008-08-14 04:07:46 -07:00
{
2008-09-30 17:51:53 -07:00
NS_ASSERTION ( aTarget , " null target " ) ;
2011-09-23 18:57:22 -07:00
NS_ASSERTION ( ! aType . IsEmpty ( ) , " missing event type " ) ;
if ( NS_FAILED ( CheckInnerWindowCorrectness ( ) ) | |
2012-07-21 19:28:26 -07:00
( ! AllowUploadProgress ( ) & & aTarget = = mUpload ) ) {
2008-08-14 04:07:46 -07:00
return ;
}
2011-09-28 23:19:26 -07:00
bool dispatchLoadend = aType . EqualsLiteral ( LOAD_STR ) | |
2013-02-28 10:53:04 -08:00
aType . EqualsLiteral ( ERROR_STR ) | |
aType . EqualsLiteral ( TIMEOUT_STR ) | |
aType . EqualsLiteral ( ABORT_STR ) ;
2013-02-22 21:49:59 -08:00
2008-08-14 04:07:46 -07:00
nsCOMPtr < nsIDOMEvent > event ;
2013-03-09 03:34:29 -08:00
nsresult rv = NS_NewDOMProgressEvent ( getter_AddRefs ( event ) , this ,
2013-02-22 21:49:59 -08:00
nullptr , nullptr ) ;
2008-08-14 04:07:46 -07:00
if ( NS_FAILED ( rv ) ) {
return ;
}
nsCOMPtr < nsIDOMProgressEvent > progress = do_QueryInterface ( event ) ;
if ( ! progress ) {
return ;
}
2011-10-17 07:59:28 -07:00
progress - > InitProgressEvent ( aType , false , false , aLengthComputable ,
2012-09-28 12:55:23 -07:00
aLoaded , ( aTotal = = UINT64_MAX ) ? 0 : aTotal ) ;
2008-08-14 04:07:46 -07:00
2012-11-27 12:20:40 -08:00
event - > SetTrusted ( true ) ;
2012-07-30 07:20:58 -07:00
aTarget - > DispatchDOMEvent ( nullptr , event , nullptr , nullptr ) ;
2013-02-28 10:53:04 -08:00
2011-03-24 06:22:03 -07:00
if ( dispatchLoadend ) {
DispatchProgressEvent ( aTarget , NS_LITERAL_STRING ( LOADEND_STR ) ,
2013-02-28 10:53:04 -08:00
aLengthComputable , aLoaded , aTotal ) ;
2011-03-24 06:22:03 -07:00
}
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 ( )
{
2013-03-04 01:06:15 -08:00
nsCOMPtr < nsIHttpChannel > httpChannel = do_QueryInterface ( mChannel ) ;
2012-10-25 18:57:57 -07:00
return httpChannel . forget ( ) ;
}
2007-03-22 10:30:00 -07:00
2012-10-25 18:57:57 -07:00
already_AddRefed < nsIJARChannel >
nsXMLHttpRequest : : GetCurrentJARChannel ( )
{
2013-03-04 01:06:15 -08:00
nsCOMPtr < nsIJARChannel > appChannel = do_QueryInterface ( mChannel ) ;
2012-10-25 18:57:57 -07:00
return appChannel . forget ( ) ;
2007-03-22 10:30:00 -07:00
}
2011-08-11 06:29:50 -07:00
bool
nsXMLHttpRequest : : IsSystemXHR ( )
{
2012-06-07 11:28:33 -07:00
return mIsSystem | | nsContentUtils : : IsSystemPrincipal ( mPrincipal ) ;
2011-08-11 06:29:50 -07:00
}
2008-09-30 17:49:30 -07:00
nsresult
nsXMLHttpRequest : : CheckChannelForCrossSiteRequest ( nsIChannel * aChannel )
{
2012-12-29 10:10:51 -08:00
// A system XHR (chrome code or a web app with the right permission) can
// always perform cross-site requests. In the web app case, however, we
// must still check for protected URIs like file:///.
2011-03-17 09:19:13 -07:00
if ( IsSystemXHR ( ) ) {
2012-12-29 10:10:51 -08:00
if ( ! nsContentUtils : : IsSystemPrincipal ( mPrincipal ) ) {
nsIScriptSecurityManager * secMan = nsContentUtils : : GetSecurityManager ( ) ;
nsCOMPtr < nsIURI > uri ;
aChannel - > GetOriginalURI ( getter_AddRefs ( uri ) ) ;
return secMan - > CheckLoadURIWithPrincipal (
mPrincipal , uri , nsIScriptSecurityManager : : STANDARD ) ;
}
2010-06-17 04:27:52 -07:00
return NS_OK ;
}
2012-08-20 11:34:33 -07:00
// If this is a same-origin request or the channel's URI inherits
// its principal, it's allowed.
if ( nsContentUtils : : CheckMayLoad ( mPrincipal , aChannel , true ) ) {
2012-01-11 01:47:46 -08:00
return NS_OK ;
}
2008-09-30 17:49:30 -07:00
// 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 ) ;
2012-01-11 01:47:46 -08:00
2012-09-01 19:35:17 -07:00
nsAutoCString method ;
2009-02-24 11:46:51 -08:00
httpChannel - > GetRequestMethod ( method ) ;
2011-03-28 13:18:45 -07:00
if ( ! mCORSUnsafeHeaders . IsEmpty ( ) | |
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 ,
2011-09-28 23:19:26 -07:00
bool async , const nsAString & user ,
2012-08-22 08:56:38 -07:00
const nsAString & password , uint8_t optional_argc )
2007-03-22 10:30:00 -07:00
{
2011-03-28 13:05:52 -07:00
if ( ! optional_argc ) {
// No optional arguments were passed in. Default async to true.
2011-10-17 07:59:28 -07:00
async = true ;
2011-03-28 13:05:52 -07:00
}
2012-05-29 20:45:18 -07:00
Optional < nsAString > realUser ;
if ( optional_argc > 1 ) {
realUser = & user ;
}
Optional < nsAString > realPassword ;
if ( optional_argc > 2 ) {
realPassword = & password ;
}
return Open ( method , url , async , realUser , realPassword ) ;
2012-03-26 08:38:06 -07:00
}
nsresult
nsXMLHttpRequest : : Open ( const nsACString & method , const nsACString & url ,
2012-05-29 20:45:18 -07:00
bool async , const Optional < nsAString > & user ,
const Optional < nsAString > & password )
2012-03-26 08:38:06 -07:00
{
NS_ENSURE_ARG ( ! method . IsEmpty ( ) ) ;
2011-11-19 10:50:17 -08:00
Telemetry : : Accumulate ( Telemetry : : XMLHTTPREQUEST_ASYNC_OR_SYNC ,
async ? 0 : 1 ) ;
2011-03-28 13:05:52 -07:00
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 ;
}
2011-12-08 05:54:05 -08:00
// sync request is not allowed using withCredential or responseType
// in window context
2012-03-12 17:56:07 -07:00
if ( ! async & & HasOrHasHadOwner ( ) & &
2011-12-08 05:54:05 -08:00
( mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS | |
2012-01-26 02:02:22 -08:00
mTimeoutMilliseconds | |
2011-12-08 05:54:05 -08:00
mResponseType ! = XML_HTTP_RESPONSE_TYPE_DEFAULT ) ) {
if ( mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS ) {
2012-03-12 17:56:07 -07:00
LogMessage ( " WithCredentialsSyncXHRWarning " , GetOwner ( ) ) ;
2011-12-08 05:54:05 -08:00
}
2012-01-26 02:02:22 -08:00
if ( mTimeoutMilliseconds ) {
2012-03-12 17:56:07 -07:00
LogMessage ( " TimeoutSyncXHRWarning " , GetOwner ( ) ) ;
2012-01-26 02:02:22 -08:00
}
2011-12-08 05:54:05 -08:00
if ( mResponseType ! = XML_HTTP_RESPONSE_TYPE_DEFAULT ) {
2012-03-12 17:56:07 -07:00
LogMessage ( " ResponseTypeSyncXHRWarning " , GetOwner ( ) ) ;
2011-12-08 05:54:05 -08:00
}
return NS_ERROR_DOM_INVALID_ACCESS_ERR ;
}
2007-03-22 10:30:00 -07:00
nsresult rv ;
nsCOMPtr < nsIURI > uri ;
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 |
2012-11-21 22:25:01 -08:00
XML_HTTP_REQUEST_SENT ) ) {
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
2012-01-26 02:02:22 -08:00
// Unset any pre-existing aborted and timed-out states.
mState & = ~ XML_HTTP_REQUEST_ABORTED & ~ XML_HTTP_REQUEST_TIMED_OUT ;
2007-03-22 10:30:00 -07:00
if ( async ) {
mState | = XML_HTTP_REQUEST_ASYNC ;
} else {
mState & = ~ XML_HTTP_REQUEST_ASYNC ;
}
2012-03-12 17:56:07 -07:00
nsIScriptContext * sc = GetContextForEventHandlers ( & rv ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2009-06-15 01:27:29 -07:00
nsCOMPtr < nsIDocument > doc =
2012-03-12 17:56:07 -07:00
nsContentUtils : : GetDocumentFromScriptContext ( sc ) ;
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 ( ) ;
}
2012-07-30 07:20:58 -07:00
rv = NS_NewURI ( getter_AddRefs ( uri ) , url , nullptr , baseURI ) ;
2007-03-22 10:30:00 -07:00
if ( NS_FAILED ( rv ) ) return rv ;
2007-12-12 00:33:32 -08:00
rv = CheckInnerWindowCorrectness ( ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2012-08-22 08:56:38 -07:00
int16_t 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
2012-07-30 07:20:58 -07:00
nullptr , //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 ;
}
2012-05-29 20:45:18 -07:00
// XXXbz this is wrong: we should only be looking at whether
// user/password were passed, not at the values! See bug 759624.
if ( user . WasPassed ( ) & & ! user . Value ( ) . IsEmpty ( ) ) {
2012-09-01 19:35:17 -07:00
nsAutoCString userpass ;
2012-05-29 20:45:18 -07:00
CopyUTF16toUTF8 ( user . Value ( ) , userpass ) ;
if ( password . WasPassed ( ) & & ! password . Value ( ) . IsEmpty ( ) ) {
2007-03-22 10:30:00 -07:00
userpass . Append ( ' : ' ) ;
2012-05-29 20:45:18 -07:00
AppendUTF16toUTF8 ( password . Value ( ) , userpass ) ;
2007-03-22 10:30:00 -07:00
}
uri - > SetUserPass ( userpass ) ;
}
2013-02-03 16:56:09 -08:00
// Clear our record of previously set headers so future header set
// operations will merge/override correctly.
mAlreadySetHeaders . Clear ( ) ;
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.
2011-08-24 10:46:53 -07:00
nsCOMPtr < nsILoadGroup > loadGroup = GetLoadGroup ( ) ;
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 ,
2012-07-30 07:20:58 -07:00
nullptr , // ioService
2010-04-23 12:54:09 -07:00
loadGroup ,
2012-07-30 07:20:58 -07:00
nullptr , // 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 ,
2012-08-22 08:56:38 -07:00
uint32_t toOffset ,
uint32_t count ,
uint32_t * writeCount )
2007-03-22 10:30:00 -07:00
{
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 ;
}
2012-01-30 02:33:59 -08:00
nsresult rv = NS_OK ;
if ( xmlHttpRequest - > mResponseType = = XML_HTTP_RESPONSE_TYPE_BLOB | |
xmlHttpRequest - > mResponseType = = XML_HTTP_RESPONSE_TYPE_MOZ_BLOB ) {
if ( ! xmlHttpRequest - > mDOMFile ) {
2012-09-20 00:55:36 -07:00
if ( ! xmlHttpRequest - > mBlobSet ) {
xmlHttpRequest - > mBlobSet = new BlobSet ( ) ;
2012-01-30 02:33:59 -08:00
}
2012-09-20 00:55:36 -07:00
rv = xmlHttpRequest - > mBlobSet - > AppendVoidPtr ( fromRawSegment , count ) ;
2012-01-30 02:33:59 -08:00
}
// Clear the cache so that the blob size is updated.
if ( xmlHttpRequest - > mResponseType = = XML_HTTP_RESPONSE_TYPE_MOZ_BLOB ) {
2012-07-30 07:20:58 -07:00
xmlHttpRequest - > mResponseBlob = nullptr ;
2012-01-30 02:33:59 -08:00
}
2013-04-27 12:25:24 -07:00
} else if ( xmlHttpRequest - > mResponseType = = XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER | |
xmlHttpRequest - > mResponseType = = XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER ) {
// get the initial capacity to something reasonable to avoid a bunch of reallocs right
// at the start
2013-05-15 11:42:10 -07:00
if ( xmlHttpRequest - > mArrayBufferBuilder . capacity ( ) = = 0 )
2013-04-27 12:25:24 -07:00
xmlHttpRequest - > mArrayBufferBuilder . setCapacity ( PR_MAX ( count , XML_HTTP_REQUEST_ARRAYBUFFER_MIN_SIZE ) ) ;
xmlHttpRequest - > mArrayBufferBuilder . append ( reinterpret_cast < const uint8_t * > ( fromRawSegment ) , count ,
XML_HTTP_REQUEST_ARRAYBUFFER_MAX_GROWTH ) ;
} else if ( xmlHttpRequest - > mResponseType = = XML_HTTP_RESPONSE_TYPE_DEFAULT & &
xmlHttpRequest - > mResponseXML ) {
2011-05-10 16:18:55 -07:00
// Copy for our own use
2012-08-22 08:56:38 -07:00
uint32_t previousLength = xmlHttpRequest - > mResponseBody . Length ( ) ;
2011-05-10 16:18:55 -07:00
xmlHttpRequest - > mResponseBody . Append ( fromRawSegment , count ) ;
if ( count > 0 & & xmlHttpRequest - > mResponseBody . Length ( ) = = previousLength ) {
return NS_ERROR_OUT_OF_MEMORY ;
}
2011-09-23 18:57:36 -07:00
} else if ( xmlHttpRequest - > mResponseType = = XML_HTTP_RESPONSE_TYPE_DEFAULT | |
xmlHttpRequest - > mResponseType = = XML_HTTP_RESPONSE_TYPE_TEXT | |
xmlHttpRequest - > mResponseType = = XML_HTTP_RESPONSE_TYPE_JSON | |
xmlHttpRequest - > mResponseType = = XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT ) {
2011-09-23 18:57:36 -07:00
NS_ASSERTION ( ! xmlHttpRequest - > mResponseXML ,
" We shouldn't be parsing a doc here " ) ;
xmlHttpRequest - > AppendToResponseText ( fromRawSegment , count ) ;
2011-05-10 16:18:55 -07:00
}
2007-03-22 10:30:00 -07:00
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
2013-03-04 01:06:15 -08:00
- > OnDataAvailable ( xmlHttpRequest - > mChannel ,
2007-03-22 10:30:00 -07:00
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 ;
}
}
}
if ( NS_SUCCEEDED ( rv ) ) {
* writeCount = count ;
} else {
* writeCount = 0 ;
}
return rv ;
}
2012-01-30 02:33:59 -08:00
bool nsXMLHttpRequest : : CreateDOMFile ( nsIRequest * request )
2011-05-10 16:18:55 -07:00
{
nsCOMPtr < nsIFile > file ;
2012-11-27 03:48:15 -08:00
nsCOMPtr < nsIFileChannel > fc = do_QueryInterface ( request ) ;
if ( fc ) {
fc - > GetFile ( getter_AddRefs ( file ) ) ;
2011-05-10 16:18:55 -07:00
}
2011-06-30 14:42:15 -07:00
2012-11-27 03:48:15 -08:00
if ( ! file )
return false ;
nsAutoCString contentType ;
mChannel - > GetContentType ( contentType ) ;
mDOMFile =
new nsDOMFileFile ( file , EmptyString ( ) , NS_ConvertASCIItoUTF16 ( contentType ) ) ;
mBlobSet = nullptr ;
NS_ASSERTION ( mResponseBody . IsEmpty ( ) , " mResponseBody should be empty " ) ;
return true ;
2011-05-10 16:18:55 -07:00
}
2007-03-22 10:30:00 -07:00
NS_IMETHODIMP
2011-09-23 18:57:22 -07:00
nsXMLHttpRequest : : OnDataAvailable ( nsIRequest * request ,
nsISupports * ctxt ,
nsIInputStream * inStr ,
2012-09-05 19:41:02 -07:00
uint64_t sourceOffset ,
2012-08-22 08:56:38 -07:00
uint32_t count )
2007-03-22 10:30:00 -07:00
{
NS_ENSURE_ARG_POINTER ( inStr ) ;
NS_ABORT_IF_FALSE ( mContext . get ( ) = = ctxt , " start context different from OnDataAvailable context " ) ;
2011-10-26 05:52:19 -07:00
mProgressSinceLastProgressEvent = true ;
2011-10-28 07:05:07 -07:00
bool cancelable = false ;
2012-01-30 02:33:59 -08:00
if ( ( mResponseType = = XML_HTTP_RESPONSE_TYPE_BLOB | |
mResponseType = = XML_HTTP_RESPONSE_TYPE_MOZ_BLOB ) & & ! mDOMFile ) {
cancelable = CreateDOMFile ( request ) ;
2011-10-28 07:05:07 -07:00
// The nsIStreamListener contract mandates us
// to read from the stream before returning.
2011-05-10 16:18:55 -07:00
}
2012-08-22 08:56:38 -07:00
uint32_t totalRead ;
2011-09-23 18:57:22 -07:00
nsresult rv = inStr - > ReadSegments ( nsXMLHttpRequest : : StreamReaderFunc ,
( void * ) this , count , & totalRead ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2011-10-28 07:05:07 -07:00
if ( cancelable ) {
// We don't have to read from the local file for the blob response
2012-01-30 02:33:59 -08:00
mDOMFile - > GetSize ( & mLoadTransferred ) ;
2011-10-28 07:05:07 -07:00
ChangeState ( XML_HTTP_REQUEST_LOADING ) ;
return request - > Cancel ( NS_OK ) ;
}
2011-09-23 18:57:22 -07:00
mLoadTransferred + = totalRead ;
ChangeState ( XML_HTTP_REQUEST_LOADING ) ;
2011-10-17 07:59:28 -07:00
MaybeDispatchProgressEvents ( false ) ;
2011-09-23 18:57:22 -07:00
return NS_OK ;
2007-03-22 10:30:00 -07:00
}
/* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
NS_IMETHODIMP
nsXMLHttpRequest : : OnStartRequest ( nsIRequest * request , nsISupports * ctxt )
{
2013-03-15 21:47:02 -07:00
PROFILER_LABEL ( " nsXMLHttpRequest " , " OnStartRequest " ) ;
2008-10-19 14:26:37 -07:00
nsresult rv = NS_OK ;
2008-09-30 16:56:57 -07:00
if ( ! mFirstStartRequestSeen & & mRequestObserver ) {
2011-10-17 07:59:28 -07:00
mFirstStartRequestSeen = true ;
2008-09-30 16:56:57 -07:00
mRequestObserver - > OnStartRequest ( request , ctxt ) ;
}
2013-03-04 01:06:15 -08:00
if ( request ! = mChannel ) {
// Can this still happen?
2007-09-05 20:51:56 -07:00
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 ;
2012-01-26 02:02:22 -08:00
/* Apparently, Abort() should set XML_HTTP_REQUEST_UNSENT. See bug 361773.
XHR2 spec says this is correct . */
2007-03-22 10:30:00 -07:00
if ( mState & XML_HTTP_REQUEST_ABORTED ) {
NS_ERROR ( " Ugh, still getting data on an aborted XMLHttpRequest! " ) ;
return NS_ERROR_UNEXPECTED ;
}
2012-01-26 02:02:22 -08:00
// Don't do anything if we have timed out.
if ( mState & XML_HTTP_REQUEST_TIMED_OUT ) {
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
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
2011-09-23 18:57:22 -07:00
nsresult status ;
request - > GetStatus ( & status ) ;
mErrorLoad = mErrorLoad | | NS_FAILED ( status ) ;
if ( mUpload & & ! mUploadComplete & & ! mErrorLoad & &
( mState & XML_HTTP_REQUEST_ASYNC ) ) {
2012-01-26 02:02:22 -08:00
if ( mProgressTimerIsActive ) {
mProgressTimerIsActive = false ;
2011-09-23 18:57:22 -07:00
mProgressNotifier - > Cancel ( ) ;
}
2011-10-17 07:59:28 -07:00
MaybeDispatchProgressEvents ( true ) ;
mUploadComplete = true ;
2011-09-23 18:57:22 -07:00
DispatchProgressEvent ( mUpload , NS_LITERAL_STRING ( LOAD_STR ) ,
2011-10-17 07:59:28 -07:00
true , mUploadTotal , mUploadTotal ) ;
2011-09-23 18:57:22 -07:00
}
2007-03-22 10:30:00 -07:00
mContext = ctxt ;
mState | = XML_HTTP_REQUEST_PARSEBODY ;
2011-05-10 16:18:55 -07:00
ChangeState ( XML_HTTP_REQUEST_HEADERS_RECEIVED ) ;
2011-09-23 18:57:22 -07:00
ResetResponse ( ) ;
2008-10-11 23:30:14 -07:00
2011-09-23 18:57:36 -07:00
if ( ! mOverrideMimeType . IsEmpty ( ) ) {
2012-03-26 08:38:06 -07:00
channel - > SetContentType ( NS_ConvertUTF16toUTF8 ( mOverrideMimeType ) ) ;
2011-09-23 18:57:36 -07:00
}
DetectCharset ( ) ;
2013-05-15 11:42:10 -07:00
// Set up arraybuffer
if ( mResponseType = = XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER & & NS_SUCCEEDED ( status ) ) {
int64_t contentLength ;
rv = channel - > GetContentLength ( & contentLength ) ;
if ( NS_SUCCEEDED ( rv ) & &
contentLength > 0 & &
contentLength < XML_HTTP_REQUEST_MAX_CONTENT_LENGTH_PREALLOCATE ) {
mArrayBufferBuilder . setCapacity ( static_cast < int32_t > ( contentLength ) ) ;
}
}
2008-10-11 23:30:14 -07:00
// Set up responseXML
2011-09-28 23:19:26 -07:00
bool parseBody = mResponseType = = XML_HTTP_RESPONSE_TYPE_DEFAULT | |
2011-05-10 16:18:55 -07:00
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 ) {
2012-09-01 19:35:17 -07:00
nsAutoCString method ;
2007-03-22 10:30:00 -07:00
httpChannel - > GetRequestMethod ( method ) ;
parseBody = ! method . EqualsLiteral ( " HEAD " ) ;
}
2011-11-15 23:38:51 -08:00
mIsHtml = false ;
mWarnAboutSyncHtml = false ;
2007-03-22 10:30:00 -07:00
if ( parseBody & & NS_SUCCEEDED ( status ) ) {
// 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.
2012-09-01 19:35:17 -07:00
nsAutoCString type ;
2007-03-22 10:30:00 -07:00
channel - > GetContentType ( type ) ;
2011-11-24 07:28:12 -08:00
if ( ( mResponseType = = XML_HTTP_RESPONSE_TYPE_DOCUMENT ) & &
type . EqualsLiteral ( " text/html " ) ) {
// HTML parsing is only supported for responseType == "document" to
// avoid running the parser and, worse, populating responseXML for
// legacy users of XHR who use responseType == "" for retrieving the
// responseText of text/html resources. This legacy case is so common
// that it's not useful to emit a warning about it.
2011-11-15 23:38:51 -08:00
if ( ! ( mState & XML_HTTP_REQUEST_ASYNC ) ) {
// We don't make cool new features available in the bad synchronous
// mode. The synchronous mode is for legacy only.
mWarnAboutSyncHtml = true ;
mState & = ~ XML_HTTP_REQUEST_PARSEBODY ;
} else {
mIsHtml = true ;
}
} else if ( type . Find ( " xml " ) = = kNotFound ) {
2007-03-22 10:30:00 -07:00
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 ;
2012-03-12 17:56:07 -07:00
nsIScriptContext * sc = GetContextForEventHandlers ( & rv ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2009-06-15 01:27:29 -07:00
nsCOMPtr < nsIDocument > doc =
2012-03-12 17:56:07 -07:00
nsContentUtils : : GetDocumentFromScriptContext ( sc ) ;
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 ( ) ;
2012-03-26 08:38:06 -07:00
nsCOMPtr < nsIDOMDocument > responseDoc ;
2013-04-04 02:32:29 -07:00
nsIGlobalObject * global = nsDOMEventTargetHelper : : GetParentObject ( ) ;
2012-12-10 06:05:33 -08:00
rv = NS_NewDOMDocument ( getter_AddRefs ( responseDoc ) ,
emptyStr , emptyStr , nullptr , docURI ,
baseURI , mPrincipal , true , global ,
mIsHtml ? DocumentFlavorHTML :
DocumentFlavorLegacyGuess ) ;
2008-10-11 23:30:14 -07:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2012-03-26 08:38:06 -07:00
mResponseXML = do_QueryInterface ( responseDoc ) ;
mResponseXML - > SetPrincipal ( documentPrincipal ) ;
2008-10-11 23:30:14 -07:00
2012-06-07 11:28:33 -07:00
if ( nsContentUtils : : IsSystemPrincipal ( mPrincipal ) ) {
2012-03-26 08:38:06 -07:00
mResponseXML - > ForceEnableXULXBL ( ) ;
2010-08-25 13:12:28 -07:00
}
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 ( ) ;
}
}
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsIStreamListener > listener ;
nsCOMPtr < nsILoadGroup > loadGroup ;
channel - > GetLoadGroup ( getter_AddRefs ( loadGroup ) ) ;
2012-03-26 08:38:06 -07:00
rv = mResponseXML - > StartDocumentLoad ( kLoadAsData , channel , loadGroup ,
2012-07-30 07:20:58 -07:00
nullptr , getter_AddRefs ( listener ) ,
2012-03-26 08:38:06 -07:00
! ( 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 ) & &
2012-10-28 21:33:51 -07:00
HasListenersFor ( nsGkAtoms : : onprogress ) ) {
2008-10-19 14:26:37 -07:00
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 )
{
2013-03-15 21:47:02 -07:00
PROFILER_LABEL ( " content " , " nsXMLHttpRequest::OnStopRequest " ) ;
2013-03-04 01:06:15 -08:00
if ( request ! = mChannel ) {
// Can this still happen?
2007-09-05 20:51:56 -07:00
return NS_OK ;
}
2012-02-16 08:45:25 -08:00
mWaitingForOnStopRequest = false ;
2013-03-04 01:06:15 -08:00
if ( mRequestObserver ) {
2008-11-26 22:16:37 -08:00
NS_ASSERTION ( mFirstStartRequestSeen , " Inconsistent state! " ) ;
2011-10-17 07:59:28 -07:00
mFirstStartRequestSeen = false ;
2008-11-26 22:16:37 -08:00
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??
2012-01-26 02:02:22 -08:00
// XML_HTTP_REQUEST_UNSENT is for abort calls. See OnStartRequest above.
if ( ( mState & XML_HTTP_REQUEST_UNSENT ) | |
( mState & XML_HTTP_REQUEST_TIMED_OUT ) ) {
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
// Is this good enough here?
if ( mState & XML_HTTP_REQUEST_PARSEBODY & & mXMLParserStreamListener ) {
2011-06-14 00:53:08 -07:00
mXMLParserStreamListener - > OnStopRequest ( request , ctxt , status ) ;
2008-11-26 22:16:37 -08:00
}
2012-07-30 07:20:58 -07:00
mXMLParserStreamListener = nullptr ;
mContext = nullptr ;
2007-03-22 10:30:00 -07:00
2011-09-23 18:57:22 -07:00
// If we're received data since the last progress event, make sure to fire
2011-11-15 23:38:51 -08:00
// an event for it, except in the HTML case, defer the last progress event
// until the parser is done.
if ( ! mIsHtml ) {
MaybeDispatchProgressEvents ( true ) ;
}
2011-09-23 18:57:22 -07:00
2012-01-30 02:33:59 -08:00
if ( NS_SUCCEEDED ( status ) & &
( mResponseType = = XML_HTTP_RESPONSE_TYPE_BLOB | |
mResponseType = = XML_HTTP_RESPONSE_TYPE_MOZ_BLOB ) ) {
if ( ! mDOMFile ) {
CreateDOMFile ( request ) ;
2011-05-10 16:18:55 -07:00
}
2012-01-30 02:33:59 -08:00
if ( mDOMFile ) {
mResponseBlob = mDOMFile ;
2012-07-30 07:20:58 -07:00
mDOMFile = nullptr ;
2012-01-30 02:33:59 -08:00
} else {
2012-09-20 00:55:36 -07:00
// mBlobSet can be null if the channel is non-file non-cacheable
2012-09-17 15:42:36 -07:00
// and if the response length is zero.
2012-09-20 00:55:36 -07:00
if ( ! mBlobSet ) {
mBlobSet = new BlobSet ( ) ;
2012-09-17 15:42:36 -07:00
}
2011-05-10 16:18:55 -07:00
// Smaller files may be written in cache map instead of separate files.
// Also, no-store response cannot be written in persistent cache.
2012-09-01 19:35:17 -07:00
nsAutoCString contentType ;
2011-05-10 16:18:55 -07:00
mChannel - > GetContentType ( contentType ) ;
2012-09-20 00:55:36 -07:00
mResponseBlob = mBlobSet - > GetBlobInternal ( contentType ) ;
mBlobSet = nullptr ;
2011-05-10 16:18:55 -07:00
}
2012-01-30 02:33:59 -08:00
NS_ASSERTION ( mResponseBody . IsEmpty ( ) , " mResponseBody should be empty " ) ;
NS_ASSERTION ( mResponseText . IsEmpty ( ) , " mResponseText should be empty " ) ;
2013-04-27 12:25:24 -07:00
} else if ( NS_SUCCEEDED ( status ) & &
( mResponseType = = XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER | |
mResponseType = = XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER ) ) {
// set the capacity down to the actual length, to realloc back
// down to the actual size
if ( ! mArrayBufferBuilder . setCapacity ( mArrayBufferBuilder . length ( ) ) ) {
// this should never happen!
status = NS_ERROR_UNEXPECTED ;
}
2011-05-10 16:18:55 -07:00
}
2012-01-30 02:33:59 -08:00
nsCOMPtr < nsIChannel > channel ( do_QueryInterface ( request ) ) ;
NS_ENSURE_TRUE ( channel , NS_ERROR_UNEXPECTED ) ;
2012-07-30 07:20:58 -07:00
channel - > SetNotificationCallbacks ( nullptr ) ;
mNotificationCallbacks = nullptr ;
mChannelEventSink = nullptr ;
mProgressEventSink = nullptr ;
2007-03-22 10:30:00 -07:00
2011-11-16 11:50:48 -08:00
mState & = ~ XML_HTTP_REQUEST_SYNCLOOPING ;
2007-03-22 10:30:00 -07:00
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.
2011-10-17 07:59:28 -07:00
mErrorLoad = true ;
2012-07-30 07:20:58 -07:00
mResponseXML = nullptr ;
2007-03-22 10:30:00 -07:00
}
// 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 ;
}
2011-11-15 23:38:51 -08:00
if ( ! mResponseXML ) {
ChangeStateToDone ( ) ;
return NS_OK ;
}
if ( mIsHtml ) {
NS_ASSERTION ( ! ( mState & XML_HTTP_REQUEST_SYNCLOOPING ) ,
" We weren't supposed to support HTML parsing with XHR! " ) ;
2013-04-05 17:44:26 -07:00
nsCOMPtr < EventTarget > eventTarget = do_QueryInterface ( mResponseXML ) ;
2013-10-14 11:38:54 -07:00
nsEventListenerManager * manager = eventTarget - > GetListenerManager ( true ) ;
2011-11-15 23:38:51 -08:00
manager - > AddEventListenerByType ( new nsXHRParseEndListener ( this ) ,
NS_LITERAL_STRING ( " DOMContentLoaded " ) ,
2012-12-15 17:26:05 -08:00
dom : : TrustedEventsAtSystemGroupBubble ( ) ) ;
2011-11-15 23:38:51 -08:00
return NS_OK ;
}
2011-11-16 11:50:48 -08:00
// We might have been sent non-XML data. If that was the case,
// we should null out the document member. The idea in this
// check here is that if there is no document element it is not
// an XML document. We might need a fancier check...
2012-03-26 08:38:06 -07:00
if ( ! mResponseXML - > GetRootElement ( ) ) {
2012-07-30 07:20:58 -07:00
mResponseXML = nullptr ;
2007-03-22 10:30:00 -07:00
}
2011-11-15 23:38:51 -08:00
ChangeStateToDone ( ) ;
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
2011-11-15 23:38:51 -08:00
void
nsXMLHttpRequest : : ChangeStateToDone ( )
{
if ( mIsHtml ) {
// In the HTML case, this has to be deferred, because the parser doesn't
// do it's job synchronously.
MaybeDispatchProgressEvents ( true ) ;
}
2012-01-26 02:02:22 -08:00
2011-10-17 07:59:28 -07:00
ChangeState ( XML_HTTP_REQUEST_DONE , true ) ;
2012-01-26 02:02:22 -08:00
if ( mTimeoutTimer ) {
mTimeoutTimer - > Cancel ( ) ;
}
2007-03-22 10:30:00 -07:00
2008-08-14 04:07:46 -07:00
NS_NAMED_LITERAL_STRING ( errorStr , ERROR_STR ) ;
NS_NAMED_LITERAL_STRING ( loadStr , LOAD_STR ) ;
DispatchProgressEvent ( this ,
mErrorLoad ? errorStr : loadStr ,
! mErrorLoad ,
2011-09-23 18:57:22 -07:00
mLoadTransferred ,
mErrorLoad ? 0 : mLoadTransferred ) ;
2008-08-14 04:07:46 -07:00
if ( mErrorLoad & & mUpload & & ! mUploadComplete ) {
2011-10-17 07:59:28 -07:00
DispatchProgressEvent ( mUpload , errorStr , true ,
2008-08-14 04:07:46 -07:00
mUploadTransferred , mUploadTotal ) ;
2007-03-22 10:30:00 -07:00
}
2011-06-14 00:53:08 -07:00
if ( mErrorLoad ) {
// 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.
2012-07-30 07:20:58 -07:00
mChannel = nullptr ;
mCORSPreflightChannel = nullptr ;
2011-06-14 00:53:08 -07:00
}
2007-03-22 10:30:00 -07:00
}
2007-07-24 21:53:21 -07:00
NS_IMETHODIMP
2012-06-20 03:18:39 -07:00
nsXMLHttpRequest : : SendAsBinary ( const nsAString & aBody )
2012-03-26 08:38:06 -07:00
{
2012-05-05 18:15:11 -07:00
ErrorResult rv ;
2012-06-20 03:18:39 -07:00
SendAsBinary ( aBody , rv ) ;
2012-05-05 18:15:11 -07:00
return rv . ErrorCode ( ) ;
2012-03-26 08:38:06 -07:00
}
void
2012-06-20 03:18:39 -07:00
nsXMLHttpRequest : : SendAsBinary ( const nsAString & aBody ,
2012-05-05 18:15:11 -07:00
ErrorResult & aRv )
2007-07-24 21:53:21 -07:00
{
char * data = static_cast < char * > ( NS_Alloc ( aBody . Length ( ) + 1 ) ) ;
2012-03-26 08:38:06 -07:00
if ( ! data ) {
2012-05-05 18:15:11 -07:00
aRv . Throw ( NS_ERROR_OUT_OF_MEMORY ) ;
2012-03-26 08:38:06 -07:00
return ;
}
2007-07-24 21:53:21 -07:00
nsAString : : const_iterator iter , end ;
aBody . BeginReading ( iter ) ;
aBody . EndReading ( end ) ;
char * p = data ;
while ( iter ! = end ) {
if ( * iter & 0xFF00 ) {
NS_Free ( data ) ;
2012-05-05 18:15:11 -07:00
aRv . Throw ( NS_ERROR_DOM_INVALID_CHARACTER_ERR ) ;
2012-03-26 08:38:06 -07:00
return ;
2007-07-24 21:53:21 -07:00
}
* p + + = static_cast < char > ( * iter + + ) ;
}
* p = ' \0 ' ;
nsCOMPtr < nsIInputStream > stream ;
2012-03-26 08:38:06 -07:00
aRv = NS_NewByteInputStream ( getter_AddRefs ( stream ) , data , aBody . Length ( ) ,
NS_ASSIGNMENT_ADOPT ) ;
2012-05-05 18:15:11 -07:00
if ( aRv . Failed ( ) ) {
2007-07-24 21:53:21 -07:00
NS_Free ( data ) ;
2012-03-26 08:38:06 -07:00
return ;
}
2007-07-24 21:53:21 -07:00
nsCOMPtr < nsIWritableVariant > variant = new nsVariant ( ) ;
2012-03-26 08:38:06 -07:00
aRv = variant - > SetAsISupports ( stream ) ;
2012-05-05 18:15:11 -07:00
if ( aRv . Failed ( ) ) {
2012-03-26 08:38:06 -07:00
return ;
}
2012-06-20 03:18:39 -07:00
aRv = Send ( variant ) ;
2012-03-26 08:38:06 -07:00
}
static nsresult
2012-09-22 09:40:28 -07:00
GetRequestBody ( nsIDOMDocument * aDoc , nsIInputStream * * aResult ,
uint64_t * aContentLength , nsACString & aContentType ,
nsACString & aCharset )
2012-03-26 08:38:06 -07:00
{
aContentType . AssignLiteral ( " application/xml " ) ;
nsAutoString inputEncoding ;
aDoc - > GetInputEncoding ( inputEncoding ) ;
if ( ! DOMStringIsNull ( inputEncoding ) ) {
CopyUTF16toUTF8 ( inputEncoding , aCharset ) ;
}
else {
aCharset . AssignLiteral ( " UTF-8 " ) ;
}
// Serialize to a stream so that the encoding used will
// match the document's.
nsresult rv ;
nsCOMPtr < nsIDOMSerializer > serializer =
do_CreateInstance ( NS_XMLSERIALIZER_CONTRACTID , & rv ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
nsCOMPtr < nsIStorageStream > storStream ;
2012-09-27 23:57:33 -07:00
rv = NS_NewStorageStream ( 4096 , UINT32_MAX , getter_AddRefs ( storStream ) ) ;
2012-03-26 08:38:06 -07:00
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
2013-05-16 13:11:55 -07:00
rv = serializer - > SerializeToStream ( aDoc , output , aCharset ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2007-07-24 21:53:21 -07:00
2012-03-26 08:38:06 -07:00
output - > Close ( ) ;
2012-09-19 15:15:32 -07:00
uint32_t length ;
rv = storStream - > GetLength ( & length ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
* aContentLength = length ;
2012-03-26 08:38:06 -07:00
return storStream - > NewInputStream ( 0 , aResult ) ;
2007-07-24 21:53:21 -07:00
}
2010-02-24 21:58:17 -08:00
static nsresult
2012-09-22 09:40:28 -07:00
GetRequestBody ( const nsAString & aString , nsIInputStream * * aResult ,
uint64_t * aContentLength , nsACString & aContentType ,
nsACString & aCharset )
2010-02-24 21:58:17 -08:00
{
aContentType . AssignLiteral ( " text/plain " ) ;
aCharset . AssignLiteral ( " UTF-8 " ) ;
2012-09-19 15:15:32 -07:00
nsCString converted = NS_ConvertUTF16toUTF8 ( aString ) ;
* aContentLength = converted . Length ( ) ;
return NS_NewCStringInputStream ( aResult , converted ) ;
2012-03-26 08:38:06 -07:00
}
static nsresult
2012-09-22 09:40:28 -07:00
GetRequestBody ( nsIInputStream * aStream , nsIInputStream * * aResult ,
uint64_t * aContentLength , nsACString & aContentType ,
nsACString & aCharset )
2012-03-26 08:38:06 -07:00
{
aContentType . AssignLiteral ( " text/plain " ) ;
aCharset . Truncate ( ) ;
2012-09-19 15:15:32 -07:00
nsresult rv = aStream - > Available ( aContentLength ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2012-03-26 08:38:06 -07:00
NS_ADDREF ( * aResult = aStream ) ;
return NS_OK ;
}
static nsresult
2012-09-19 15:15:32 -07:00
GetRequestBody ( nsIXHRSendable * aSendable , nsIInputStream * * aResult , uint64_t * aContentLength ,
2012-03-26 08:38:06 -07:00
nsACString & aContentType , nsACString & aCharset )
{
2012-09-19 15:15:32 -07:00
return aSendable - > GetSendInfo ( aResult , aContentLength , aContentType , aCharset ) ;
2012-03-26 08:38:06 -07:00
}
2012-12-19 17:47:39 -08:00
// Used for array buffers and array buffer views
2012-03-26 08:38:06 -07:00
static nsresult
2012-12-19 17:47:39 -08:00
GetRequestBody ( const uint8_t * aData , uint32_t aDataLength ,
nsIInputStream * * aResult , uint64_t * aContentLength ,
2012-03-26 08:38:06 -07:00
nsACString & aContentType , nsACString & aCharset )
{
aContentType . SetIsVoid ( true ) ;
aCharset . Truncate ( ) ;
2012-12-19 17:47:39 -08:00
* aContentLength = aDataLength ;
const char * data = reinterpret_cast < const char * > ( aData ) ;
2012-03-26 08:38:06 -07:00
nsCOMPtr < nsIInputStream > stream ;
2012-12-19 17:47:39 -08:00
nsresult rv = NS_NewByteInputStream ( getter_AddRefs ( stream ) , data , aDataLength ,
2012-03-26 08:38:06 -07:00
NS_ASSIGNMENT_COPY ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
stream . forget ( aResult ) ;
return NS_OK ;
}
static nsresult
2012-09-19 15:15:32 -07:00
GetRequestBody ( nsIVariant * aBody , nsIInputStream * * aResult , uint64_t * aContentLength ,
2012-03-26 08:38:06 -07:00
nsACString & aContentType , nsACString & aCharset )
{
2012-07-30 07:20:58 -07:00
* aResult = nullptr ;
2012-03-26 08:38:06 -07:00
2012-08-22 08:56:38 -07:00
uint16_t dataType ;
2010-02-24 21:58:17 -08:00
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 ) {
2012-09-19 15:15:32 -07:00
return GetRequestBody ( doc , aResult , aContentLength , aContentType , aCharset ) ;
2010-02-24 21:58:17 -08:00
}
// nsISupportsString?
nsCOMPtr < nsISupportsString > wstr = do_QueryInterface ( supports ) ;
if ( wstr ) {
nsAutoString string ;
wstr - > GetData ( string ) ;
2012-09-19 15:15:32 -07:00
return GetRequestBody ( string , aResult , aContentLength , aContentType , aCharset ) ;
2010-02-24 21:58:17 -08:00
}
// nsIInputStream?
nsCOMPtr < nsIInputStream > stream = do_QueryInterface ( supports ) ;
if ( stream ) {
2012-09-19 15:15:32 -07:00
return GetRequestBody ( stream , aResult , aContentLength , aContentType , aCharset ) ;
2010-02-24 21:58:17 -08:00
}
2010-02-24 21:58:18 -08:00
// nsIXHRSendable?
nsCOMPtr < nsIXHRSendable > sendable = do_QueryInterface ( supports ) ;
if ( sendable ) {
2012-09-19 15:15:32 -07:00
return GetRequestBody ( sendable , aResult , aContentLength , aContentType , aCharset ) ;
2010-02-24 21:58:18 -08:00
}
2011-08-17 18:44:56 -07:00
// ArrayBuffer?
2013-05-07 19:34:56 -07:00
AutoSafeJSContext cx ;
JS : : Rooted < JS : : Value > realVal ( cx ) ;
2012-06-20 03:18:39 -07:00
2013-05-07 19:34:56 -07:00
nsresult rv = aBody - > GetAsJSVal ( realVal . address ( ) ) ;
2012-08-21 18:42:53 -07:00
if ( NS_SUCCEEDED ( rv ) & & ! JSVAL_IS_PRIMITIVE ( realVal ) ) {
2013-05-07 19:34:56 -07:00
JS : : Rooted < JSObject * > obj ( cx , JSVAL_TO_OBJECT ( realVal ) ) ;
2012-11-14 09:56:26 -08:00
if ( JS_IsArrayBufferObject ( obj ) ) {
ArrayBuffer buf ( obj ) ;
2012-12-19 17:47:39 -08:00
return GetRequestBody ( buf . Data ( ) , buf . Length ( ) , aResult ,
aContentLength , aContentType , aCharset ) ;
2012-08-21 18:42:53 -07:00
}
2011-08-17 18:44:56 -07:00
}
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
2012-03-26 08:38:06 -07:00
aContentType . AssignLiteral ( " text/plain " ) ;
aCharset . AssignLiteral ( " UTF-8 " ) ;
2012-09-19 15:15:32 -07:00
* aContentLength = 0 ;
2012-03-26 08:38:06 -07:00
2010-02-24 21:58:17 -08:00
return NS_OK ;
}
2012-07-30 07:20:58 -07:00
PRUnichar * data = nullptr ;
2012-08-22 08:56:38 -07:00
uint32_t len = 0 ;
2010-02-24 21:58:17 -08:00
rv = aBody - > GetAsWStringWithSize ( & len , & data ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
nsString string ;
string . Adopt ( data , len ) ;
2012-09-19 15:15:32 -07:00
return GetRequestBody ( string , aResult , aContentLength , aContentType , aCharset ) ;
2012-03-26 08:38:06 -07:00
}
/* static */
nsresult
2012-06-20 03:18:39 -07:00
nsXMLHttpRequest : : GetRequestBody ( nsIVariant * aVariant ,
2012-03-30 21:42:20 -07:00
const Nullable < RequestBody > & aBody ,
2012-09-22 09:40:28 -07:00
nsIInputStream * * aResult ,
uint64_t * aContentLength ,
2012-03-26 08:38:06 -07:00
nsACString & aContentType , nsACString & aCharset )
{
if ( aVariant ) {
2012-09-19 15:15:32 -07:00
return : : GetRequestBody ( aVariant , aResult , aContentLength , aContentType , aCharset ) ;
2012-03-26 08:38:06 -07:00
}
2012-03-30 21:42:20 -07:00
const RequestBody & body = aBody . Value ( ) ;
2012-03-26 08:38:06 -07:00
RequestBody : : Value value = body . GetValue ( ) ;
switch ( body . GetType ( ) ) {
case nsXMLHttpRequest : : RequestBody : : ArrayBuffer :
{
2012-12-19 17:47:39 -08:00
return : : GetRequestBody ( value . mArrayBuffer - > Data ( ) ,
value . mArrayBuffer - > Length ( ) , aResult ,
aContentLength , aContentType , aCharset ) ;
}
case nsXMLHttpRequest : : RequestBody : : ArrayBufferView :
{
return : : GetRequestBody ( value . mArrayBufferView - > Data ( ) ,
value . mArrayBufferView - > Length ( ) , aResult ,
aContentLength , aContentType , aCharset ) ;
2012-03-26 08:38:06 -07:00
}
case nsXMLHttpRequest : : RequestBody : : Blob :
{
nsresult rv ;
nsCOMPtr < nsIXHRSendable > sendable = do_QueryInterface ( value . mBlob , & rv ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2012-09-19 15:15:32 -07:00
return : : GetRequestBody ( sendable , aResult , aContentLength , aContentType , aCharset ) ;
2012-03-26 08:38:06 -07:00
}
case nsXMLHttpRequest : : RequestBody : : Document :
{
nsCOMPtr < nsIDOMDocument > document = do_QueryInterface ( value . mDocument ) ;
2012-09-19 15:15:32 -07:00
return : : GetRequestBody ( document , aResult , aContentLength , aContentType , aCharset ) ;
2012-03-26 08:38:06 -07:00
}
case nsXMLHttpRequest : : RequestBody : : DOMString :
{
2012-09-19 15:15:32 -07:00
return : : GetRequestBody ( * value . mString , aResult , aContentLength ,
aContentType , aCharset ) ;
2012-03-26 08:38:06 -07:00
}
case nsXMLHttpRequest : : RequestBody : : FormData :
{
2012-12-11 10:09:56 -08:00
MOZ_ASSERT ( value . mFormData ) ;
return : : GetRequestBody ( value . mFormData , aResult , aContentLength ,
aContentType , aCharset ) ;
2012-03-26 08:38:06 -07:00
}
case nsXMLHttpRequest : : RequestBody : : InputStream :
{
2012-09-19 15:15:32 -07:00
return : : GetRequestBody ( value . mStream , aResult , aContentLength ,
aContentType , aCharset ) ;
2012-03-26 08:38:06 -07:00
}
default :
{
return NS_ERROR_FAILURE ;
}
}
NS_NOTREACHED ( " Default cases exist for a reason " ) ;
return NS_OK ;
2010-02-24 21:58:17 -08:00
}
2007-03-22 10:30:00 -07:00
/* void send (in nsIVariant aBody); */
NS_IMETHODIMP
2012-06-20 03:18:39 -07:00
nsXMLHttpRequest : : Send ( nsIVariant * aBody )
2012-03-26 08:38:06 -07:00
{
2012-06-20 03:18:39 -07:00
return Send ( aBody , Nullable < RequestBody > ( ) ) ;
2012-03-26 08:38:06 -07:00
}
nsresult
2012-06-20 03:18:39 -07:00
nsXMLHttpRequest : : Send ( nsIVariant * aVariant , const Nullable < RequestBody > & aBody )
2007-03-22 10:30:00 -07:00
{
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.
2012-10-28 21:33:51 -07:00
if ( HasListenersFor ( nsGkAtoms : : onprogress ) | |
( mUpload & & mUpload - > HasListenersFor ( nsGkAtoms : : onprogress ) ) ) {
2010-09-08 10:42:08 -07:00
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
2012-09-01 19:35:17 -07:00
nsAutoCString method ;
2007-03-22 10:30:00 -07:00
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 ) ) ;
2012-03-12 17:56:07 -07:00
nsIScriptContext * sc = GetContextForEventHandlers ( & rv ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2011-01-30 13:46:34 -08:00
nsCOMPtr < nsIDocument > doc =
2012-03-12 17:56:07 -07:00
nsContentUtils : : GetDocumentFromScriptContext ( sc ) ;
2011-01-30 13:46:34 -08:00
nsCOMPtr < nsIURI > docCurURI ;
nsCOMPtr < nsIURI > docOrigURI ;
if ( doc ) {
docCurURI = doc - > GetDocumentURI ( ) ;
docOrigURI = doc - > GetOriginalURI ( ) ;
}
nsCOMPtr < nsIURI > referrerURI ;
if ( principalURI & & docCurURI & & docOrigURI ) {
2011-09-28 23:19:26 -07:00
bool equal = false ;
2011-01-30 13:46:34 -08:00
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.
2011-10-17 07:59:28 -07:00
mUploadComplete = true ;
mErrorLoad = false ;
mLoadLengthComputable = false ;
2008-10-19 14:26:37 -07:00
mLoadTotal = 0 ;
2012-03-30 21:42:20 -07:00
if ( ( aVariant | | ! aBody . IsNull ( ) ) & & httpChannel & &
2013-05-15 04:48:59 -07:00
! method . LowerCaseEqualsLiteral ( " get " ) & &
! method . LowerCaseEqualsLiteral ( " head " ) ) {
2008-10-14 17:12:28 -07:00
2012-09-01 19:35:17 -07:00
nsAutoCString charset ;
nsAutoCString defaultContentType ;
2010-02-24 21:58:17 -08:00
nsCOMPtr < nsIInputStream > postDataStream ;
2008-10-14 17:12:28 -07:00
2012-06-20 03:18:39 -07:00
rv = GetRequestBody ( aVariant , aBody , getter_AddRefs ( postDataStream ) ,
2012-09-19 15:15:32 -07:00
& mUploadTotal , defaultContentType , charset ) ;
2010-02-24 21:58:17 -08:00
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.
2012-09-01 19:35:17 -07:00
nsAutoCString contentType ;
2008-10-14 17:12:28 -07:00
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 ( ) ) {
2012-09-01 19:35:17 -07:00
nsAutoCString specifiedCharset ;
2011-09-28 23:19:26 -07:00
bool haveCharset ;
2012-08-22 08:56:38 -07:00
int32_t charsetStart , charsetEnd ;
2008-10-14 17:12:28 -07:00
rv = NS_ExtractCharsetFromContentType ( contentType , specifiedCharset ,
& haveCharset , & charsetStart ,
& charsetEnd ) ;
2009-01-13 22:53:43 -08:00
if ( NS_SUCCEEDED ( rv ) ) {
2011-11-29 14:06:32 -08:00
// special case: the extracted charset is quoted with single quotes
// -- for the purpose of preserving what was set we want to handle
// them as delimiters (although they aren't really)
if ( specifiedCharset . Length ( ) > = 2 & &
specifiedCharset . First ( ) = = ' \' ' & &
specifiedCharset . Last ( ) = = ' \' ' ) {
specifiedCharset = Substring ( specifiedCharset , 1 ,
specifiedCharset . Length ( ) - 2 ) ;
}
2009-01-13 22:53:43 -08:00
// 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 ( ) ) ) {
2012-09-01 19:35:17 -07:00
nsAutoCString newCharset ( " ; charset= " ) ;
2009-01-13 22:53:43 -08:00
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 ;
}
2011-10-17 07:59:28 -07:00
mUploadComplete = false ;
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 ,
2012-09-19 15:15:32 -07:00
mUploadTotal , method , false ) ;
2009-11-18 15:21:13 -08:00
}
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 ) ;
2012-09-19 15:15:32 -07:00
uploadChannel - > SetUploadStream ( postDataStream , contentType , mUploadTotal ) ;
2009-11-18 15:21:13 -08:00
// 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 ) {
2012-09-01 19:35:17 -07:00
nsAutoCString contentTypeHeader ;
2010-10-04 17:41:07 -07:00
rv = httpChannel - > GetRequestHeader ( NS_LITERAL_CSTRING ( " Content-Type " ) ,
contentTypeHeader ) ;
if ( NS_SUCCEEDED ( rv ) ) {
2012-09-01 19:35:17 -07:00
nsAutoCString contentType , charset ;
2010-10-04 17:41:07 -07:00
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
}
}
}
2011-09-23 18:57:22 -07:00
ResetResponse ( ) ;
2007-03-22 10:30:00 -07:00
2008-09-30 17:49:30 -07:00
rv = CheckChannelForCrossSiteRequest ( mChannel ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2011-09-28 23:19:26 -07:00
bool withCredentials = ! ! ( mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS ) ;
2008-09-30 17:52:52 -07:00
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 ) ;
2012-03-22 16:39:31 -07:00
// Blocking gets are common enough out of XHR that we should mark
// the channel slow by default for pipeline purposes
AddLoadFlags ( mChannel , nsIRequest : : INHIBIT_PIPELINE ) ;
2012-12-04 15:06:29 -08:00
nsCOMPtr < nsIHttpChannelInternal >
internalHttpChannel ( do_QueryInterface ( mChannel ) ) ;
if ( internalHttpChannel ) {
// we never let XHR be blocked by head CSS/JS loads to avoid
// potential deadlock where server generation of CSS/JS requires
// an XHR signal.
internalHttpChannel - > SetLoadUnblocked ( true ) ;
}
2013-03-04 01:06:15 -08:00
nsCOMPtr < nsIStreamListener > listener = this ;
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.
2012-09-18 19:16:23 -07:00
nsRefPtr < nsCORSListenerProxy > corsListener =
new nsCORSListenerProxy ( listener , mPrincipal , withCredentials ) ;
rv = corsListener - > Init ( mChannel , true ) ;
2008-09-30 17:49:30 -07:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2012-09-18 19:16:23 -07:00
listener = corsListener ;
2008-09-30 17:49:30 -07:00
}
2012-05-10 11:58:48 -07:00
else {
// Because of bug 682305, we can't let listener be the XHR object itself
// because JS wouldn't be able to use it. So if we haven't otherwise
// created a listener around 'this', do so now.
listener = new nsStreamListenerWrapper ( listener ) ;
}
2012-06-07 11:28:33 -07:00
if ( mIsAnon ) {
AddLoadFlags ( mChannel , nsIRequest : : LOAD_ANONYMOUS ) ;
}
2012-10-24 07:05:13 -07:00
else {
AddLoadFlags ( mChannel , nsIChannel : : LOAD_EXPLICIT_CREDENTIALS ) ;
}
2012-06-07 11:28:33 -07:00
2012-05-10 11:58:48 -07:00
NS_ASSERTION ( listener ! = this ,
" Using an object as a listener that can't be exposed to JS " ) ;
2008-09-30 17:49:30 -07:00
2008-10-14 17:12:28 -07:00
// Bypass the network cache in cases where it makes no sense:
2013-03-04 01:06:15 -08:00
// 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 ( method . EqualsLiteral ( " POST " ) ) {
2008-10-14 17:12:28 -07:00
AddLoadFlags ( mChannel ,
nsIRequest : : LOAD_BYPASS_CACHE | nsIRequest : : INHIBIT_CACHING ) ;
}
// When we are sync loading, we need to bypass the local cache when it would
// otherwise block us waiting for exclusive access to the cache. If we don't
// do this, then we could dead lock in some cases (see bug 309424).
else if ( ! ( mState & XML_HTTP_REQUEST_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
2012-08-27 16:34:30 -07:00
// if the channel doesn't know any content type.
2008-10-14 17:12:28 -07:00
// This means that we always try to parse local files as XML
// ignoring return value, as this is not critical
2012-09-01 19:35:17 -07:00
nsAutoCString contentType ;
2012-08-27 16:34:30 -07:00
if ( NS_FAILED ( mChannel - > GetContentType ( contentType ) ) | |
contentType . IsEmpty ( ) | |
contentType . Equals ( UNKNOWN_CONTENT_TYPE ) ) {
mChannel - > SetContentType ( NS_LITERAL_CSTRING ( " application/xml " ) ) ;
}
2007-03-22 10:30:00 -07:00
2012-01-26 02:02:22 -08:00
// We're about to send the request. Start our timeout.
mRequestSentTime = PR_Now ( ) ;
StartTimeoutTimer ( ) ;
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
2012-07-30 07:20:58 -07:00
rv = mChannel - > AsyncOpen ( listener , nullptr ) ;
2008-09-30 17:49:30 -07:00
}
2007-03-22 10:30:00 -07:00
if ( NS_FAILED ( rv ) ) {
// Drop our ref to the channel to avoid cycles
2012-07-30 07:20:58 -07:00
mChannel = nullptr ;
mCORSPreflightChannel = nullptr ;
2007-03-22 10:30:00 -07:00
return rv ;
}
2012-02-16 08:45:25 -08:00
// Either AsyncOpen was called, or CORS will open the channel later.
mWaitingForOnStopRequest = true ;
2007-03-22 10:30:00 -07:00
// 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 ;
2012-03-12 17:56:07 -07:00
if ( GetOwner ( ) ) {
2009-02-17 12:07:39 -08:00
nsCOMPtr < nsIDOMWindow > topWindow ;
2012-03-12 17:56:07 -07:00
if ( NS_SUCCEEDED ( GetOwner ( ) - > GetTop ( getter_AddRefs ( topWindow ) ) ) ) {
2009-02-17 12:07:39 -08:00
nsCOMPtr < nsPIDOMWindow > suspendedWindow ( do_QueryInterface ( topWindow ) ) ;
2009-03-03 12:11:14 -08:00
if ( suspendedWindow & &
( suspendedWindow = suspendedWindow - > GetCurrentInnerWindow ( ) ) ) {
2013-04-23 21:22:37 -07:00
suspendedDoc = suspendedWindow - > GetExtantDoc ( ) ;
2009-03-03 12:11:14 -08:00
if ( suspendedDoc ) {
suspendedDoc - > SuppressEventHandling ( ) ;
}
2011-10-17 07:59:28 -07:00
suspendedWindow - > SuspendTimeouts ( 1 , false ) ;
2009-03-03 12:11:14 -08:00
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 ) ;
2012-03-31 09:30:13 -07:00
{
nsAutoSyncOperation sync ( suspendedDoc ) ;
// Note, calling ChangeState may have cleared
// XML_HTTP_REQUEST_SYNCLOOPING flag.
nsIThread * thread = NS_GetCurrentThread ( ) ;
while ( mState & XML_HTTP_REQUEST_SYNCLOOPING ) {
if ( ! NS_ProcessNextEvent ( thread ) ) {
rv = NS_ERROR_UNEXPECTED ;
break ;
}
2007-03-22 10:30:00 -07:00
}
}
2009-02-17 12:07:39 -08:00
2009-03-03 12:11:14 -08:00
if ( suspendedDoc ) {
2011-10-17 07:59:28 -07:00
suspendedDoc - > UnsuppressEventHandlingAndFireEvents ( 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 ) ;
2012-10-28 21:33:51 -07:00
if ( mUpload & & mUpload - > HasListenersFor ( nsGkAtoms : : onprogress ) ) {
2008-10-19 14:26:37 -07:00
StartProgressEventTimer ( ) ;
}
2011-10-17 07:59:28 -07:00
DispatchProgressEvent ( this , NS_LITERAL_STRING ( LOADSTART_STR ) , false ,
2008-08-14 04:07:46 -07:00
0 , 0 ) ;
if ( mUpload & & ! mUploadComplete ) {
2011-10-17 07:59:28 -07:00
DispatchProgressEvent ( mUpload , NS_LITERAL_STRING ( LOADSTART_STR ) , true ,
2008-08-14 04:07:46 -07:00
0 , mUploadTotal ) ;
}
2007-03-22 10:30:00 -07:00
}
if ( ! mChannel ) {
return NS_ERROR_FAILURE ;
}
return rv ;
}
2013-06-12 22:20:10 -07:00
/* void setRequestHeader (in ByteString header, in ByteString value); */
2012-08-04 00:44:01 -07:00
// http://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-setrequestheader
2007-03-22 10:30:00 -07:00
NS_IMETHODIMP
nsXMLHttpRequest : : SetRequestHeader ( const nsACString & header ,
const nsACString & value )
{
2012-08-04 00:44:01 -07:00
// Step 1 and 2
if ( ! ( mState & XML_HTTP_REQUEST_OPENED ) ) {
return NS_ERROR_DOM_INVALID_STATE_ERR ;
}
NS_ASSERTION ( mChannel , " mChannel must be valid if we're OPENED. " ) ;
2007-07-26 19:49:18 -07:00
2012-08-04 00:44:01 -07:00
// Step 3
2011-03-28 13:18:45 -07:00
// Make sure we don't store an invalid header name in mCORSUnsafeHeaders
2012-08-04 00:44:01 -07:00
if ( ! IsValidHTTPToken ( header ) ) { // XXX nsHttp::IsValidToken?
return NS_ERROR_DOM_SYNTAX_ERR ;
2008-09-30 17:50:42 -07:00
}
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 ) {
2011-09-28 23:19:26 -07:00
bool pending ;
2012-08-04 00:44:01 -07:00
nsresult 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()
2012-08-04 00:44:01 -07:00
nsCOMPtr < nsIHttpChannel > httpChannel = do_QueryInterface ( mChannel ) ;
2007-07-30 17:42:16 -07:00
if ( ! httpChannel ) {
return NS_OK ;
}
2013-02-03 16:56:09 -08:00
// We will merge XHR headers, per the spec (secion 4.6.2) unless:
// 1 - The caller is privileged and setting an invalid header,
// or
// 2 - we have not yet explicitly set that header; this allows web
// content to override default headers the first time they set them.
bool mergeHeaders = true ;
2007-03-22 10:30:00 -07:00
// Prevent modification to certain HTTP headers (see bug 302263), unless
2012-10-21 23:29:55 -07:00
// the executing script is privileged.
2013-02-03 16:56:09 -08:00
bool isInvalidHeader = false ;
2013-07-03 14:04:43 -07:00
static const char * kInvalidHeaders [ ] = {
2013-02-03 16:56:09 -08:00
" accept-charset " , " accept-encoding " , " access-control-request-headers " ,
" access-control-request-method " , " connection " , " content-length " ,
" cookie " , " cookie2 " , " content-transfer-encoding " , " date " , " dnt " ,
" expect " , " host " , " keep-alive " , " origin " , " referer " , " te " , " trailer " ,
" transfer-encoding " , " upgrade " , " user-agent " , " via "
} ;
uint32_t i ;
for ( i = 0 ; i < ArrayLength ( kInvalidHeaders ) ; + + i ) {
if ( header . LowerCaseEqualsASCII ( kInvalidHeaders [ i ] ) ) {
isInvalidHeader = true ;
break ;
}
}
2007-03-22 10:30:00 -07:00
2013-07-03 14:04:43 -07:00
if ( ! IsSystemXHR ( ) ) {
2012-08-04 00:44:01 -07:00
// Step 5: Check for dangerous headers.
2013-02-03 16:56:09 -08:00
if ( isInvalidHeader ) {
NS_WARNING ( " refusing to set request header " ) ;
return NS_OK ;
2007-03-22 10:30:00 -07:00
}
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
} ;
2011-10-10 22:50:08 -07:00
for ( i = 0 ; i < ArrayLength ( kCrossOriginSafeHeaders ) ; + + i ) {
2008-09-30 17:49:30 -07:00
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 ) {
2012-09-05 22:28:12 -07:00
if ( ! mCORSUnsafeHeaders . Contains ( header ) ) {
mCORSUnsafeHeaders . AppendElement ( header ) ;
}
2008-09-30 17:49:30 -07:00
}
2013-02-03 16:56:09 -08:00
} else {
// Case 1 above
if ( isInvalidHeader ) {
mergeHeaders = false ;
}
2007-03-22 10:30:00 -07:00
}
2013-02-03 16:56:09 -08:00
if ( ! mAlreadySetHeaders . Contains ( header ) ) {
// Case 2 above
mergeHeaders = false ;
}
// Merge headers depending on what we decided above.
nsresult rv = httpChannel - > SetRequestHeader ( header , value , mergeHeaders ) ;
2012-08-04 00:44:01 -07:00
if ( rv = = NS_ERROR_INVALID_ARG ) {
return NS_ERROR_DOM_SYNTAX_ERR ;
}
2010-03-21 18:52:35 -07:00
if ( NS_SUCCEEDED ( rv ) ) {
2013-02-03 16:56:09 -08:00
// Remember that we've set this header, so subsequent set operations will merge values.
mAlreadySetHeaders . PutEntry ( nsCString ( header ) ) ;
2010-03-21 18:52:35 -07:00
// We'll want to duplicate this header for any replacement channels (eg. on redirect)
RequestHeader reqHeader = {
nsCString ( header ) , nsCString ( value )
} ;
mModifiedRequestHeaders . AppendElement ( reqHeader ) ;
}
return rv ;
2007-03-22 10:30:00 -07:00
}
2012-01-26 02:02:22 -08:00
/* attribute unsigned long timeout; */
NS_IMETHODIMP
2012-08-22 08:56:38 -07:00
nsXMLHttpRequest : : GetTimeout ( uint32_t * aTimeout )
2012-01-26 02:02:22 -08:00
{
2012-09-11 12:08:24 -07:00
* aTimeout = Timeout ( ) ;
2012-01-26 02:02:22 -08:00
return NS_OK ;
}
2012-03-26 08:38:06 -07:00
2012-01-26 02:02:22 -08:00
NS_IMETHODIMP
2012-08-22 08:56:38 -07:00
nsXMLHttpRequest : : SetTimeout ( uint32_t aTimeout )
2012-01-26 02:02:22 -08:00
{
2012-05-05 18:15:11 -07:00
ErrorResult rv ;
2012-03-26 08:38:06 -07:00
SetTimeout ( aTimeout , rv ) ;
2012-05-05 18:15:11 -07:00
return rv . ErrorCode ( ) ;
2012-03-26 08:38:06 -07:00
}
void
2012-05-05 18:15:11 -07:00
nsXMLHttpRequest : : SetTimeout ( uint32_t aTimeout , ErrorResult & aRv )
2012-03-26 08:38:06 -07:00
{
if ( ! ( mState & ( XML_HTTP_REQUEST_ASYNC | XML_HTTP_REQUEST_UNSENT ) ) & &
HasOrHasHadOwner ( ) ) {
/* Timeout is not supported for synchronous requests with an owning window,
per XHR2 spec . */
LogMessage ( " TimeoutSyncXHRWarning " , GetOwner ( ) ) ;
2012-05-05 18:15:11 -07:00
aRv . Throw ( NS_ERROR_DOM_INVALID_ACCESS_ERR ) ;
2012-03-26 08:38:06 -07:00
return ;
2012-01-26 02:02:22 -08:00
}
2012-03-26 08:38:06 -07:00
mTimeoutMilliseconds = aTimeout ;
if ( mRequestSentTime ) {
StartTimeoutTimer ( ) ;
}
2012-01-26 02:02:22 -08:00
}
void
nsXMLHttpRequest : : StartTimeoutTimer ( )
{
NS_ABORT_IF_FALSE ( mRequestSentTime ,
" StartTimeoutTimer mustn't be called before the request was sent! " ) ;
if ( mState & XML_HTTP_REQUEST_DONE ) {
// do nothing!
return ;
}
if ( mTimeoutTimer ) {
mTimeoutTimer - > Cancel ( ) ;
}
if ( ! mTimeoutMilliseconds ) {
return ;
}
if ( ! mTimeoutTimer ) {
mTimeoutTimer = do_CreateInstance ( NS_TIMER_CONTRACTID ) ;
}
2012-08-22 08:56:38 -07:00
uint32_t elapsed =
( uint32_t ) ( ( PR_Now ( ) - mRequestSentTime ) / PR_USEC_PER_MSEC ) ;
2012-01-26 02:02:22 -08:00
mTimeoutTimer - > InitWithCallback (
this ,
mTimeoutMilliseconds > elapsed ? mTimeoutMilliseconds - elapsed : 0 ,
nsITimer : : TYPE_ONE_SHOT
) ;
}
2012-03-26 08:38:06 -07:00
/* readonly attribute unsigned short readyState; */
2007-03-22 10:30:00 -07:00
NS_IMETHODIMP
2012-08-22 08:56:38 -07:00
nsXMLHttpRequest : : GetReadyState ( uint16_t * aState )
2007-03-22 10:30:00 -07:00
{
2012-09-11 12:08:24 -07:00
* aState = ReadyState ( ) ;
2012-03-26 08:38:06 -07:00
return NS_OK ;
}
uint16_t
2012-09-11 12:08:24 -07:00
nsXMLHttpRequest : : ReadyState ( )
2012-03-26 08:38:06 -07:00
{
2007-03-22 10:30:00 -07:00
// Translate some of our internal states for external consumers
2011-05-10 16:18:55 -07:00
if ( mState & XML_HTTP_REQUEST_UNSENT ) {
2012-03-26 08:38:06 -07:00
return UNSENT ;
2007-03-22 10:30:00 -07:00
}
2012-03-26 08:38:06 -07:00
if ( mState & ( XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT ) ) {
return OPENED ;
}
if ( mState & XML_HTTP_REQUEST_HEADERS_RECEIVED ) {
return HEADERS_RECEIVED ;
}
2012-11-21 22:25:01 -08:00
if ( mState & XML_HTTP_REQUEST_LOADING ) {
2012-03-26 08:38:06 -07:00
return LOADING ;
}
MOZ_ASSERT ( mState & XML_HTTP_REQUEST_DONE ) ;
return DONE ;
2007-03-22 10:30:00 -07:00
}
2012-03-26 08:38:06 -07:00
/* void overrideMimeType(in DOMString mimetype); */
2007-03-22 10:30:00 -07:00
NS_IMETHODIMP
2012-03-26 08:38:06 -07:00
nsXMLHttpRequest : : SlowOverrideMimeType ( const nsAString & aMimeType )
2007-03-22 10:30:00 -07:00
{
2012-03-26 08:38:06 -07:00
OverrideMimeType ( aMimeType ) ;
2007-03-22 10:30:00 -07:00
return NS_OK ;
}
2008-03-18 17:14:38 -07:00
/* attribute boolean mozBackgroundRequest; */
NS_IMETHODIMP
2011-09-28 23:19:26 -07:00
nsXMLHttpRequest : : GetMozBackgroundRequest ( bool * _retval )
2008-03-18 17:14:38 -07:00
{
2012-09-11 12:08:24 -07:00
* _retval = MozBackgroundRequest ( ) ;
2008-03-18 17:14:38 -07:00
return NS_OK ;
}
2012-03-26 08:38:06 -07:00
bool
2012-09-11 12:08:24 -07:00
nsXMLHttpRequest : : MozBackgroundRequest ( )
2012-03-26 08:38:06 -07:00
{
return ! ! ( mState & XML_HTTP_REQUEST_BACKGROUND ) ;
}
2008-03-18 17:14:38 -07:00
NS_IMETHODIMP
2011-09-28 23:19:26 -07:00
nsXMLHttpRequest : : SetMozBackgroundRequest ( bool aMozBackgroundRequest )
2008-03-18 17:14:38 -07:00
{
2012-03-26 08:38:06 -07:00
nsresult rv = NS_OK ;
SetMozBackgroundRequest ( aMozBackgroundRequest , rv ) ;
return rv ;
}
2008-03-18 17:14:38 -07:00
2012-03-26 08:38:06 -07:00
void
nsXMLHttpRequest : : SetMozBackgroundRequest ( bool aMozBackgroundRequest , nsresult & aRv )
{
2013-07-03 14:04:43 -07:00
if ( ! IsSystemXHR ( ) ) {
2012-03-26 08:38:06 -07:00
aRv = NS_ERROR_DOM_SECURITY_ERR ;
return ;
}
2008-03-18 17:14:38 -07:00
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.
2012-03-26 08:38:06 -07:00
aRv = NS_ERROR_IN_PROGRESS ;
return ;
2008-03-18 17:14:38 -07:00
}
if ( aMozBackgroundRequest ) {
mState | = XML_HTTP_REQUEST_BACKGROUND ;
} else {
mState & = ~ XML_HTTP_REQUEST_BACKGROUND ;
}
}
2008-09-30 17:52:52 -07:00
/* attribute boolean withCredentials; */
NS_IMETHODIMP
2011-09-28 23:19:26 -07:00
nsXMLHttpRequest : : GetWithCredentials ( bool * _retval )
2008-09-30 17:52:52 -07:00
{
2012-09-11 12:08:24 -07:00
* _retval = WithCredentials ( ) ;
2008-09-30 17:52:52 -07:00
return NS_OK ;
}
2012-03-26 08:38:06 -07:00
bool
2012-09-11 12:08:24 -07:00
nsXMLHttpRequest : : WithCredentials ( )
2012-03-26 08:38:06 -07:00
{
return ! ! ( mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS ) ;
}
2008-09-30 17:52:52 -07:00
NS_IMETHODIMP
2011-09-28 23:19:26 -07:00
nsXMLHttpRequest : : SetWithCredentials ( bool aWithCredentials )
2012-03-26 08:38:06 -07:00
{
2012-11-27 12:20:40 -08:00
ErrorResult rv ;
2012-03-26 08:38:06 -07:00
SetWithCredentials ( aWithCredentials , rv ) ;
2012-11-27 12:20:40 -08:00
return rv . ErrorCode ( ) ;
2012-03-26 08:38:06 -07:00
}
void
2012-11-27 12:20:40 -08:00
nsXMLHttpRequest : : SetWithCredentials ( bool aWithCredentials , ErrorResult & aRv )
2008-09-30 17:52:52 -07:00
{
// Return error if we're already processing a request
if ( XML_HTTP_REQUEST_SENT & mState ) {
2012-03-26 08:38:06 -07:00
aRv = NS_ERROR_FAILURE ;
return ;
2008-09-30 17:52:52 -07:00
}
2011-12-08 05:54:05 -08:00
// sync request is not allowed setting withCredentials in window context
2012-03-12 17:56:07 -07:00
if ( HasOrHasHadOwner ( ) & &
2011-12-08 05:54:05 -08:00
! ( mState & ( XML_HTTP_REQUEST_UNSENT | XML_HTTP_REQUEST_ASYNC ) ) ) {
2012-03-12 17:56:07 -07:00
LogMessage ( " WithCredentialsSyncXHRWarning " , GetOwner ( ) ) ;
2012-11-27 12:20:40 -08:00
aRv . Throw ( NS_ERROR_DOM_INVALID_ACCESS_ERR ) ;
2012-03-26 08:38:06 -07:00
return ;
2011-12-08 05:54:05 -08:00
}
2008-09-30 17:52:52 -07:00
if ( aWithCredentials ) {
mState | = XML_HTTP_REQUEST_AC_WITH_CREDENTIALS ;
2012-03-26 08:38:06 -07:00
} else {
2008-09-30 17:52:52 -07:00
mState & = ~ XML_HTTP_REQUEST_AC_WITH_CREDENTIALS ;
}
}
2007-03-22 10:30:00 -07:00
nsresult
2012-08-22 08:56:38 -07:00
nsXMLHttpRequest : : ChangeState ( uint32_t aState , bool 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 ) ) ) {
2012-01-26 02:02:22 -08:00
mProgressTimerIsActive = false ;
2008-10-19 14:26:37 -07:00
mProgressNotifier - > Cancel ( ) ;
}
2012-11-21 22:25:01 -08:00
if ( ( aState & XML_HTTP_REQUEST_LOADSTATES ) & & // Broadcast load states only
aState ! = XML_HTTP_REQUEST_SENT & & // And not internal ones
2010-09-17 02:30:35 -07:00
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 ) ;
2012-07-30 07:20:58 -07:00
DispatchDOMEvent ( nullptr , event , nullptr , nullptr ) ;
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 .
*/
2012-06-18 19:30:09 -07:00
class AsyncVerifyRedirectCallbackForwarder MOZ_FINAL : public nsIAsyncVerifyRedirectCallback
2010-08-04 19:15:55 -07:00
{
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 ;
} ;
2013-01-12 04:40:33 -08:00
NS_IMPL_CYCLE_COLLECTION_1 ( AsyncVerifyRedirectCallbackForwarder , mXHR )
2010-08-04 19:15:55 -07:00
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 ,
2012-08-22 08:56:38 -07:00
uint32_t aFlags ,
2010-08-04 19:15:55 -07:00
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 ) ) {
2012-07-30 07:20:58 -07:00
mRedirectCallback = nullptr ;
mNewRedirectChannel = nullptr ;
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-03-21 18:52:35 -07:00
if ( NS_SUCCEEDED ( result ) ) {
2010-08-04 19:15:55 -07:00
mChannel = mNewRedirectChannel ;
2010-03-21 18:52:35 -07:00
nsCOMPtr < nsIHttpChannel > httpChannel ( do_QueryInterface ( mChannel ) ) ;
if ( httpChannel ) {
// Ensure all original headers are duplicated for the new channel (bug #553888)
2012-08-22 08:56:38 -07:00
for ( uint32_t i = mModifiedRequestHeaders . Length ( ) ; i > 0 ; ) {
2010-03-21 18:52:35 -07:00
- - i ;
httpChannel - > SetRequestHeader ( mModifiedRequestHeaders [ i ] . header ,
mModifiedRequestHeaders [ i ] . value ,
2011-10-17 07:59:28 -07:00
false ) ;
2010-03-21 18:52:35 -07:00
}
}
} else {
2011-10-17 07:59:28 -07:00
mErrorLoad = true ;
2010-03-21 18:52:35 -07:00
}
2010-08-04 19:15:55 -07:00
2012-07-30 07:20:58 -07:00
mNewRedirectChannel = nullptr ;
2010-08-04 19:15:55 -07:00
mRedirectCallback - > OnRedirectVerifyCallback ( result ) ;
2012-07-30 07:20:58 -07:00
mRedirectCallback = nullptr ;
2007-03-22 10:30:00 -07:00
}
/////////////////////////////////////////////////////
// nsIProgressEventSink methods:
//
2011-09-23 18:57:22 -07:00
void
2011-09-28 23:19:26 -07:00
nsXMLHttpRequest : : MaybeDispatchProgressEvents ( bool aFinalProgress )
2011-09-23 18:57:22 -07:00
{
2012-01-26 02:02:22 -08:00
if ( aFinalProgress & & mProgressTimerIsActive ) {
mProgressTimerIsActive = false ;
2011-09-23 18:57:22 -07:00
mProgressNotifier - > Cancel ( ) ;
}
2012-01-26 02:02:22 -08:00
if ( mProgressTimerIsActive | |
2011-09-23 18:57:22 -07:00
! mProgressSinceLastProgressEvent | |
mErrorLoad | |
! ( mState & XML_HTTP_REQUEST_ASYNC ) ) {
return ;
}
if ( ! aFinalProgress ) {
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 ) {
if ( aFinalProgress ) {
mUploadTotal = mUploadTransferred ;
}
if ( mUpload & & ! mUploadComplete ) {
DispatchProgressEvent ( mUpload , NS_LITERAL_STRING ( PROGRESS_STR ) ,
2013-02-28 10:53:04 -08:00
mUploadLengthComputable , mUploadTransferred ,
mUploadTotal ) ;
2011-09-23 18:57:22 -07:00
}
} else {
if ( aFinalProgress ) {
mLoadTotal = mLoadTransferred ;
}
2011-11-24 07:28:12 -08:00
mInLoadProgressEvent = true ;
DispatchProgressEvent ( this , NS_LITERAL_STRING ( PROGRESS_STR ) ,
2013-02-28 10:53:04 -08:00
mLoadLengthComputable , mLoadTransferred ,
mLoadTotal ) ;
2011-11-24 07:28:12 -08:00
mInLoadProgressEvent = false ;
2011-09-23 18:57:36 -07:00
if ( mResponseType = = XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT | |
mResponseType = = XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER ) {
mResponseBody . Truncate ( ) ;
mResponseText . Truncate ( ) ;
2012-07-30 07:20:58 -07:00
mResultArrayBuffer = nullptr ;
2013-05-23 19:09:38 -07:00
mArrayBufferBuilder . reset ( ) ;
2011-09-23 18:57:36 -07:00
}
2011-09-23 18:57:22 -07:00
}
2011-10-17 07:59:28 -07:00
mProgressSinceLastProgressEvent = false ;
2011-09-23 18:57:22 -07:00
}
2007-03-22 10:30:00 -07:00
NS_IMETHODIMP
2012-08-22 08:56:38 -07:00
nsXMLHttpRequest : : OnProgress ( nsIRequest * aRequest , nsISupports * aContext , uint64_t aProgress , uint64_t aProgressMax )
2007-03-22 10:30:00 -07:00
{
// We're uploading if our state is XML_HTTP_REQUEST_OPENED or
// XML_HTTP_REQUEST_SENT
2011-09-28 23:19:26 -07:00
bool upload = ! ! ( ( XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT ) & mState ) ;
2008-08-14 04:07:46 -07:00
// When uploading, OnProgress reports also headers in aProgress and aProgressMax.
// So, try to remove the headers, if possible.
2012-09-28 12:55:23 -07:00
bool lengthComputable = ( aProgressMax ! = UINT64_MAX ) ;
2008-08-14 04:07:46 -07:00
if ( upload ) {
2012-08-22 08:56:38 -07:00
uint64_t loaded = aProgress ;
uint64_t total = aProgressMax ;
2011-09-23 18:57:22 -07:00
if ( lengthComputable ) {
2012-08-22 08:56:38 -07:00
uint64_t headerSize = aProgressMax - mUploadTotal ;
2008-08-14 04:07:46 -07:00
loaded - = headerSize ;
total - = headerSize ;
}
2011-09-23 18:57:22 -07:00
mUploadLengthComputable = lengthComputable ;
2008-08-14 04:07:46 -07:00
mUploadTransferred = loaded ;
2011-10-17 07:59:28 -07:00
mProgressSinceLastProgressEvent = true ;
2011-09-23 18:57:22 -07:00
2011-10-17 07:59:28 -07:00
MaybeDispatchProgressEvents ( false ) ;
2008-10-19 14:26:37 -07:00
} else {
mLoadLengthComputable = lengthComputable ;
2011-09-23 18:57:22 -07:00
mLoadTotal = lengthComputable ? aProgressMax : 0 ;
// Don't dispatch progress events here. OnDataAvailable will take care
// of that.
2008-08-14 04:07:46 -07:00
}
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 ;
}
2011-09-28 23:19:26 -07:00
bool
2008-09-30 17:51:53 -07:00
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 ) ;
2012-09-07 07:51:35 -07:00
* aResult = static_cast < nsIChannelEventSink * > ( EnsureXPCOMifier ( ) . get ( ) ) ;
2007-03-22 10:30:00 -07:00
return NS_OK ;
} else if ( aIID . Equals ( NS_GET_IID ( nsIProgressEventSink ) ) ) {
mProgressEventSink = do_GetInterface ( mNotificationCallbacks ) ;
2012-09-07 07:51:35 -07:00
* aResult = static_cast < nsIProgressEventSink * > ( EnsureXPCOMifier ( ) . get ( ) ) ;
2007-03-22 10:30:00 -07:00
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 ) ) ) {
2012-10-07 04:40:10 -07:00
nsCOMPtr < nsIURI > uri ;
rv = mChannel - > GetURI ( getter_AddRefs ( uri ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
// Verify that it's ok to prompt for credentials here, per spec
// http://xhr.spec.whatwg.org/#the-send%28%29-method
bool showPrompt = true ;
// If authentication fails, XMLHttpRequest origin and
// the request URL are same origin, ...
2012-10-11 10:45:37 -07:00
/* Disabled - bug: 799540
2012-10-07 04:40:10 -07:00
if ( mState & XML_HTTP_REQUEST_USE_XSITE_AC ) {
showPrompt = false ;
}
2012-10-11 10:45:37 -07:00
*/
2012-10-07 04:40:10 -07:00
// ... Authorization is not in the list of author request headers, ...
if ( showPrompt ) {
for ( uint32_t i = 0 , len = mModifiedRequestHeaders . Length ( ) ; i < len ; + + i ) {
if ( mModifiedRequestHeaders [ i ] . header .
LowerCaseEqualsLiteral ( " authorization " ) ) {
showPrompt = false ;
break ;
}
}
}
// ... request username is null, and request password is null,
if ( showPrompt ) {
nsCString username ;
rv = uri - > GetUsername ( username ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
nsCString password ;
rv = uri - > GetPassword ( password ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
if ( ! username . IsEmpty ( ) | | ! password . IsEmpty ( ) ) {
showPrompt = false ;
}
}
// ... user agents should prompt the end user for their username and password.
if ( ! showPrompt ) {
nsRefPtr < XMLHttpRequestAuthPrompt > prompt = new XMLHttpRequestAuthPrompt ( ) ;
if ( ! prompt )
return NS_ERROR_OUT_OF_MEMORY ;
return prompt - > QueryInterface ( aIID , aResult ) ;
}
2008-04-08 17:27:50 -07:00
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 ;
2012-03-12 17:56:07 -07:00
if ( GetOwner ( ) ) {
window = GetOwner ( ) - > GetOuterWindow ( ) ;
2008-04-08 17:27:50 -07:00
}
return wwatch - > GetPrompt ( window , aIID ,
reinterpret_cast < void * * > ( aResult ) ) ;
2012-09-07 07:51:35 -07:00
}
// Now check for the various XHR non-DOM interfaces, except
// nsIProgressEventSink and nsIChannelEventSink which we already
// handled above.
else if ( aIID . Equals ( NS_GET_IID ( nsIStreamListener ) ) ) {
* aResult = static_cast < nsIStreamListener * > ( EnsureXPCOMifier ( ) . get ( ) ) ;
return NS_OK ;
}
else if ( aIID . Equals ( NS_GET_IID ( nsIRequestObserver ) ) ) {
* aResult = static_cast < nsIRequestObserver * > ( EnsureXPCOMifier ( ) . get ( ) ) ;
return NS_OK ;
}
else if ( aIID . Equals ( NS_GET_IID ( nsITimerCallback ) ) ) {
* aResult = static_cast < nsITimerCallback * > ( EnsureXPCOMifier ( ) . get ( ) ) ;
return NS_OK ;
2008-04-08 17:27:50 -07:00
}
2008-03-18 17:14:38 -07:00
2007-03-22 10:30:00 -07:00
return QueryInterface ( aIID , aResult ) ;
}
2012-03-30 21:42:20 -07:00
JS : : Value
2012-10-15 20:12:03 -07:00
nsXMLHttpRequest : : GetInterface ( JSContext * aCx , nsIJSID * aIID , ErrorResult & aRv )
2012-03-30 21:42:20 -07:00
{
const nsID * iid = aIID - > GetID ( ) ;
nsCOMPtr < nsISupports > result ;
2013-05-02 02:12:47 -07:00
JS : : Rooted < JS : : Value > v ( aCx , JSVAL_NULL ) ;
2012-03-30 21:42:20 -07:00
aRv = GetInterface ( * iid , getter_AddRefs ( result ) ) ;
2012-05-05 18:15:11 -07:00
NS_ENSURE_FALSE ( aRv . Failed ( ) , JSVAL_NULL ) ;
2012-03-30 21:42:20 -07:00
2013-05-02 02:12:45 -07:00
JS : : Rooted < JSObject * > wrapper ( aCx , GetWrapper ( ) ) ;
2013-01-17 16:30:41 -08:00
JSAutoCompartment ac ( aCx , wrapper ) ;
2013-05-02 02:12:46 -07:00
JS : : Rooted < JSObject * > global ( aCx , JS_GetGlobalForObject ( aCx , wrapper ) ) ;
2013-05-02 02:12:47 -07:00
aRv = nsContentUtils : : WrapNative ( aCx , global , result , iid , v . address ( ) ) ;
2012-05-05 18:15:11 -07:00
return aRv . Failed ( ) ? JSVAL_NULL : v ;
2012-03-30 21:42:20 -07:00
}
2012-03-26 08:38:06 -07:00
nsXMLHttpRequestUpload *
2012-09-11 12:08:24 -07:00
nsXMLHttpRequest : : Upload ( )
2008-08-14 04:04:43 -07:00
{
2008-08-14 04:07:46 -07:00
if ( ! mUpload ) {
2012-03-12 17:56:07 -07:00
mUpload = new nsXMLHttpRequestUpload ( this ) ;
2008-08-14 04:04:43 -07:00
}
2012-03-26 08:38:06 -07:00
return mUpload ;
}
NS_IMETHODIMP
nsXMLHttpRequest : : GetUpload ( nsIXMLHttpRequestUpload * * aUpload )
{
2012-09-11 12:08:24 -07:00
nsRefPtr < nsXMLHttpRequestUpload > upload = Upload ( ) ;
2012-03-26 08:38:06 -07:00
upload . forget ( aUpload ) ;
2008-08-14 04:04:43 -07:00
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
2012-06-07 11:28:33 -07:00
bool
2012-09-11 12:08:24 -07:00
nsXMLHttpRequest : : MozAnon ( )
2012-06-07 11:28:33 -07:00
{
return mIsAnon ;
}
NS_IMETHODIMP
nsXMLHttpRequest : : GetMozAnon ( bool * aAnon )
{
2012-09-11 12:08:24 -07:00
* aAnon = MozAnon ( ) ;
2012-06-07 11:28:33 -07:00
return NS_OK ;
}
bool
2012-09-11 12:08:24 -07:00
nsXMLHttpRequest : : MozSystem ( )
2012-06-07 11:28:33 -07:00
{
return IsSystemXHR ( ) ;
}
NS_IMETHODIMP
nsXMLHttpRequest : : GetMozSystem ( bool * aSystem )
{
2012-09-11 12:08:24 -07:00
* aSystem = MozSystem ( ) ;
2012-06-07 11:28:33 -07:00
return NS_OK ;
}
2012-01-26 02:02:22 -08:00
void
nsXMLHttpRequest : : HandleTimeoutCallback ( )
{
if ( mState & XML_HTTP_REQUEST_DONE ) {
NS_NOTREACHED ( " nsXMLHttpRequest::HandleTimeoutCallback with completed request " ) ;
// do nothing!
return ;
}
CloseRequestWithError ( NS_LITERAL_STRING ( TIMEOUT_STR ) ,
XML_HTTP_REQUEST_TIMED_OUT ) ;
}
2008-10-19 14:26:37 -07:00
NS_IMETHODIMP
nsXMLHttpRequest : : Notify ( nsITimer * aTimer )
{
2012-01-26 02:02:22 -08:00
if ( mProgressNotifier = = aTimer ) {
HandleProgressTimerCallback ( ) ;
return NS_OK ;
}
if ( mTimeoutTimer = = aTimer ) {
HandleTimeoutCallback ( ) ;
return NS_OK ;
}
// Just in case some JS user wants to QI to nsITimerCallback and play with us...
NS_WARNING ( " Unexpected timer! " ) ;
return NS_ERROR_INVALID_POINTER ;
}
void
nsXMLHttpRequest : : HandleProgressTimerCallback ( )
{
mProgressTimerIsActive = false ;
2013-03-04 01:06:15 -08:00
MaybeDispatchProgressEvents ( false ) ;
2008-10-19 14:26:37 -07:00
}
void
nsXMLHttpRequest : : StartProgressEventTimer ( )
{
if ( ! mProgressNotifier ) {
mProgressNotifier = do_CreateInstance ( NS_TIMER_CONTRACTID ) ;
}
if ( mProgressNotifier ) {
2012-01-26 02:02:22 -08:00
mProgressTimerIsActive = true ;
2008-10-19 14:26:37 -07:00
mProgressNotifier - > Cancel ( ) ;
mProgressNotifier - > InitWithCallback ( this , NS_PROGRESS_EVENT_INTERVAL ,
nsITimer : : TYPE_ONE_SHOT ) ;
}
}
2012-09-07 07:51:35 -07:00
already_AddRefed < nsXMLHttpRequestXPCOMifier >
nsXMLHttpRequest : : EnsureXPCOMifier ( )
{
if ( ! mXPCOMifier ) {
mXPCOMifier = new nsXMLHttpRequestXPCOMifier ( this ) ;
}
nsRefPtr < nsXMLHttpRequestXPCOMifier > newRef ( mXPCOMifier ) ;
return newRef . forget ( ) ;
}
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 )
{
2013-01-10 14:47:43 -08:00
if ( mXHR - > IsSafeHeader ( header , mHttpChannel ) ) {
mHeaders . Append ( header ) ;
mHeaders . Append ( " : " ) ;
mHeaders . Append ( value ) ;
mHeaders . Append ( " \r \n " ) ;
}
return NS_OK ;
2007-03-22 10:30:00 -07:00
}
2012-09-07 07:51:35 -07:00
// nsXMLHttpRequestXPCOMifier implementation
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION ( nsXMLHttpRequestXPCOMifier )
NS_INTERFACE_MAP_ENTRY ( nsIStreamListener )
NS_INTERFACE_MAP_ENTRY ( nsIRequestObserver )
NS_INTERFACE_MAP_ENTRY ( nsIChannelEventSink )
NS_INTERFACE_MAP_ENTRY ( nsIProgressEventSink )
NS_INTERFACE_MAP_ENTRY ( nsIInterfaceRequestor )
NS_INTERFACE_MAP_ENTRY ( nsITimerCallback )
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS ( nsISupports , nsIStreamListener )
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF ( nsXMLHttpRequestXPCOMifier )
NS_IMPL_CYCLE_COLLECTING_RELEASE ( nsXMLHttpRequestXPCOMifier )
// Can't NS_IMPL_CYCLE_COLLECTION_1 because mXHR has ambiguous
// inheritance from nsISupports.
2013-08-01 18:29:05 -07:00
NS_IMPL_CYCLE_COLLECTION_CLASS ( nsXMLHttpRequestXPCOMifier )
2012-09-07 07:51:35 -07:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN ( nsXMLHttpRequestXPCOMifier )
if ( tmp - > mXHR ) {
tmp - > mXHR - > mXPCOMifier = nullptr ;
}
2012-11-14 23:32:40 -08:00
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mXHR )
2012-09-07 07:51:35 -07:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN ( nsXMLHttpRequestXPCOMifier )
2012-11-14 23:32:40 -08:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mXHR )
2012-09-07 07:51:35 -07:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMETHODIMP
nsXMLHttpRequestXPCOMifier : : GetInterface ( const nsIID & aIID , void * * aResult )
{
// Return ourselves for the things we implement (except
// nsIInterfaceRequestor) and the XHR for the rest.
if ( ! aIID . Equals ( NS_GET_IID ( nsIInterfaceRequestor ) ) ) {
nsresult rv = QueryInterface ( aIID , aResult ) ;
if ( NS_SUCCEEDED ( rv ) ) {
return rv ;
}
}
return mXHR - > GetInterface ( aIID , aResult ) ;
}
2013-08-27 16:55:31 -07:00
namespace mozilla {
ArrayBufferBuilder : : ArrayBufferBuilder ( )
: mRawContents ( nullptr ) ,
mDataPtr ( nullptr ) ,
mCapacity ( 0 ) ,
mLength ( 0 )
{
}
ArrayBufferBuilder : : ~ ArrayBufferBuilder ( )
{
reset ( ) ;
}
void
ArrayBufferBuilder : : reset ( )
{
if ( mRawContents ) {
JS_free ( nullptr , mRawContents ) ;
}
mRawContents = mDataPtr = nullptr ;
mCapacity = mLength = 0 ;
}
bool
ArrayBufferBuilder : : setCapacity ( uint32_t aNewCap )
{
if ( ! JS_ReallocateArrayBufferContents ( nullptr , aNewCap , & mRawContents , & mDataPtr ) ) {
return false ;
}
mCapacity = aNewCap ;
if ( mLength > aNewCap ) {
mLength = aNewCap ;
}
return true ;
}
bool
ArrayBufferBuilder : : append ( const uint8_t * aNewData , uint32_t aDataLen ,
uint32_t aMaxGrowth )
{
if ( mLength + aDataLen > mCapacity ) {
uint32_t newcap ;
// Double while under aMaxGrowth or if not specified.
if ( ! aMaxGrowth | | mCapacity < aMaxGrowth ) {
newcap = mCapacity * 2 ;
} else {
newcap = mCapacity + aMaxGrowth ;
}
// But make sure there's always enough to satisfy our request.
if ( newcap < mLength + aDataLen ) {
newcap = mLength + aDataLen ;
}
// Did we overflow?
if ( newcap < mCapacity ) {
return false ;
}
if ( ! setCapacity ( newcap ) ) {
return false ;
}
}
// Assert that the region isn't overlapping so we can memcpy.
MOZ_ASSERT ( ! areOverlappingRegions ( aNewData , aDataLen , mDataPtr + mLength ,
aDataLen ) ) ;
memcpy ( mDataPtr + mLength , aNewData , aDataLen ) ;
mLength + = aDataLen ;
return true ;
}
JSObject *
ArrayBufferBuilder : : getArrayBuffer ( JSContext * aCx )
{
// we need to check for mLength == 0, because nothing may have been
// added
if ( mCapacity > mLength | | mLength = = 0 ) {
if ( ! setCapacity ( mLength ) ) {
return nullptr ;
}
}
JSObject * obj = JS_NewArrayBufferWithContents ( aCx , mRawContents ) ;
if ( ! obj ) {
return nullptr ;
}
mRawContents = mDataPtr = nullptr ;
mLength = mCapacity = 0 ;
return obj ;
}
/* static */ bool
ArrayBufferBuilder : : areOverlappingRegions ( const uint8_t * aStart1 ,
uint32_t aLength1 ,
const uint8_t * aStart2 ,
uint32_t aLength2 )
{
const uint8_t * end1 = aStart1 + aLength1 ;
const uint8_t * end2 = aStart2 + aLength2 ;
const uint8_t * max_start = aStart1 > aStart2 ? aStart1 : aStart2 ;
const uint8_t * min_end = end1 < end2 ? end1 : end2 ;
return max_start < min_end ;
}
} // namespace mozilla