2013-01-18 09:21:43 +04: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 15:12:37 +04: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/. */
2006-04-20 07:36:50 +04:00
2016-06-27 20:13:41 +03:00
# include "XMLHttpRequestMainThread.h"
2013-08-22 10:29:30 +04:00
2014-05-16 09:34:43 +04:00
# ifndef XP_WIN
# include <unistd.h>
# endif
2013-12-09 06:52:54 +04:00
# include "mozilla/ArrayUtils.h"
2015-05-29 22:46:12 +03:00
# include "mozilla/CheckedInt.h"
2014-10-08 20:15:23 +04:00
# include "mozilla/dom/BlobSet.h"
2014-10-08 20:15:23 +04:00
# include "mozilla/dom/File.h"
2015-09-11 21:26:33 +03:00
# include "mozilla/dom/FetchUtil.h"
2016-01-07 22:30:36 +03:00
# include "mozilla/dom/FormData.h"
2016-07-11 22:03:44 +03:00
# include "mozilla/dom/URLSearchParams.h"
2014-03-18 08:48:21 +04:00
# include "mozilla/EventDispatcher.h"
2014-03-17 10:56:53 +04:00
# include "mozilla/EventListenerManager.h"
2014-07-10 10:56:37 +04:00
# include "mozilla/LoadInfo.h"
2013-06-23 16:03:39 +04:00
# include "mozilla/MemoryReporting.h"
2013-08-22 10:30:55 +04:00
# include "nsIDOMDocument.h"
2014-06-04 02:52:36 +04:00
# include "mozilla/dom/ProgressEvent.h"
2013-08-22 10:29:30 +04:00
# include "nsIJARChannel.h"
2014-05-16 09:34:43 +04:00
# include "nsIJARURI.h"
2006-04-20 07:36:50 +04:00
# include "nsLayoutCID.h"
2006-04-20 07:37:41 +04:00
# include "nsReadableUtils.h"
2013-08-22 10:29:30 +04:00
2006-04-20 07:36:50 +04:00
# include "nsIURI.h"
# include "nsILoadGroup.h"
# include "nsNetUtil.h"
2015-07-07 05:17:00 +03:00
# include "nsStringStream.h"
# include "nsIAuthPrompt.h"
# include "nsIAuthPrompt2.h"
# include "nsIOutputStream.h"
# include "nsISupportsPrimitives.h"
# include "nsIInterfaceRequestorUtils.h"
2009-09-09 03:29:41 +04:00
# include "nsStreamUtils.h"
2006-05-10 21:30:15 +04:00
# include "nsThreadUtils.h"
2006-04-20 07:37:32 +04:00
# include "nsIUploadChannel.h"
2009-09-09 03:29:41 +04:00
# include "nsIUploadChannel2.h"
2006-04-20 07:36:50 +04:00
# include "nsIDOMSerializer.h"
2006-04-20 07:38:11 +04:00
# include "nsXPCOM.h"
2006-04-20 07:36:50 +04:00
# include "nsIDOMEventListener.h"
2006-04-20 07:36:51 +04:00
# include "nsIScriptSecurityManager.h"
2006-04-20 07:37:45 +04:00
# include "nsIVariant.h"
2011-12-24 12:27:04 +04:00
# include "nsVariant.h"
# include "nsIScriptError.h"
2006-04-20 07:38:52 +04:00
# include "nsIStreamConverterService.h"
2006-04-20 07:39:48 +04:00
# include "nsICachingChannel.h"
2006-04-26 13:19:48 +04:00
# include "nsContentUtils.h"
2007-01-05 01:31:26 +03:00
# include "nsCycleCollectionParticipant.h"
2012-07-27 18:03:27 +04:00
# include "nsError.h"
2007-07-27 06:49:18 +04:00
# include "nsIHTMLDocument.h"
2008-03-18 22:49:20 +03:00
# include "nsIStorageStream.h"
2008-04-09 04:27:50 +04:00
# include "nsIPromptFactory.h"
# include "nsIWindowWatcher.h"
2009-11-19 02:21:13 +03:00
# include "nsIConsoleService.h"
2010-04-23 23:54:09 +04:00
# include "nsIContentSecurityPolicy.h"
2010-08-05 06:15:55 +04:00
# include "nsAsyncRedirectVerifyHelper.h"
2010-11-23 19:49:12 +03:00
# include "nsStringBuffer.h"
2011-05-11 03:18:55 +04:00
# include "nsIFileChannel.h"
2011-11-19 22:50:17 +04:00
# include "mozilla/Telemetry.h"
2012-01-14 21:43:00 +04:00
# include "jsfriendapi.h"
2013-03-18 18:25:50 +04:00
# include "GeckoProfiler.h"
2012-11-08 03:04:22 +04:00
# include "mozilla/dom/EncodingUtils.h"
2013-11-26 11:31:52 +04:00
# include "nsIUnicodeDecoder.h"
2012-05-03 08:35:38 +04:00
# include "mozilla/dom/XMLHttpRequestBinding.h"
2012-06-19 06:30:09 +04:00
# include "mozilla/Attributes.h"
2012-08-18 04:42:00 +04:00
# include "nsIPermissionManager.h"
2012-08-28 03:34:30 +04:00
# include "nsMimeTypes.h"
2012-12-05 03:06:29 +04:00
# include "nsIHttpChannelInternal.h"
2014-12-06 22:26:50 +03:00
# include "nsIClassOfService.h"
2013-08-22 13:22:03 +04:00
# include "nsCharSeparatedTokenizer.h"
2012-12-11 22:09:56 +04:00
# include "nsStreamListenerWrapper.h"
2013-09-06 21:50:24 +04:00
# include "xpcjsid.h"
2013-10-16 05:35:44 +04:00
# include "nsITimedChannel.h"
2012-01-26 19:55:30 +04:00
# include "nsWrapperCacheInlines.h"
2014-05-16 09:34:43 +04:00
# include "nsZipArchive.h"
# include "mozilla/Preferences.h"
# include "private/pprio.h"
2016-06-27 20:13:41 +03:00
# include "XMLHttpRequestUpload.h"
2006-05-05 21:01:53 +04:00
2016-06-27 20:13:40 +03:00
using namespace mozilla : : net ;
2011-10-11 09:50:08 +04:00
2016-06-27 20:13:41 +03:00
namespace mozilla {
namespace dom {
2013-04-27 23:25:24 +04: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 22:42:10 +04: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 23:25:24 +04:00
2016-07-08 19:44:33 +03:00
namespace {
const nsLiteralString ProgressEventTypeStrings [ ] = {
NS_LITERAL_STRING ( " loadstart " ) ,
NS_LITERAL_STRING ( " progress " ) ,
NS_LITERAL_STRING ( " error " ) ,
NS_LITERAL_STRING ( " abort " ) ,
NS_LITERAL_STRING ( " timeout " ) ,
NS_LITERAL_STRING ( " load " ) ,
NS_LITERAL_STRING ( " loadend " )
} ;
static_assert ( MOZ_ARRAY_LENGTH ( ProgressEventTypeStrings ) = =
size_t ( XMLHttpRequestMainThread : : ProgressEventType : : ENUM_MAX ) ,
" Mismatched lengths for ProgressEventTypeStrings and ProgressEventType enums " ) ;
const nsString kLiteralString_readystatechange = NS_LITERAL_STRING ( " readystatechange " ) ;
const nsString kLiteralString_xmlhttprequest = NS_LITERAL_STRING ( " xmlhttprequest " ) ;
const nsString kLiteralString_DOMContentLoaded = NS_LITERAL_STRING ( " DOMContentLoaded " ) ;
}
2006-04-20 07:36:50 +04:00
2006-04-20 07:36:54 +04:00
// CIDs
2008-03-19 03:14:38 +03:00
# define NS_BADCERTHANDLER_CONTRACTID \
" @mozilla.org/content/xmlhttprequest-bad-cert-handler;1 "
2009-01-13 20:38:01 +03:00
# define NS_PROGRESS_EVENT_INTERVAL 50
2008-10-20 01:26:37 +04:00
2014-04-27 11:06:00 +04:00
NS_IMPL_ISUPPORTS ( nsXHRParseEndListener , nsIDOMEventListener )
2011-11-16 11:38:51 +04:00
2016-04-26 03:23:21 +03:00
class nsResumeTimeoutsEvent : public Runnable
2009-03-03 23:11:14 +03:00
{
public :
2016-01-30 20:05:36 +03:00
explicit nsResumeTimeoutsEvent ( nsPIDOMWindowInner * aWindow ) : mWindow ( aWindow ) { }
2009-03-03 23:11:14 +03:00
2016-08-08 05:18:10 +03:00
NS_IMETHOD Run ( ) override
2009-03-03 23:11:14 +03:00
{
2011-10-17 18:59:28 +04:00
mWindow - > ResumeTimeouts ( false ) ;
2009-03-03 23:11:14 +03:00
return NS_OK ;
}
private :
2016-01-30 20:05:36 +03:00
nsCOMPtr < nsPIDOMWindowInner > mWindow ;
2009-03-03 23:11:14 +03:00
} ;
2008-08-14 15:04:43 +04:00
2006-04-20 07:39:48 +04:00
// This helper function adds the given load flags to the request's existing
// load flags.
static void AddLoadFlags ( nsIRequest * request , nsLoadFlags newFlags )
{
nsLoadFlags flags ;
request - > GetLoadFlags ( & flags ) ;
flags | = newFlags ;
request - > SetLoadFlags ( flags ) ;
}
2006-04-20 07:38:52 +04:00
2006-04-20 07:36:50 +04:00
/////////////////////////////////////////////
//
//
/////////////////////////////////////////////
2014-02-10 22:35:25 +04:00
bool
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : sDontWarnAboutSyncXHR = false ;
2014-02-10 22:35:25 +04:00
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : XMLHttpRequestMainThread ( )
2011-09-24 05:57:36 +04:00
: mResponseBodyDecodedPos ( 0 ) ,
2016-06-27 20:13:41 +03:00
mResponseType ( XMLHttpRequestResponseType : : _empty ) ,
2015-01-13 11:51:09 +03:00
mRequestObserver ( nullptr ) ,
2016-07-08 19:46:12 +03:00
mState ( State : : unsent ) ,
2016-07-08 19:49:40 +03:00
mFlagSynchronous ( false ) , mFlagAborted ( false ) , mFlagParseBody ( false ) ,
2016-07-08 19:46:12 +03:00
mFlagSyncLooping ( false ) , mFlagBackgroundRequest ( false ) ,
mFlagHadUploadListenersOnSend ( false ) , mFlagACwithCredentials ( false ) ,
2016-07-08 19:50:19 +03:00
mFlagTimedOut ( false ) , mFlagDeleted ( false ) , mFlagSend ( false ) ,
2011-10-17 18:59:28 +04:00
mUploadTransferred ( 0 ) , mUploadTotal ( 0 ) , mUploadComplete ( true ) ,
mProgressSinceLastProgressEvent ( false ) ,
2012-01-26 14:02:22 +04:00
mRequestSentTime ( 0 ) , mTimeoutMilliseconds ( 0 ) ,
2012-02-16 20:45:25 +04:00
mErrorLoad ( false ) , mWaitingForOnStopRequest ( false ) ,
2013-08-21 18:59:08 +04:00
mProgressTimerIsActive ( false ) ,
2011-11-16 11:38:51 +04:00
mIsHtml ( false ) ,
mWarnAboutSyncHtml ( false ) ,
2016-08-06 06:47:40 +03:00
mLoadTotal ( 0 ) ,
2012-07-09 05:09:51 +04:00
mIsSystem ( false ) ,
mIsAnon ( false ) ,
2011-10-17 18:59:28 +04:00
mFirstStartRequestSeen ( false ) ,
mInLoadProgressEvent ( false ) ,
2015-01-14 10:59:06 +03:00
mResultJSON ( JS : : UndefinedValue ( ) ) ,
2012-09-07 18:51:35 +04:00
mResultArrayBuffer ( nullptr ) ,
2014-05-16 09:34:43 +04:00
mIsMappedArrayBuffer ( false ) ,
2012-09-07 18:51:35 +04:00
mXPCOMifier ( nullptr )
2006-04-20 07:36:50 +04:00
{
}
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : ~ XMLHttpRequestMainThread ( )
2006-04-20 07:36:50 +04:00
{
2016-07-08 19:46:12 +03:00
mFlagDeleted = true ;
2012-02-14 22:05:43 +04:00
2016-07-08 19:50:19 +03:00
if ( ( mState = = State : : opened & & mFlagSend ) | |
mState = = State : : loading ) {
2006-04-20 07:36:54 +04:00
Abort ( ) ;
2006-04-20 07:39:09 +04:00
}
2016-07-08 19:46:12 +03:00
MOZ_ASSERT ( ! mFlagSyncLooping , " we rather crash than hang " ) ;
mFlagSyncLooping = false ;
2006-05-26 05:00:21 +04:00
2015-01-14 10:59:06 +03:00
mResultJSON . setUndefined ( ) ;
2013-05-15 15:48:55 +04:00
mResultArrayBuffer = nullptr ;
2013-08-17 00:10:17 +04:00
mozilla : : DropJSObjects ( this ) ;
2006-04-20 07:36:50 +04:00
}
2011-05-24 05:09:28 +04:00
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : RootJSResultObjects ( )
2011-05-24 05:09:28 +04:00
{
2013-08-17 00:10:17 +04:00
mozilla : : HoldJSObjects ( this ) ;
2011-05-24 05:09:28 +04:00
}
2008-02-20 02:12:23 +03:00
/**
* This Init method is called from the factory constructor .
*/
2007-12-12 11:33:32 +03:00
nsresult
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : Init ( )
2007-12-12 11:33:32 +03:00
{
2012-06-09 00:45:13 +04:00
nsIScriptSecurityManager * secMan = nsContentUtils : : GetSecurityManager ( ) ;
2007-12-12 11:33:32 +03:00
nsCOMPtr < nsIPrincipal > subjectPrincipal ;
if ( secMan ) {
2012-06-09 00:45:13 +04:00
secMan - > GetSystemPrincipal ( getter_AddRefs ( subjectPrincipal ) ) ;
2007-12-12 11:33:32 +03:00
}
NS_ENSURE_STATE ( subjectPrincipal ) ;
2013-04-04 13:30:36 +04:00
// Instead of grabbing some random global from the context stack,
2013-07-16 17:04:28 +04:00
// let's use the default one (junk scope) for now.
2013-04-04 13:30:36 +04:00
// We should move away from this Init...
2014-09-21 23:31:53 +04:00
Construct ( subjectPrincipal , xpc : : NativeGlobal ( xpc : : PrivilegedJunkScope ( ) ) ) ;
2008-02-20 02:12:23 +03:00
return NS_OK ;
}
2012-06-09 00:45:13 +04:00
2008-02-20 02:12:23 +03:00
/**
* This Init method should only be called by C + + consumers .
*/
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : Init ( nsIPrincipal * aPrincipal ,
nsIGlobalObject * aGlobalObject ,
nsIURI * aBaseURI ,
nsILoadGroup * aLoadGroup )
2008-02-20 02:12:23 +03:00
{
NS_ENSURE_ARG_POINTER ( aPrincipal ) ;
2015-01-08 19:21:52 +03:00
Construct ( aPrincipal , aGlobalObject , aBaseURI , aLoadGroup ) ;
2007-12-12 11:33:32 +03:00
return NS_OK ;
}
2012-06-21 11:21:55 +04:00
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : InitParameters ( bool aAnon , bool aSystem )
2012-06-21 11:21:55 +04:00
{
2012-09-17 04:20:16 +04:00
if ( ! aAnon & & ! aSystem ) {
return ;
}
2012-06-07 22:28:33 +04:00
// Check for permissions.
// Chrome is always allowed access, so do the permission check only
// for non-chrome pages.
2013-10-16 21:20:51 +04:00
if ( ! IsSystemXHR ( ) & & aSystem ) {
2015-05-12 22:56:41 +03:00
nsIGlobalObject * global = GetOwnerGlobal ( ) ;
if ( NS_WARN_IF ( ! global ) ) {
SetParameters ( aAnon , false ) ;
return ;
}
nsIPrincipal * principal = global - > PrincipalOrNull ( ) ;
if ( NS_WARN_IF ( ! principal ) ) {
SetParameters ( aAnon , false ) ;
2012-06-21 11:21:55 +04:00
return ;
}
2012-06-07 22:28:33 +04:00
2012-08-18 04:42:00 +04:00
nsCOMPtr < nsIPermissionManager > permMgr =
2014-04-29 21:27:26 +04:00
services : : GetPermissionManager ( ) ;
2015-05-12 22:56:41 +03:00
if ( NS_WARN_IF ( ! permMgr ) ) {
SetParameters ( aAnon , false ) ;
2012-08-18 04:42:00 +04:00
return ;
2015-05-12 22:56:41 +03:00
}
2012-08-18 04:42:00 +04:00
2012-08-22 19:56:38 +04:00
uint32_t permission ;
2012-08-18 04:42:00 +04:00
nsresult rv =
permMgr - > TestPermissionFromPrincipal ( principal , " systemXHR " , & permission ) ;
if ( NS_FAILED ( rv ) | | permission ! = nsIPermissionManager : : ALLOW_ACTION ) {
2015-05-12 22:56:41 +03:00
SetParameters ( aAnon , false ) ;
2012-06-21 11:21:55 +04:00
return ;
2012-06-07 22:28:33 +04:00
}
}
2012-09-17 04:20:16 +04:00
SetParameters ( aAnon , aSystem ) ;
2007-12-12 11:33:32 +03:00
}
2011-09-24 05:57:22 +04:00
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : ResetResponse ( )
2011-09-24 05:57:22 +04:00
{
2012-07-30 18:20:58 +04:00
mResponseXML = nullptr ;
2011-09-24 05:57:22 +04:00
mResponseBody . Truncate ( ) ;
2011-09-24 05:57:36 +04:00
mResponseText . Truncate ( ) ;
2012-07-30 18:20:58 +04:00
mResponseBlob = nullptr ;
2015-05-12 15:09:51 +03:00
mDOMBlob = nullptr ;
2012-09-20 11:55:36 +04:00
mBlobSet = nullptr ;
2012-07-30 18:20:58 +04:00
mResultArrayBuffer = nullptr ;
2013-05-15 22:42:10 +04:00
mArrayBufferBuilder . reset ( ) ;
2015-01-14 10:59:06 +03:00
mResultJSON . setUndefined ( ) ;
2014-07-24 09:47:00 +04:00
mDataAvailable = 0 ;
2011-09-24 05:57:22 +04:00
mLoadTransferred = 0 ;
2011-09-24 05:57:36 +04:00
mResponseBodyDecodedPos = 0 ;
2011-09-24 05:57:22 +04:00
}
2008-10-01 03:56:57 +04:00
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : SetRequestObserver ( nsIRequestObserver * aObserver )
2008-10-01 03:56:57 +04:00
{
mRequestObserver = aObserver ;
}
2016-06-27 20:13:41 +03:00
NS_IMPL_CYCLE_COLLECTION_CLASS ( XMLHttpRequestMainThread )
2013-08-02 05:29:05 +04:00
2016-06-27 20:13:41 +03:00
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN ( XMLHttpRequestMainThread )
2012-02-16 20:45:25 +04:00
bool isBlack = tmp - > IsBlack ( ) ;
if ( isBlack | | tmp - > mWaitingForOnStopRequest ) {
2012-01-26 19:55:30 +04:00
if ( tmp - > mListenerManager ) {
2012-10-17 05:22:02 +04:00
tmp - > mListenerManager - > MarkForCC ( ) ;
2012-01-26 19:55:30 +04:00
}
2012-03-14 18:22:10 +04:00
if ( ! isBlack & & tmp - > PreservingWrapper ( ) ) {
2013-09-09 07:28:48 +04:00
// This marks the wrapper black.
tmp - > GetWrapper ( ) ;
2012-02-16 20:45:25 +04:00
}
2012-01-26 19:55:30 +04:00
return true ;
}
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
2016-06-27 20:13:41 +03:00
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN ( XMLHttpRequestMainThread )
2012-09-29 02:29:37 +04:00
return tmp - >
2014-04-01 10:13:50 +04:00
IsBlackAndDoesNotNeedTracing ( static_cast < DOMEventTargetHelper * > ( tmp ) ) ;
2012-01-26 19:55:30 +04:00
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
2016-06-27 20:13:41 +03:00
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN ( XMLHttpRequestMainThread )
2012-01-26 19:55:30 +04:00
return tmp - > IsBlack ( ) ;
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
2016-06-27 20:13:41 +03:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED ( XMLHttpRequestMainThread ,
2016-06-27 20:13:41 +03:00
XMLHttpRequestEventTarget )
2012-11-15 11:32:40 +04:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mContext )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mChannel )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mResponseXML )
2007-01-05 01:31:26 +03:00
2012-11-15 11:32:40 +04:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mXMLParserStreamListener )
2007-01-05 01:31:26 +03:00
2014-10-16 01:14:30 +04:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mResponseBlob )
2015-05-12 15:09:51 +03:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mDOMBlob )
2014-10-16 01:14:30 +04:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mNotificationCallbacks )
2012-11-15 11:32:40 +04:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mChannelEventSink )
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mProgressEventSink )
2007-12-12 11:33:32 +03:00
2012-11-15 11:32:40 +04:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mUpload )
2007-01-05 01:31:26 +03:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
2016-06-27 20:13:41 +03:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED ( XMLHttpRequestMainThread ,
2016-06-27 20:13:41 +03:00
XMLHttpRequestEventTarget )
2012-07-30 18:20:58 +04:00
tmp - > mResultArrayBuffer = nullptr ;
2013-05-15 22:42:10 +04:00
tmp - > mArrayBufferBuilder . reset ( ) ;
2015-01-14 10:59:06 +03:00
tmp - > mResultJSON . setUndefined ( ) ;
2012-11-15 11:32:40 +04:00
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mContext )
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mChannel )
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mResponseXML )
2007-01-05 01:31:26 +03:00
2012-11-15 11:32:40 +04:00
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mXMLParserStreamListener )
2007-01-05 01:31:26 +03:00
2014-10-16 01:14:30 +04:00
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mResponseBlob )
2015-05-12 15:09:51 +03:00
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mDOMBlob )
2014-10-16 01:14:30 +04:00
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mNotificationCallbacks )
2012-11-15 11:32:40 +04:00
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mChannelEventSink )
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mProgressEventSink )
2007-12-12 11:33:32 +03:00
2012-11-15 11:32:40 +04:00
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mUpload )
2007-01-05 01:31:26 +03:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
2016-06-27 20:13:41 +03:00
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED ( XMLHttpRequestMainThread ,
2016-06-27 20:13:41 +03:00
XMLHttpRequestEventTarget )
2012-05-15 20:56:39 +04:00
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK ( mResultArrayBuffer )
2016-02-22 21:11:02 +03:00
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK ( mResultJSON )
2011-05-24 05:09:28 +04:00
NS_IMPL_CYCLE_COLLECTION_TRACE_END
2016-06-27 20:13:41 +03:00
// QueryInterface implementation for XMLHttpRequestMainThread
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED ( XMLHttpRequestMainThread )
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2006-04-20 07:37:17 +04:00
NS_INTERFACE_MAP_ENTRY ( nsIXMLHttpRequest )
2006-04-20 07:37:23 +04:00
NS_INTERFACE_MAP_ENTRY ( nsIJSXMLHttpRequest )
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2006-04-20 07:37:17 +04:00
NS_INTERFACE_MAP_ENTRY ( nsIRequestObserver )
NS_INTERFACE_MAP_ENTRY ( nsIStreamListener )
2006-04-20 07:39:29 +04:00
NS_INTERFACE_MAP_ENTRY ( nsIChannelEventSink )
2006-04-20 07:39:18 +04:00
NS_INTERFACE_MAP_ENTRY ( nsIProgressEventSink )
2006-04-20 07:38:01 +04:00
NS_INTERFACE_MAP_ENTRY ( nsIInterfaceRequestor )
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2006-04-20 07:37:17 +04:00
NS_INTERFACE_MAP_ENTRY ( nsISupportsWeakReference )
2008-10-20 01:26:37 +04:00
NS_INTERFACE_MAP_ENTRY ( nsITimerCallback )
2013-01-18 09:21:43 +04:00
NS_INTERFACE_MAP_ENTRY ( nsISizeOfEventTarget )
2016-06-27 20:13:41 +03:00
NS_INTERFACE_MAP_END_INHERITING ( XMLHttpRequestEventTarget )
2006-05-26 05:00:21 +04:00
2016-06-27 20:13:41 +03:00
NS_IMPL_ADDREF_INHERITED ( XMLHttpRequestMainThread , XMLHttpRequestEventTarget )
NS_IMPL_RELEASE_INHERITED ( XMLHttpRequestMainThread , XMLHttpRequestEventTarget )
2006-04-20 07:36:50 +04:00
2016-06-27 20:13:41 +03:00
NS_IMPL_EVENT_HANDLER ( XMLHttpRequestMainThread , readystatechange )
2012-08-31 07:45:16 +04:00
2012-03-13 04:56:07 +04:00
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : DisconnectFromOwner ( )
2012-03-13 04:56:07 +04:00
{
2016-06-27 20:13:41 +03:00
XMLHttpRequestEventTarget : : DisconnectFromOwner ( ) ;
2012-03-13 04:56:20 +04:00
Abort ( ) ;
2012-03-13 04:56:07 +04:00
}
2013-01-18 09:21:43 +04:00
size_t
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : SizeOfEventTargetIncludingThis (
2013-06-23 16:03:39 +04:00
MallocSizeOf aMallocSizeOf ) const
2013-01-18 09:21:43 +04: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
}
2006-04-20 07:39:10 +04:00
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetChannel ( nsIChannel * * aChannel )
2006-04-20 07:37:01 +04:00
{
NS_ENSURE_ARG_POINTER ( aChannel ) ;
2007-01-05 01:31:26 +03:00
NS_IF_ADDREF ( * aChannel = mChannel ) ;
2006-04-20 07:37:01 +04:00
return NS_OK ;
}
2016-01-30 20:05:36 +03:00
static void LogMessage ( const char * aWarning , nsPIDOMWindowInner * aWindow )
2011-12-08 17:54:05 +04:00
{
nsCOMPtr < nsIDocument > doc ;
if ( aWindow ) {
2013-04-24 08:22:37 +04:00
doc = aWindow - > GetExtantDoc ( ) ;
2011-12-08 17:54:05 +04:00
}
2011-12-15 18:47:03 +04:00
nsContentUtils : : ReportToConsole ( nsIScriptError : : warningFlag ,
2013-08-21 23:28:26 +04:00
NS_LITERAL_CSTRING ( " DOM " ) , doc ,
2011-12-15 18:47:03 +04:00
nsContentUtils : : eDOM_PROPERTIES ,
aWarning ) ;
2011-12-08 17:54:05 +04:00
}
2006-04-20 07:39:10 +04:00
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetResponseXML ( nsIDOMDocument * * aResponseXML )
2006-04-20 07:36:50 +04:00
{
2012-05-06 05:15:11 +04:00
ErrorResult rv ;
2012-03-26 19:38:06 +04:00
nsIDocument * responseXML = GetResponseXML ( rv ) ;
2012-05-06 05:15:11 +04:00
if ( rv . Failed ( ) ) {
2015-04-27 16:18:51 +03:00
return rv . StealNSResult ( ) ;
2012-05-06 05:15:11 +04:00
}
2012-03-26 19:38:06 +04:00
if ( ! responseXML ) {
2012-07-30 18:20:58 +04:00
* aResponseXML = nullptr ;
2012-03-26 19:38:06 +04:00
return NS_OK ;
}
return CallQueryInterface ( responseXML , aResponseXML ) ;
}
nsIDocument *
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetResponseXML ( ErrorResult & aRv )
2012-03-26 19:38:06 +04:00
{
2016-06-27 20:13:41 +03:00
if ( mResponseType ! = XMLHttpRequestResponseType : : _empty & &
mResponseType ! = XMLHttpRequestResponseType : : Document ) {
2012-05-06 05:15:11 +04:00
aRv . Throw ( NS_ERROR_DOM_INVALID_STATE_ERR ) ;
2012-07-30 18:20:58 +04:00
return nullptr ;
2006-04-20 07:36:50 +04:00
}
2011-11-16 11:38:51 +04:00
if ( mWarnAboutSyncHtml ) {
mWarnAboutSyncHtml = false ;
2012-03-13 04:56:07 +04:00
LogMessage ( " HTMLSyncXHRWarning " , GetOwner ( ) ) ;
2011-11-16 11:38:51 +04:00
}
2016-07-08 19:46:12 +03:00
if ( mState ! = State : : done ) {
2016-05-01 21:29:22 +03:00
return nullptr ;
}
return mResponseXML ;
2006-04-20 07:36:50 +04:00
}
2006-04-20 07:37:08 +04:00
/*
2013-03-20 20:22:26 +04:00
* This piece copied from XMLDocument , we try to get the charset
2006-04-20 07:37:08 +04:00
* from HTTP headers .
*/
nsresult
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : DetectCharset ( )
2006-04-20 07:37:08 +04:00
{
2011-09-24 05:57:36 +04:00
mResponseCharset . Truncate ( ) ;
2012-07-30 18:20:58 +04:00
mDecoder = nullptr ;
2006-04-20 07:38:52 +04:00
2016-06-27 20:13:41 +03:00
if ( mResponseType ! = XMLHttpRequestResponseType : : _empty & &
mResponseType ! = XMLHttpRequestResponseType : : Text & &
mResponseType ! = XMLHttpRequestResponseType : : Json & &
mResponseType ! = XMLHttpRequestResponseType : : Moz_chunked_text ) {
2006-04-20 07:37:08 +04:00
return NS_OK ;
2010-04-23 21:37:02 +04:00
}
2006-04-20 07:37:08 +04:00
2012-09-02 06:35:17 +04:00
nsAutoCString charsetVal ;
2013-03-04 13:06:15 +04:00
bool ok = mChannel & &
NS_SUCCEEDED ( mChannel - > GetContentCharset ( charsetVal ) ) & &
2012-11-08 03:04:22 +04:00
EncodingUtils : : FindEncodingForLabel ( charsetVal , mResponseCharset ) ;
if ( ! ok | | mResponseCharset . IsEmpty ( ) ) {
2011-09-24 05:57:36 +04:00
// MS documentation states UTF-8 is default for responseText
mResponseCharset . AssignLiteral ( " UTF-8 " ) ;
2010-04-23 21:37:02 +04:00
}
2006-04-20 07:38:50 +04:00
2016-06-27 20:13:41 +03:00
if ( mResponseType = = XMLHttpRequestResponseType : : Json & &
2011-12-08 17:56:14 +04:00
! mResponseCharset . EqualsLiteral ( " UTF-8 " ) ) {
// The XHR spec says only UTF-8 is supported for responseType == "json"
2012-03-13 04:56:07 +04:00
LogMessage ( " JSONCharsetWarning " , GetOwner ( ) ) ;
2011-12-08 17:56:14 +04:00
mResponseCharset . AssignLiteral ( " UTF-8 " ) ;
}
2013-11-26 11:31:52 +04:00
mDecoder = EncodingUtils : : DecoderForEncoding ( mResponseCharset ) ;
2006-04-20 07:37:08 +04:00
2013-11-26 11:31:52 +04:00
return NS_OK ;
2011-09-24 05:57:36 +04:00
}
2006-04-20 07:37:08 +04:00
2011-09-24 05:57:36 +04:00
nsresult
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : AppendToResponseText ( const char * aSrcBuffer ,
uint32_t aSrcBufferLen )
2011-09-24 05:57:36 +04:00
{
NS_ENSURE_STATE ( mDecoder ) ;
2012-08-22 19:56:38 +04:00
int32_t destBufferLen ;
2011-09-24 05:57:36 +04:00
nsresult rv = mDecoder - > GetMaxLength ( aSrcBuffer , aSrcBufferLen ,
& destBufferLen ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2006-04-20 07:37:08 +04:00
2015-06-23 17:47:38 +03:00
uint32_t size = mResponseText . Length ( ) + destBufferLen ;
if ( size < ( uint32_t ) destBufferLen ) {
return NS_ERROR_OUT_OF_MEMORY ;
}
if ( ! mResponseText . SetCapacity ( size , fallible ) ) {
2006-04-20 07:37:54 +04:00
return NS_ERROR_OUT_OF_MEMORY ;
}
2006-04-20 07:37:08 +04:00
2014-01-04 19:02:17 +04:00
char16_t * destBuffer = mResponseText . BeginWriting ( ) + mResponseText . Length ( ) ;
2010-11-23 19:49:12 +03:00
2015-06-23 17:47:38 +03:00
CheckedInt32 totalChars = mResponseText . Length ( ) ;
2006-04-20 07:37:54 +04:00
2011-09-24 05:57:36 +04:00
// This code here is basically a copy of a similar thing in
2012-08-22 19:56:38 +04:00
// nsScanner::Append(const char* aBuffer, uint32_t aLen).
2012-12-10 18:11:15 +04: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 ;
2015-06-23 17:47:38 +03:00
if ( ! totalChars . isValid ( ) ) {
return NS_ERROR_OUT_OF_MEMORY ;
}
2011-09-24 05:57:36 +04:00
2015-06-23 17:47:38 +03:00
mResponseText . SetLength ( totalChars . value ( ) ) ;
2006-04-20 07:37:08 +04:00
return NS_OK ;
}
2012-03-26 19:38:06 +04:00
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetResponseText ( nsAString & aResponseText )
2012-03-26 19:38:06 +04:00
{
2012-05-06 05:15:11 +04:00
ErrorResult rv ;
2012-03-26 19:38:06 +04:00
nsString responseText ;
GetResponseText ( responseText , rv ) ;
aResponseText = responseText ;
2015-04-27 16:18:51 +03:00
return rv . StealNSResult ( ) ;
2012-03-26 19:38:06 +04:00
}
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetResponseText ( nsAString & aResponseText ,
ErrorResult & aRv )
2006-04-20 07:37:08 +04:00
{
2006-04-20 07:38:50 +04:00
aResponseText . Truncate ( ) ;
2016-06-27 20:13:41 +03:00
if ( mResponseType ! = XMLHttpRequestResponseType : : _empty & &
mResponseType ! = XMLHttpRequestResponseType : : Text & &
mResponseType ! = XMLHttpRequestResponseType : : Moz_chunked_text ) {
2012-05-06 05:15:11 +04:00
aRv . Throw ( NS_ERROR_DOM_INVALID_STATE_ERR ) ;
2012-03-26 19:38:06 +04:00
return ;
2011-05-11 03:18:55 +04:00
}
2016-06-27 20:13:41 +03:00
if ( mResponseType = = XMLHttpRequestResponseType : : Moz_chunked_text & &
2011-09-24 05:57:36 +04:00
! mInLoadProgressEvent ) {
2011-10-17 18:59:28 +04:00
aResponseText . SetIsVoid ( true ) ;
2012-03-26 19:38:06 +04:00
return ;
2011-09-24 05:57:36 +04:00
}
2016-07-08 19:46:12 +03:00
if ( mState ! = State : : loading & & mState ! = State : : done ) {
2012-03-26 19:38:06 +04:00
return ;
2006-04-20 07:37:08 +04:00
}
2011-09-24 05:57:36 +04: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 19:28:12 +04:00
if ( ! mResponseXML | |
2011-09-24 05:57:36 +04:00
mResponseBodyDecodedPos = = mResponseBody . Length ( ) ) {
aResponseText = mResponseText ;
2012-03-26 19:38:06 +04:00
return ;
2011-09-24 05:57:36 +04:00
}
2012-03-26 19:38:06 +04:00
if ( mResponseCharset ! = mResponseXML - > GetDocumentCharacterSet ( ) ) {
mResponseCharset = mResponseXML - > GetDocumentCharacterSet ( ) ;
2011-09-24 05:57:36 +04:00
mResponseText . Truncate ( ) ;
mResponseBodyDecodedPos = 0 ;
2013-11-26 11:31:52 +04:00
mDecoder = EncodingUtils : : DecoderForEncoding ( mResponseCharset ) ;
2011-09-24 05:57:36 +04:00
}
NS_ASSERTION ( mResponseBodyDecodedPos < mResponseBody . Length ( ) ,
" Unexpected mResponseBodyDecodedPos " ) ;
2012-03-26 19:38:06 +04:00
aRv = AppendToResponseText ( mResponseBody . get ( ) + mResponseBodyDecodedPos ,
mResponseBody . Length ( ) - mResponseBodyDecodedPos ) ;
2012-05-06 05:15:11 +04:00
if ( aRv . Failed ( ) ) {
2012-03-26 19:38:06 +04:00
return ;
}
2011-09-24 05:57:36 +04:00
mResponseBodyDecodedPos = mResponseBody . Length ( ) ;
2016-03-16 06:38:27 +03:00
2016-07-08 19:46:12 +03:00
if ( mState = = State : : done ) {
2011-09-24 05:57:36 +04:00
// Free memory buffer which we no longer need
mResponseBody . Truncate ( ) ;
mResponseBodyDecodedPos = 0 ;
}
aResponseText = mResponseText ;
2006-04-20 07:37:08 +04:00
}
2011-09-09 02:12:18 +04:00
nsresult
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : CreateResponseParsedJSON ( JSContext * aCx )
2010-08-14 21:52:19 +04:00
{
2011-09-09 02:12:18 +04:00
if ( ! aCx ) {
return NS_ERROR_FAILURE ;
}
2012-08-05 19:41:13 +04:00
RootJSResultObjects ( ) ;
2012-08-03 20:29:53 +04:00
2011-12-08 17:56:14 +04:00
// The Unicode converter has already zapped the BOM if there was one
2013-06-18 14:00:37 +04:00
JS : : Rooted < JS : : Value > value ( aCx ) ;
2011-09-09 02:12:18 +04:00
if ( ! JS_ParseJSON ( aCx ,
2014-07-22 08:43:21 +04:00
static_cast < const char16_t * > ( mResponseText . get ( ) ) , mResponseText . Length ( ) ,
2013-06-18 14:00:37 +04:00
& value ) ) {
2010-08-14 21:52:19 +04:00
return NS_ERROR_FAILURE ;
2011-09-09 02:12:18 +04:00
}
2013-06-18 14:00:37 +04:00
mResultJSON = value ;
2011-09-09 02:12:18 +04:00
return NS_OK ;
}
2012-09-20 11:55:36 +04:00
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : CreatePartialBlob ( ErrorResult & aRv )
2012-01-30 14:33:59 +04:00
{
2015-05-12 15:09:51 +03:00
if ( mDOMBlob ) {
2014-07-24 09:47:00 +04:00
// Use progress info to determine whether load is complete, but use
// mDataAvailable to ensure a slice is created based on the uncompressed
// data count.
2012-01-30 14:33:59 +04:00
if ( mLoadTotal = = mLoadTransferred ) {
2015-05-12 15:09:51 +03:00
mResponseBlob = mDOMBlob ;
2012-01-30 14:33:59 +04:00
} else {
2015-05-12 15:09:51 +03:00
mResponseBlob = mDOMBlob - > CreateSlice ( 0 , mDataAvailable ,
2015-12-05 00:15:46 +03:00
EmptyString ( ) , aRv ) ;
2012-01-30 14:33:59 +04:00
}
2012-09-20 11:55:36 +04:00
return ;
2012-01-30 14:33:59 +04:00
}
2012-09-20 11:55:36 +04:00
// mBlobSet can be null if the request has been canceled
if ( ! mBlobSet ) {
return ;
2012-05-01 02:49:15 +04:00
}
2012-09-02 06:35:17 +04:00
nsAutoCString contentType ;
2012-01-30 14:33:59 +04:00
if ( mLoadTotal = = mLoadTransferred ) {
mChannel - > GetContentType ( contentType ) ;
}
2015-12-05 00:15:46 +03:00
mResponseBlob = mBlobSet - > GetBlobInternal ( GetOwner ( ) , contentType , aRv ) ;
2012-01-30 14:33:59 +04:00
}
2016-06-27 20:13:41 +03:00
NS_IMETHODIMP XMLHttpRequestMainThread : : GetResponseType ( nsAString & aResponseType )
2011-05-11 03:18:55 +04:00
{
2016-06-27 20:13:41 +03:00
MOZ_ASSERT ( mResponseType < XMLHttpRequestResponseType : : EndGuard_ ) ;
const EnumEntry & entry =
XMLHttpRequestResponseTypeValues : : strings [ static_cast < uint32_t > ( mResponseType ) ] ;
aResponseType . AssignASCII ( entry . value , entry . length ) ;
2011-05-11 03:18:55 +04:00
return NS_OK ;
}
2016-06-27 20:13:41 +03:00
NS_IMETHODIMP XMLHttpRequestMainThread : : SetResponseType ( const nsAString & aResponseType )
2012-03-26 19:38:06 +04:00
{
2016-06-27 20:13:41 +03:00
uint32_t i = 0 ;
for ( const EnumEntry * entry = XMLHttpRequestResponseTypeValues : : strings ;
entry - > value ; + + entry , + + i ) {
if ( aResponseType . EqualsASCII ( entry - > value , entry - > length ) ) {
ErrorResult rv ;
SetResponseType ( static_cast < XMLHttpRequestResponseType > ( i ) , rv ) ;
return rv . StealNSResult ( ) ;
}
2012-03-26 19:38:06 +04:00
}
2016-06-27 20:13:41 +03:00
return NS_OK ;
2012-03-31 08:42:20 +04:00
}
2012-03-26 19:38:06 +04:00
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : SetResponseType ( XMLHttpRequestResponseType aResponseType ,
2016-06-27 20:13:41 +03:00
ErrorResult & aRv )
2011-05-11 03:18:55 +04:00
{
2015-01-13 11:51:09 +03:00
// If the state is LOADING or DONE raise an INVALID_STATE_ERR exception
// and terminate these steps.
2016-07-08 19:46:12 +03:00
if ( mState = = State : : loading | | mState = = State : : done ) {
2012-05-06 05:15:11 +04:00
aRv . Throw ( NS_ERROR_DOM_INVALID_STATE_ERR ) ;
2012-03-26 19:38:06 +04:00
return ;
}
2011-05-11 03:18:55 +04:00
2011-12-08 17:54:05 +04:00
// sync request is not allowed setting responseType in window context
2016-07-08 19:49:40 +03:00
if ( HasOrHasHadOwner ( ) & & mState ! = State : : unsent & & mFlagSynchronous ) {
2012-03-13 04:56:07 +04:00
LogMessage ( " ResponseTypeSyncXHRWarning " , GetOwner ( ) ) ;
2012-05-06 05:15:11 +04:00
aRv . Throw ( NS_ERROR_DOM_INVALID_ACCESS_ERR ) ;
2012-03-26 19:38:06 +04:00
return ;
2011-12-08 17:54:05 +04:00
}
2016-07-08 19:49:40 +03:00
if ( mFlagSynchronous & &
2016-06-27 20:13:41 +03:00
( aResponseType = = XMLHttpRequestResponseType : : Moz_chunked_text | |
aResponseType = = XMLHttpRequestResponseType : : Moz_chunked_arraybuffer ) ) {
2012-05-06 05:15:11 +04:00
aRv . Throw ( NS_ERROR_DOM_INVALID_STATE_ERR ) ;
2012-03-26 19:38:06 +04:00
return ;
2011-05-11 03:18:55 +04:00
}
2012-03-26 19:38:06 +04:00
// Set the responseType attribute's value to the given value.
mResponseType = aResponseType ;
2011-05-11 03:18:55 +04:00
}
2012-03-26 19:38:06 +04:00
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetResponse ( JSContext * aCx , JS : : MutableHandle < JS : : Value > aResult )
2011-05-11 03:18:55 +04:00
{
2012-05-06 05:15:11 +04:00
ErrorResult rv ;
2014-06-12 00:26:52 +04:00
GetResponse ( aCx , aResult , rv ) ;
2015-04-27 16:18:51 +03:00
return rv . StealNSResult ( ) ;
2012-03-26 19:38:06 +04:00
}
2011-05-11 03:18:55 +04:00
2014-06-12 00:26:52 +04:00
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetResponse ( JSContext * aCx ,
JS : : MutableHandle < JS : : Value > aResponse ,
ErrorResult & aRv )
2012-03-26 19:38:06 +04:00
{
2011-05-11 03:18:55 +04:00
switch ( mResponseType ) {
2016-06-27 20:13:41 +03:00
case XMLHttpRequestResponseType : : _empty :
case XMLHttpRequestResponseType : : Text :
case XMLHttpRequestResponseType : : Moz_chunked_text :
2012-03-26 19:38:06 +04:00
{
nsString str ;
aRv = GetResponseText ( str ) ;
2012-05-06 05:15:11 +04:00
if ( aRv . Failed ( ) ) {
2014-06-12 00:26:52 +04:00
return ;
2011-05-11 03:18:55 +04:00
}
2014-06-12 00:26:52 +04:00
if ( ! xpc : : StringToJsval ( aCx , str , aResponse ) ) {
2012-05-06 05:15:11 +04:00
aRv . Throw ( NS_ERROR_OUT_OF_MEMORY ) ;
2012-03-26 19:38:06 +04:00
}
2014-06-12 00:26:52 +04:00
return ;
2012-03-26 19:38:06 +04:00
}
2011-05-11 03:18:55 +04:00
2016-06-27 20:13:41 +03:00
case XMLHttpRequestResponseType : : Arraybuffer :
case XMLHttpRequestResponseType : : Moz_chunked_arraybuffer :
2012-03-26 19:38:06 +04:00
{
2016-06-27 20:13:41 +03:00
if ( ! ( mResponseType = = XMLHttpRequestResponseType : : Arraybuffer & &
2016-07-08 19:46:12 +03:00
mState = = State : : done ) & &
2016-06-27 20:13:41 +03:00
! ( mResponseType = = XMLHttpRequestResponseType : : Moz_chunked_arraybuffer & &
2012-03-26 19:38:06 +04:00
mInLoadProgressEvent ) ) {
2014-06-12 00:26:52 +04:00
aResponse . setNull ( ) ;
return ;
2012-03-26 19:38:06 +04:00
}
if ( ! mResultArrayBuffer ) {
2012-08-05 19:41:13 +04:00
RootJSResultObjects ( ) ;
2013-04-27 23:25:24 +04:00
mResultArrayBuffer = mArrayBufferBuilder . getArrayBuffer ( aCx ) ;
if ( ! mResultArrayBuffer ) {
aRv . Throw ( NS_ERROR_OUT_OF_MEMORY ) ;
2014-06-12 00:26:52 +04:00
return ;
2011-05-24 05:09:28 +04:00
}
2011-05-11 03:18:55 +04:00
}
2014-06-12 00:26:52 +04:00
JS : : ExposeObjectToActiveJS ( mResultArrayBuffer ) ;
aResponse . setObject ( * mResultArrayBuffer ) ;
return ;
2012-03-26 19:38:06 +04:00
}
2016-06-27 20:13:41 +03:00
case XMLHttpRequestResponseType : : Blob :
case XMLHttpRequestResponseType : : Moz_blob :
2012-03-26 19:38:06 +04:00
{
2016-07-08 19:46:12 +03:00
if ( mState ! = State : : done ) {
2016-06-27 20:13:41 +03:00
if ( mResponseType ! = XMLHttpRequestResponseType : : Moz_blob ) {
2014-06-12 00:26:52 +04:00
aResponse . setNull ( ) ;
return ;
2012-03-26 19:38:06 +04:00
}
2012-01-30 14:33:59 +04:00
if ( ! mResponseBlob ) {
2015-12-05 00:15:46 +03:00
CreatePartialBlob ( aRv ) ;
2012-01-30 14:33:59 +04:00
}
}
2012-03-26 19:38:06 +04:00
if ( ! mResponseBlob ) {
2014-06-12 00:26:52 +04:00
aResponse . setNull ( ) ;
return ;
2011-05-11 03:18:55 +04:00
}
2014-11-26 22:25:20 +03:00
GetOrCreateDOMReflector ( aCx , mResponseBlob , aResponse ) ;
2014-06-12 00:26:52 +04:00
return ;
2012-03-26 19:38:06 +04:00
}
2016-06-27 20:13:41 +03:00
case XMLHttpRequestResponseType : : Document :
2012-03-26 19:38:06 +04:00
{
2016-07-08 19:46:12 +03:00
if ( ! mResponseXML | | mState ! = State : : done ) {
2014-06-12 00:26:52 +04:00
aResponse . setNull ( ) ;
return ;
2011-05-11 03:18:55 +04:00
}
2014-06-12 00:26:52 +04:00
aRv = nsContentUtils : : WrapNative ( aCx , mResponseXML , aResponse ) ;
return ;
2012-03-26 19:38:06 +04:00
}
2016-06-27 20:13:41 +03:00
case XMLHttpRequestResponseType : : Json :
2012-03-26 19:38:06 +04:00
{
2016-07-08 19:46:12 +03:00
if ( mState ! = State : : done ) {
2014-06-12 00:26:52 +04:00
aResponse . setNull ( ) ;
return ;
2011-09-09 02:12:18 +04:00
}
2014-06-12 00:26:52 +04:00
if ( mResultJSON . isUndefined ( ) ) {
2012-03-26 19:38:06 +04:00
aRv = CreateResponseParsedJSON ( aCx ) ;
mResponseText . Truncate ( ) ;
2012-05-06 05:15:11 +04:00
if ( aRv . Failed ( ) ) {
2012-03-26 19:38:06 +04: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 ) ;
2014-06-12 00:26:52 +04:00
mResultJSON . setNull ( ) ;
2012-03-26 19:38:06 +04:00
}
}
2014-06-12 00:26:52 +04:00
JS : : ExposeValueToActiveJS ( mResultJSON ) ;
aResponse . set ( mResultJSON ) ;
return ;
2012-03-26 19:38:06 +04:00
}
2011-05-11 03:18:55 +04:00
default :
NS_ERROR ( " Should not happen " ) ;
}
2014-06-12 00:26:52 +04:00
aResponse . setNull ( ) ;
2011-05-11 03:18:55 +04:00
}
2014-05-17 04:24:37 +04:00
bool
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : IsCrossSiteCORSRequest ( ) const
2014-05-17 04:24:37 +04:00
{
2015-12-07 02:33:15 +03:00
if ( ! mChannel ) {
return false ;
}
nsCOMPtr < nsILoadInfo > loadInfo = mChannel - > GetLoadInfo ( ) ;
MOZ_ASSERT ( loadInfo ) ;
return loadInfo - > GetTainting ( ) = = LoadTainting : : CORS ;
}
bool
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : IsDeniedCrossSiteCORSRequest ( )
2015-12-07 02:33:15 +03:00
{
if ( IsCrossSiteCORSRequest ( ) ) {
2014-05-17 04:24:37 +04:00
nsresult rv ;
mChannel - > GetStatus ( & rv ) ;
if ( NS_FAILED ( rv ) ) {
return true ;
}
}
return false ;
}
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetResponseURL ( nsAString & aUrl )
2014-05-17 04:24:37 +04:00
{
aUrl . Truncate ( ) ;
2015-02-19 04:56:21 +03:00
uint16_t readyState = ReadyState ( ) ;
2014-05-17 04:24:37 +04:00
if ( ( readyState = = UNSENT | | readyState = = OPENED ) | | ! mChannel ) {
return ;
}
// Make sure we don't leak responseURL information from denied cross-site
// requests.
2015-12-07 02:33:15 +03:00
if ( IsDeniedCrossSiteCORSRequest ( ) ) {
2014-05-17 04:24:37 +04:00
return ;
}
nsCOMPtr < nsIURI > responseUrl ;
mChannel - > GetURI ( getter_AddRefs ( responseUrl ) ) ;
if ( ! responseUrl ) {
return ;
}
nsAutoCString temp ;
2014-09-28 03:51:23 +04:00
responseUrl - > GetSpecIgnoringRef ( temp ) ;
2014-05-17 04:24:37 +04:00
CopyUTF8toUTF16 ( temp , aUrl ) ;
}
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetStatus ( uint32_t * aStatus )
2006-04-20 07:36:50 +04:00
{
2016-06-27 20:13:41 +03:00
ErrorResult rv ;
* aStatus = GetStatus ( rv ) ;
return rv . StealNSResult ( ) ;
2012-03-26 19:38:06 +04:00
}
2008-10-01 04:50:42 +04:00
2012-03-26 19:38:06 +04:00
uint32_t
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetStatus ( ErrorResult & aRv )
2012-03-26 19:38:06 +04:00
{
2014-05-17 04:24:37 +04:00
// Make sure we don't leak status information from denied cross-site
// requests.
2015-12-07 02:33:15 +03:00
if ( IsDeniedCrossSiteCORSRequest ( ) ) {
2014-05-17 04:24:37 +04:00
return 0 ;
2008-10-01 04:50:42 +04:00
}
2014-09-04 23:26:58 +04:00
uint16_t readyState = ReadyState ( ) ;
2012-10-26 05:57:57 +04: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 19:38:06 +04:00
return 0 ;
2012-03-26 12:40:09 +04:00
}
2006-04-20 07:37:29 +04:00
2012-03-26 12:40:09 +04:00
nsCOMPtr < nsIHttpChannel > httpChannel = GetCurrentHttpChannel ( ) ;
2012-03-26 19:38:06 +04:00
if ( ! httpChannel ) {
2014-09-04 23:26:58 +04:00
// Pretend like we got a 200 response, since our load was successful
return 200 ;
2006-04-20 07:39:09 +04:00
}
2006-04-20 07:37:29 +04:00
2012-08-22 19:56:38 +04:00
uint32_t status ;
2012-03-26 19:38:06 +04:00
nsresult rv = httpChannel - > GetResponseStatus ( & status ) ;
if ( NS_FAILED ( rv ) ) {
status = 0 ;
}
return status ;
2006-04-20 07:36:50 +04:00
}
2016-06-27 20:13:41 +03:00
NS_IMETHODIMP
XMLHttpRequestMainThread : : GetStatusText ( nsACString & aOut )
{
ErrorResult rv ;
GetStatusText ( aOut , rv ) ;
return rv . StealNSResult ( ) ;
}
2012-03-26 19:38:06 +04:00
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetStatusText ( nsACString & aStatusText ,
ErrorResult & aRv )
2006-04-20 07:36:50 +04:00
{
2014-09-04 23:26:58 +04:00
// Return an empty status text on all error loads.
2006-04-20 07:38:50 +04:00
aStatusText . Truncate ( ) ;
2014-05-17 04:24:37 +04:00
// Make sure we don't leak status information from denied cross-site
// requests.
2015-12-07 02:33:15 +03:00
if ( IsDeniedCrossSiteCORSRequest ( ) ) {
2014-05-17 04:24:37 +04:00
return ;
2006-04-20 07:36:50 +04:00
}
2006-04-20 07:38:50 +04:00
2014-06-25 10:33:03 +04:00
// Check the current XHR state to see if it is valid to obtain the statusText
// value. This check is to prevent the status text for redirects from being
// available before all the redirects have been followed and HTTP headers have
// been received.
2014-09-04 23:26:58 +04:00
uint16_t readyState = ReadyState ( ) ;
if ( readyState = = UNSENT | | readyState = = OPENED ) {
return ;
2014-06-25 10:33:03 +04:00
}
2014-09-04 23:26:58 +04:00
if ( mErrorLoad ) {
return ;
}
2013-06-13 09:20:10 +04:00
2014-09-04 23:26:58 +04:00
nsCOMPtr < nsIHttpChannel > httpChannel = GetCurrentHttpChannel ( ) ;
if ( httpChannel ) {
httpChannel - > GetResponseStatusText ( aStatusText ) ;
} else {
aStatusText . AssignLiteral ( " OK " ) ;
}
2006-04-20 07:36:50 +04:00
}
2012-01-26 14:02:22 +04:00
void
2016-07-16 20:56:36 +03:00
XMLHttpRequestMainThread : : CloseRequest ( )
2006-04-20 07:36:50 +04:00
{
2006-04-20 07:37:51 +04:00
if ( mChannel ) {
mChannel - > Cancel ( NS_BINDING_ABORTED ) ;
2006-04-20 07:36:50 +04:00
}
2012-01-26 14:02:22 +04:00
if ( mTimeoutTimer ) {
mTimeoutTimer - > Cancel ( ) ;
}
2016-07-16 20:56:36 +03:00
}
void
XMLHttpRequestMainThread : : CloseRequestWithError ( const ProgressEventType aType )
{
CloseRequest ( ) ;
2011-09-24 05:57:22 +04:00
ResetResponse ( ) ;
2012-02-14 22:05:43 +04:00
// If we're in the destructor, don't risk dispatching an event.
2016-07-08 19:46:12 +03:00
if ( mFlagDeleted ) {
mFlagSyncLooping = false ;
2012-02-14 22:05:43 +04:00
return ;
2012-02-21 00:02:47 +04:00
}
2012-02-14 22:05:43 +04:00
2016-07-08 19:46:12 +03:00
if ( mState ! = State : : unsent & &
2016-07-08 19:50:19 +03:00
! ( mState = = State : : opened & & ! mFlagSend ) & &
2016-07-08 19:46:12 +03:00
mState ! = State : : done ) {
ChangeState ( State : : done , true ) ;
2006-04-20 07:38:26 +04:00
2016-07-08 19:46:12 +03:00
if ( ! mFlagSyncLooping ) {
2011-11-21 22:07:12 +04:00
if ( mUpload & & ! mUploadComplete ) {
mUploadComplete = true ;
2016-08-06 06:47:40 +03:00
DispatchProgressEvent ( mUpload , ProgressEventType : : progress , 0 , 0 ) ;
DispatchProgressEvent ( mUpload , aType , 0 , 0 ) ;
2011-11-21 22:07:12 +04:00
}
2016-08-06 06:47:40 +03:00
DispatchProgressEvent ( this , ProgressEventType : : progress , 0 , 0 ) ;
DispatchProgressEvent ( this , aType , 0 , 0 ) ;
2008-08-14 15:07:46 +04:00
}
}
2006-11-28 16:56:40 +03:00
// The ChangeState call above calls onreadystatechange handlers which
2016-06-27 20:13:41 +03:00
// if they load a new url will cause XMLHttpRequestMainThread::Open to clear
2006-11-28 16:56:40 +03:00
// the abort state bit. If this occurs we're not uninitialized (bug 361773).
2016-07-08 19:46:12 +03:00
if ( mFlagAborted ) {
ChangeState ( State : : unsent , false ) ; // IE seems to do it
2006-11-28 16:56:40 +03:00
}
2006-04-20 07:38:48 +04:00
2016-07-08 19:46:12 +03:00
mFlagSyncLooping = false ;
2012-01-26 14:02:22 +04:00
}
2008-08-25 21:21:28 +04:00
2012-03-26 19:38:06 +04:00
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : Abort ( ErrorResult & arv )
2012-01-26 14:02:22 +04:00
{
2016-07-08 19:46:12 +03:00
mFlagAborted = true ;
CloseRequestWithError ( ProgressEventType : : abort ) ;
2012-03-26 19:38:06 +04:00
}
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : SlowAbort ( )
2012-03-26 19:38:06 +04:00
{
Abort ( ) ;
2006-04-20 07:36:50 +04:00
return NS_OK ;
}
2013-01-11 02:47:43 +04: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
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : IsSafeHeader ( const nsACString & aHeader ,
NotNull < nsIHttpChannel * > aHttpChannel ) const
2013-01-11 02:47:43 +04:00
{
// See bug #380418. Hide "Set-Cookie" headers from non-chrome scripts.
2016-06-09 09:11:00 +03:00
if ( ! IsSystemXHR ( ) & & nsContentUtils : : IsForbiddenResponseHeader ( aHeader ) ) {
2013-01-11 02:47:43 +04:00
NS_WARNING ( " blocked access to response header " ) ;
return false ;
}
// if this is not a CORS call all headers are safe
2015-12-07 02:33:15 +03:00
if ( ! IsCrossSiteCORSRequest ( ) ) {
2013-01-11 02:47:43 +04:00
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 ;
}
2016-03-16 06:38:27 +03:00
}
2013-01-11 02:47:43 +04:00
const char * kCrossOriginSafeHeaders [ ] = {
" cache-control " , " content-language " , " content-type " , " expires " ,
" last-modified " , " pragma "
} ;
for ( uint32_t i = 0 ; i < ArrayLength ( kCrossOriginSafeHeaders ) ; + + i ) {
2016-06-09 09:11:00 +03:00
if ( aHeader . LowerCaseEqualsASCII ( kCrossOriginSafeHeaders [ i ] ) ) {
2013-01-11 02:47:43 +04:00
return true ;
}
}
nsAutoCString headerVal ;
// The "Access-Control-Expose-Headers" header contains a comma separated
// list of method names.
2016-06-09 09:11:00 +03:00
aHttpChannel - >
2013-01-11 02:47:43 +04:00
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 ;
}
2014-07-24 20:38:55 +04:00
if ( ! NS_IsValidHTTPToken ( token ) ) {
2013-01-11 02:47:43 +04:00
return false ;
}
2016-06-09 09:11:00 +03:00
if ( aHeader . Equals ( token , nsCaseInsensitiveCStringComparator ( ) ) ) {
2013-01-11 02:47:43 +04:00
isSafe = true ;
}
}
return isSafe ;
}
2016-06-27 20:13:41 +03:00
NS_IMETHODIMP
XMLHttpRequestMainThread : : GetAllResponseHeaders ( nsACString & aOut )
{
ErrorResult rv ;
GetAllResponseHeaders ( aOut , rv ) ;
return rv . StealNSResult ( ) ;
}
2012-03-26 19:38:06 +04:00
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetAllResponseHeaders ( nsACString & aResponseHeaders ,
ErrorResult & aRv )
2006-04-20 07:36:50 +04:00
{
2012-02-21 13:34:01 +04:00
aResponseHeaders . Truncate ( ) ;
2006-04-20 07:38:52 +04:00
2012-02-19 15:58:24 +04:00
// If the state is UNSENT or OPENED,
// return the empty string and terminate these steps.
2016-07-08 19:50:19 +03:00
if ( mState = = State : : unsent | | mState = = State : : opened ) {
2012-03-26 19:38:06 +04:00
return ;
2012-02-19 15:58:24 +04:00
}
2016-07-14 18:14:46 +03:00
if ( mErrorLoad ) {
return ;
}
2012-02-21 13:34:01 +04:00
if ( nsCOMPtr < nsIHttpChannel > httpChannel = GetCurrentHttpChannel ( ) ) {
2016-06-09 09:11:00 +03:00
RefPtr < nsHeaderVisitor > visitor =
new nsHeaderVisitor ( * this , WrapNotNull ( httpChannel ) ) ;
2012-02-21 13:34:01 +04:00
if ( NS_SUCCEEDED ( httpChannel - > VisitResponseHeaders ( visitor ) ) ) {
2013-06-13 09:20:10 +04:00
aResponseHeaders = visitor - > Headers ( ) ;
2012-02-19 15:58:24 +04:00
}
2012-03-26 19:38:06 +04:00
return ;
2010-11-12 00:39:14 +03:00
}
2012-02-19 15:58:24 +04:00
2012-02-21 13:34:01 +04:00
if ( ! mChannel ) {
2012-03-26 19:38:06 +04:00
return ;
2006-04-20 07:36:50 +04:00
}
2006-04-20 07:39:09 +04:00
2012-02-21 13:34:01 +04:00
// Even non-http channels supply content type.
2012-09-02 06:35:17 +04:00
nsAutoCString value ;
2012-02-21 13:34:01 +04:00
if ( NS_SUCCEEDED ( mChannel - > GetContentType ( value ) ) ) {
aResponseHeaders . AppendLiteral ( " Content-Type: " ) ;
2013-06-13 09:20:10 +04:00
aResponseHeaders . Append ( value ) ;
2012-03-26 19:38:06 +04:00
if ( NS_SUCCEEDED ( mChannel - > GetContentCharset ( value ) ) & & ! value . IsEmpty ( ) ) {
2012-02-21 13:34:01 +04:00
aResponseHeaders . AppendLiteral ( " ;charset= " ) ;
2013-06-13 09:20:10 +04:00
aResponseHeaders . Append ( value ) ;
2012-02-21 13:34:01 +04:00
}
2012-07-26 19:55:23 +04:00
aResponseHeaders . AppendLiteral ( " \r \n " ) ;
2012-02-21 13:34:01 +04:00
}
2012-08-28 03:34:29 +04:00
2016-06-29 02:22:16 +03:00
// Don't provide Content-Length for data URIs
nsCOMPtr < nsIURI > uri ;
bool isDataURI ;
if ( NS_FAILED ( mChannel - > GetURI ( getter_AddRefs ( uri ) ) ) | |
NS_FAILED ( uri - > SchemeIs ( " data " , & isDataURI ) ) | |
! isDataURI ) {
int64_t length ;
if ( NS_SUCCEEDED ( mChannel - > GetContentLength ( & length ) ) ) {
aResponseHeaders . AppendLiteral ( " Content-Length: " ) ;
aResponseHeaders . AppendInt ( length ) ;
aResponseHeaders . AppendLiteral ( " \r \n " ) ;
}
2012-08-28 03:34:29 +04:00
}
2006-04-20 07:36:50 +04:00
}
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetResponseHeader ( const nsACString & aHeader ,
nsACString & aResult )
2006-04-20 07:36:50 +04:00
{
2012-05-06 05:15:11 +04:00
ErrorResult rv ;
2012-03-26 19:38:06 +04:00
GetResponseHeader ( aHeader , aResult , rv ) ;
2015-04-27 16:18:51 +03:00
return rv . StealNSResult ( ) ;
2012-03-26 19:38:06 +04:00
}
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetResponseHeader ( const nsACString & header ,
nsACString & _retval , ErrorResult & aRv )
2012-03-26 19:38:06 +04:00
{
2011-10-17 18:59:28 +04:00
_retval . SetIsVoid ( true ) ;
2010-10-05 05:25:44 +04:00
nsCOMPtr < nsIHttpChannel > httpChannel = GetCurrentHttpChannel ( ) ;
if ( ! httpChannel ) {
2012-02-19 15:58:24 +04:00
// If the state is UNSENT or OPENED,
// return null and terminate these steps.
2016-07-08 19:50:19 +03:00
if ( mState = = State : : unsent | | mState = = State : : opened ) {
2012-03-26 19:38:06 +04:00
return ;
2012-02-19 15:58:24 +04:00
}
2012-08-28 03:34:29 +04:00
// Even non-http channels supply content type and content length.
2012-02-19 15:58:24 +04:00
// Remember we don't leak header information from denied cross-site
// requests.
nsresult status ;
if ( ! mChannel | |
NS_FAILED ( mChannel - > GetStatus ( & status ) ) | |
2012-08-28 03:34:29 +04:00
NS_FAILED ( status ) ) {
2012-03-26 19:38:06 +04:00
return ;
2012-02-19 15:58:24 +04:00
}
2012-08-28 03:34:29 +04: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 ( ) ) {
2014-05-22 07:48:51 +04:00
_retval . AppendLiteral ( " ;charset= " ) ;
2012-08-28 03:34:29 +04:00
_retval . Append ( value ) ;
}
2012-02-19 15:58:24 +04:00
}
2012-08-28 03:34:29 +04:00
// Content Length:
else if ( header . LowerCaseEqualsASCII ( " content-length " ) ) {
2012-10-22 21:51:07 +04:00
int64_t length ;
2012-08-28 03:34:29 +04:00
if ( NS_SUCCEEDED ( mChannel - > GetContentLength ( & length ) ) ) {
_retval . AppendInt ( length ) ;
}
2012-02-19 15:58:24 +04:00
}
2012-03-26 19:38:06 +04:00
return ;
2010-10-05 05:25:44 +04:00
}
2006-04-20 07:36:50 +04:00
2008-10-01 04:49:30 +04:00
// Check for dangerous headers
2016-06-09 09:11:00 +03:00
if ( ! IsSafeHeader ( header , WrapNotNull ( httpChannel ) ) ) {
2013-01-11 02:47:43 +04:00
return ;
2006-04-20 07:37:53 +04:00
}
2006-04-20 07:38:50 +04:00
2012-03-26 19:38:06 +04:00
aRv = httpChannel - > GetResponseHeader ( header , _retval ) ;
2015-04-27 16:18:52 +03:00
if ( aRv . ErrorCodeIs ( NS_ERROR_NOT_AVAILABLE ) ) {
2006-04-20 07:39:27 +04:00
// Means no header
2011-10-17 18:59:28 +04:00
_retval . SetIsVoid ( true ) ;
2015-04-27 16:18:52 +03:00
aRv . SuppressException ( ) ;
2006-04-20 07:39:27 +04:00
}
2006-04-20 07:36:50 +04:00
}
2011-08-24 21:46:53 +04:00
already_AddRefed < nsILoadGroup >
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetLoadGroup ( ) const
2008-10-15 04:12:28 +04:00
{
2016-07-08 19:46:12 +03:00
if ( mFlagBackgroundRequest ) {
2012-07-30 18:20:58 +04:00
return nullptr ;
2008-10-15 04:12:28 +04:00
}
2015-01-08 19:21:52 +03:00
if ( mLoadGroup ) {
nsCOMPtr < nsILoadGroup > ref = mLoadGroup ;
return ref . forget ( ) ;
}
2016-04-21 01:04:36 +03:00
nsIDocument * doc = GetDocumentIfCurrent ( ) ;
2008-10-15 04:12:28 +04:00
if ( doc ) {
2011-08-24 21:46:53 +04:00
return doc - > GetDocumentLoadGroup ( ) ;
2008-10-15 04:12:28 +04:00
}
2012-07-30 18:20:58 +04:00
return nullptr ;
2008-10-15 04:12:28 +04:00
}
2006-04-20 07:38:48 +04:00
nsresult
2016-07-08 19:50:48 +03:00
XMLHttpRequestMainThread : : FireReadystatechangeEvent ( )
2006-04-20 07:38:48 +04:00
{
2015-10-18 08:24:48 +03:00
RefPtr < Event > event = NS_NewDOMEvent ( this , nullptr , nullptr ) ;
2016-07-08 19:50:48 +03:00
event - > InitEvent ( kLiteralString_readystatechange , false , false ) ;
2008-08-14 15:07:46 +04:00
// We assume anyone who managed to call CreateReadystatechangeEvent is trusted
2016-07-08 19:50:48 +03:00
event - > SetTrusted ( true ) ;
DispatchDOMEvent ( nullptr , event , nullptr , nullptr ) ;
2006-04-20 07:38:48 +04:00
return NS_OK ;
}
2008-08-14 15:07:46 +04:00
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : DispatchProgressEvent ( DOMEventTargetHelper * aTarget ,
2016-07-08 19:44:33 +03:00
const ProgressEventType aType ,
2016-06-27 20:13:41 +03:00
int64_t aLoaded , int64_t aTotal )
2008-08-14 15:07:46 +04:00
{
2008-10-01 04:51:53 +04:00
NS_ASSERTION ( aTarget , " null target " ) ;
2011-09-24 05:57:22 +04:00
if ( NS_FAILED ( CheckInnerWindowCorrectness ( ) ) | |
2012-07-22 06:28:26 +04:00
( ! AllowUploadProgress ( ) & & aTarget = = mUpload ) ) {
2008-08-14 15:07:46 +04:00
return ;
}
2016-08-06 06:47:40 +03:00
// If blocked by CORS, zero-out the stats on progress events
// and never fire "progress" or "load" events at all.
if ( IsDeniedCrossSiteCORSRequest ( ) ) {
if ( aType = = ProgressEventType : : progress | |
aType = = ProgressEventType : : load ) {
return ;
}
aLoaded = 0 ;
aTotal = 0 ;
}
2016-08-04 04:58:17 +03:00
if ( aType = = ProgressEventType : : progress ) {
mInLoadProgressEvent = true ;
}
2014-06-04 02:52:36 +04:00
ProgressEventInit init ;
init . mBubbles = false ;
init . mCancelable = false ;
2016-08-06 06:47:40 +03:00
init . mLengthComputable = aTotal ! = 0 ; // XHR spec step 6.1
2014-06-04 02:52:36 +04:00
init . mLoaded = aLoaded ;
2015-01-08 22:48:52 +03:00
init . mTotal = ( aTotal = = - 1 ) ? 0 : aTotal ;
2008-08-14 15:07:46 +04:00
2016-07-08 19:44:33 +03:00
const nsAString & typeString = ProgressEventTypeStrings [ ( uint8_t ) aType ] ;
2015-10-18 08:24:48 +03:00
RefPtr < ProgressEvent > event =
2016-07-08 19:44:33 +03:00
ProgressEvent : : Constructor ( aTarget , typeString , init ) ;
2012-11-28 00:20:40 +04:00
event - > SetTrusted ( true ) ;
2012-07-30 18:20:58 +04:00
aTarget - > DispatchDOMEvent ( nullptr , event , nullptr , nullptr ) ;
2013-02-28 22:53:04 +04:00
2016-08-04 04:58:17 +03:00
if ( aType = = ProgressEventType : : progress ) {
mInLoadProgressEvent = false ;
// clear chunked responses after every progress event
if ( mResponseType = = XMLHttpRequestResponseType : : Moz_chunked_text | |
mResponseType = = XMLHttpRequestResponseType : : Moz_chunked_arraybuffer ) {
mResponseBody . Truncate ( ) ;
mResponseText . Truncate ( ) ;
mResultArrayBuffer = nullptr ;
mArrayBufferBuilder . reset ( ) ;
}
}
2016-07-08 19:44:33 +03:00
// If we're sending a load, error, timeout or abort event, then
// also dispatch the subsequent loadend event.
if ( aType = = ProgressEventType : : load | | aType = = ProgressEventType : : error | |
aType = = ProgressEventType : : timeout | | aType = = ProgressEventType : : abort ) {
2016-08-06 06:47:40 +03:00
DispatchProgressEvent ( aTarget , ProgressEventType : : loadend , aLoaded , aTotal ) ;
2011-03-24 16:22:03 +03:00
}
2008-08-14 15:07:46 +04:00
}
2016-03-16 06:38:27 +03:00
2006-04-20 07:38:52 +04:00
already_AddRefed < nsIHttpChannel >
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetCurrentHttpChannel ( )
2006-04-20 07:38:52 +04:00
{
2013-03-04 13:06:15 +04:00
nsCOMPtr < nsIHttpChannel > httpChannel = do_QueryInterface ( mChannel ) ;
2012-10-26 05:57:57 +04:00
return httpChannel . forget ( ) ;
}
2006-04-20 07:38:52 +04:00
2012-10-26 05:57:57 +04:00
already_AddRefed < nsIJARChannel >
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetCurrentJARChannel ( )
2012-10-26 05:57:57 +04:00
{
2013-03-04 13:06:15 +04:00
nsCOMPtr < nsIJARChannel > appChannel = do_QueryInterface ( mChannel ) ;
2012-10-26 05:57:57 +04:00
return appChannel . forget ( ) ;
2006-04-20 07:38:52 +04:00
}
2011-08-11 17:29:50 +04:00
bool
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : IsSystemXHR ( ) const
2011-08-11 17:29:50 +04:00
{
2012-06-07 22:28:33 +04:00
return mIsSystem | | nsContentUtils : : IsSystemPrincipal ( mPrincipal ) ;
2011-08-11 17:29:50 +04:00
}
2016-08-04 04:58:17 +03:00
bool
XMLHttpRequestMainThread : : InUploadPhase ( ) const
{
// We're in the upload phase while our state is State::opened.
return mState = = State : : opened ;
}
2011-08-11 17:29:50 +04:00
2006-04-20 07:38:50 +04:00
NS_IMETHODIMP
2016-07-20 20:02:36 +03:00
XMLHttpRequestMainThread : : Open ( const nsACString & aMethod , const nsACString & aUrl ,
bool aAsync , const nsAString & aUsername ,
const nsAString & aPassword , uint8_t optional_argc )
2006-04-20 07:36:50 +04:00
{
2016-07-20 20:02:36 +03:00
Optional < bool > async ;
2011-03-29 00:05:52 +04:00
if ( ! optional_argc ) {
// No optional arguments were passed in. Default async to true.
2016-07-20 20:02:36 +03:00
async . Construct ( ) = true ;
} else {
async . Construct ( ) = aAsync ;
2011-03-29 00:05:52 +04:00
}
2016-07-20 20:02:36 +03:00
Optional < nsAString > username ;
2012-05-30 07:45:18 +04:00
if ( optional_argc > 1 ) {
2016-07-20 20:02:36 +03:00
username = & aUsername ;
2012-05-30 07:45:18 +04:00
}
2016-07-20 20:02:36 +03:00
Optional < nsAString > password ;
2012-05-30 07:45:18 +04:00
if ( optional_argc > 2 ) {
2016-07-20 20:02:36 +03:00
password = & aPassword ;
2012-05-30 07:45:18 +04:00
}
2016-07-20 20:02:36 +03:00
return OpenInternal ( aMethod , aUrl , async , username , password ) ;
}
// This case is hit when the async parameter is outright omitted, which
// should set it to true (and the username and password to null).
void
XMLHttpRequestMainThread : : Open ( const nsACString & aMethod , const nsAString & aUrl ,
ErrorResult & aRv )
{
aRv = OpenInternal ( aMethod , NS_ConvertUTF16toUTF8 ( aUrl ) , Optional < bool > ( true ) ,
Optional < nsAString > ( ) , Optional < nsAString > ( ) ) ;
}
// This case is hit when the async parameter is specified, even if the
// JS value was "undefined" (which due to legacy reasons should be
// treated as true, which is how it will already be passed in here).
void
XMLHttpRequestMainThread : : Open ( const nsACString & aMethod ,
const nsAString & aUrl ,
bool aAsync ,
const Optional < nsAString > & aUsername ,
const Optional < nsAString > & aPassword ,
ErrorResult & aRv )
{
aRv = OpenInternal ( aMethod , NS_ConvertUTF16toUTF8 ( aUrl ) ,
Optional < bool > ( aAsync ) , aUsername , aPassword ) ;
2012-03-26 19:38:06 +04:00
}
nsresult
2016-07-20 20:02:36 +03:00
XMLHttpRequestMainThread : : OpenInternal ( const nsACString & aMethod ,
const nsACString & aUrl ,
const Optional < bool > & aAsync ,
const Optional < nsAString > & aUsername ,
const Optional < nsAString > & aPassword )
2012-03-26 19:38:06 +04:00
{
2016-07-20 20:02:36 +03:00
bool async = aAsync . WasPassed ( ) ? aAsync . Value ( ) : true ;
2012-03-26 19:38:06 +04:00
2016-07-20 20:02:36 +03:00
// Gecko-specific
2014-02-10 22:35:25 +04:00
if ( ! async & & ! DontWarnAboutSyncXHR ( ) & & GetOwner ( ) & &
GetOwner ( ) - > GetExtantDoc ( ) ) {
GetOwner ( ) - > GetExtantDoc ( ) - > WarnOnceAbout ( nsIDocument : : eSyncXMLHttpRequest ) ;
}
2016-07-20 20:02:36 +03:00
Telemetry : : Accumulate ( Telemetry : : XMLHTTPREQUEST_ASYNC_OR_SYNC , async ? 0 : 1 ) ;
2011-03-29 00:05:52 +04:00
2016-07-20 20:02:36 +03:00
// Step 1
nsCOMPtr < nsIDocument > responsibleDocument = GetDocumentIfCurrent ( ) ;
if ( ! responsibleDocument ) {
// This could be because we're no longer current or because we're in some
// non-window context...
nsresult rv = CheckInnerWindowCorrectness ( ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return NS_ERROR_DOM_INVALID_STATE_ERR ;
}
}
2008-02-20 02:12:23 +03:00
NS_ENSURE_TRUE ( mPrincipal , NS_ERROR_NOT_INITIALIZED ) ;
2016-07-20 20:02:36 +03:00
// Steps 2-4
2014-03-18 20:36:18 +04:00
nsAutoCString method ;
2016-07-20 20:02:36 +03:00
nsresult rv = FetchUtil : : GetValidRequestMethod ( aMethod , method ) ;
2015-09-11 21:26:33 +03:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
2006-04-20 07:39:38 +04:00
}
2016-07-20 20:02:36 +03:00
// Steps 5-6
2008-10-12 10:30:14 +04:00
nsCOMPtr < nsIURI > baseURI ;
2008-12-31 01:24:58 +03:00
if ( mBaseURI ) {
baseURI = mBaseURI ;
2016-07-20 20:02:36 +03:00
} else if ( responsibleDocument ) {
baseURI = responsibleDocument - > GetBaseURI ( ) ;
2008-12-31 01:24:58 +03:00
}
2016-07-20 20:02:36 +03:00
nsCOMPtr < nsIURI > parsedURL ;
rv = NS_NewURI ( getter_AddRefs ( parsedURL ) , aUrl , nullptr , baseURI ) ;
2016-04-03 15:33:04 +03:00
if ( NS_FAILED ( rv ) ) {
if ( rv = = NS_ERROR_MALFORMED_URI ) {
return NS_ERROR_DOM_SYNTAX_ERR ;
}
return rv ;
}
2016-07-18 08:38:03 +03:00
if ( NS_WARN_IF ( NS_FAILED ( CheckInnerWindowCorrectness ( ) ) ) ) {
return NS_ERROR_DOM_INVALID_STATE_ERR ;
}
2007-03-25 09:35:39 +04:00
2016-07-20 20:02:36 +03:00
// Step 7 is already done above.
// Note that the username and password are already passed in as null by Open()
// if the async parameter is omitted, so there's no need check again here.
2016-07-28 19:13:17 +03:00
2016-07-20 20:02:36 +03:00
// Step 8
if ( aAsync . WasPassed ( ) ) {
nsAutoCString host ;
parsedURL - > GetHost ( host ) ;
if ( ! host . IsEmpty ( ) ) {
nsAutoCString userpass ;
if ( aUsername . WasPassed ( ) ) {
CopyUTF16toUTF8 ( aUsername . Value ( ) , userpass ) ;
}
userpass . AppendLiteral ( " : " ) ;
if ( aPassword . WasPassed ( ) ) {
AppendUTF16toUTF8 ( aPassword . Value ( ) , userpass ) ;
}
parsedURL - > SetUserPass ( userpass ) ;
}
2016-07-21 21:56:01 +03:00
}
2016-07-21 07:14:28 +03:00
2016-07-20 20:02:36 +03:00
// Step 9
if ( ! async & & HasOrHasHadOwner ( ) & & ( mTimeoutMilliseconds | |
mResponseType ! = XMLHttpRequestResponseType : : _empty ) ) {
if ( mTimeoutMilliseconds ) {
LogMessage ( " TimeoutSyncXHRWarning " , GetOwner ( ) ) ;
}
if ( mResponseType ! = XMLHttpRequestResponseType : : _empty ) {
LogMessage ( " ResponseTypeSyncXHRWarning " , GetOwner ( ) ) ;
}
return NS_ERROR_DOM_INVALID_ACCESS_ERR ;
2016-07-28 19:13:17 +03:00
}
2016-07-21 21:56:01 +03:00
2016-07-20 20:02:36 +03:00
// Step 10
CloseRequest ( ) ;
2016-07-28 19:13:17 +03:00
2016-07-20 20:02:36 +03:00
// Step 11
// timeouts are handled without a flag
mFlagSend = false ;
mRequestMethod . Assign ( method ) ;
mRequestURL = parsedURL ;
mFlagSynchronous = ! async ;
mAuthorRequestHeaders . Clear ( ) ;
ResetResponse ( ) ;
2006-04-20 07:39:09 +04:00
2016-07-20 20:02:36 +03:00
// Gecko-specific
2016-07-08 19:46:12 +03:00
mFlagHadUploadListenersOnSend = false ;
2016-07-20 20:02:36 +03:00
mFlagAborted = false ;
mFlagTimedOut = false ;
2009-02-24 22:46:51 +03:00
2016-07-20 20:02:36 +03:00
rv = InitChannel ( ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2006-04-20 07:36:54 +04:00
2016-07-20 20:02:36 +03:00
// Step 12
2016-07-16 20:56:36 +03:00
if ( mState ! = State : : opened ) {
2016-07-20 20:02:36 +03:00
mState = State : : opened ;
FireReadystatechangeEvent ( ) ;
2016-07-16 20:56:36 +03:00
}
2006-04-20 07:36:54 +04:00
2015-10-19 21:14:54 +03:00
return NS_OK ;
2006-04-20 07:36:50 +04:00
}
2015-03-03 04:09:07 +03:00
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : PopulateNetworkInterfaceId ( )
2015-03-03 04:09:07 +03:00
{
if ( mNetworkInterfaceId . IsEmpty ( ) ) {
return ;
}
nsCOMPtr < nsIHttpChannelInternal > channel ( do_QueryInterface ( mChannel ) ) ;
if ( ! channel ) {
return ;
}
channel - > SetNetworkInterfaceId ( mNetworkInterfaceId ) ;
}
2006-04-20 07:37:08 +04:00
/*
2006-04-20 07:37:22 +04:00
* " Copy " from a stream .
2006-04-20 07:37:08 +04:00
*/
2016-08-12 10:36:22 +03:00
nsresult
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : StreamReaderFunc ( nsIInputStream * in ,
void * closure ,
const char * fromRawSegment ,
uint32_t toOffset ,
uint32_t count ,
uint32_t * writeCount )
{
XMLHttpRequestMainThread * xmlHttpRequest = static_cast < XMLHttpRequestMainThread * > ( closure ) ;
2006-04-20 07:37:22 +04:00
if ( ! xmlHttpRequest | | ! writeCount ) {
NS_WARNING ( " XMLHttpRequest cannot read from stream: no closure or writeCount " ) ;
2006-04-20 07:37:08 +04:00
return NS_ERROR_FAILURE ;
}
2012-01-30 14:33:59 +04:00
nsresult rv = NS_OK ;
2016-06-27 20:13:41 +03:00
if ( xmlHttpRequest - > mResponseType = = XMLHttpRequestResponseType : : Blob | |
xmlHttpRequest - > mResponseType = = XMLHttpRequestResponseType : : Moz_blob ) {
2015-05-12 15:09:51 +03:00
if ( ! xmlHttpRequest - > mDOMBlob ) {
2012-09-20 11:55:36 +04:00
if ( ! xmlHttpRequest - > mBlobSet ) {
xmlHttpRequest - > mBlobSet = new BlobSet ( ) ;
2012-01-30 14:33:59 +04:00
}
2012-09-20 11:55:36 +04:00
rv = xmlHttpRequest - > mBlobSet - > AppendVoidPtr ( fromRawSegment , count ) ;
2012-01-30 14:33:59 +04:00
}
// Clear the cache so that the blob size is updated.
2016-06-27 20:13:41 +03:00
if ( xmlHttpRequest - > mResponseType = = XMLHttpRequestResponseType : : Moz_blob ) {
2012-07-30 18:20:58 +04:00
xmlHttpRequest - > mResponseBlob = nullptr ;
2012-01-30 14:33:59 +04:00
}
2016-06-27 20:13:41 +03:00
} else if ( ( xmlHttpRequest - > mResponseType = = XMLHttpRequestResponseType : : Arraybuffer & &
2014-05-16 09:34:43 +04:00
! xmlHttpRequest - > mIsMappedArrayBuffer ) | |
2016-06-27 20:13:41 +03:00
xmlHttpRequest - > mResponseType = = XMLHttpRequestResponseType : : Moz_chunked_arraybuffer ) {
2013-04-27 23:25:24 +04:00
// get the initial capacity to something reasonable to avoid a bunch of reallocs right
// at the start
2013-05-15 22:42:10 +04:00
if ( xmlHttpRequest - > mArrayBufferBuilder . capacity ( ) = = 0 )
2013-04-27 23:25:24 +04: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 ) ;
2016-06-27 20:13:41 +03:00
} else if ( xmlHttpRequest - > mResponseType = = XMLHttpRequestResponseType : : _empty & &
2013-04-27 23:25:24 +04:00
xmlHttpRequest - > mResponseXML ) {
2011-05-11 03:18:55 +04:00
// Copy for our own use
2015-05-20 22:09:32 +03:00
if ( ! xmlHttpRequest - > mResponseBody . Append ( fromRawSegment , count , fallible ) ) {
2011-05-11 03:18:55 +04:00
return NS_ERROR_OUT_OF_MEMORY ;
}
2016-06-27 20:13:41 +03:00
} else if ( xmlHttpRequest - > mResponseType = = XMLHttpRequestResponseType : : _empty | |
xmlHttpRequest - > mResponseType = = XMLHttpRequestResponseType : : Text | |
xmlHttpRequest - > mResponseType = = XMLHttpRequestResponseType : : Json | |
xmlHttpRequest - > mResponseType = = XMLHttpRequestResponseType : : Moz_chunked_text ) {
2011-09-24 05:57:36 +04:00
NS_ASSERTION ( ! xmlHttpRequest - > mResponseXML ,
" We shouldn't be parsing a doc here " ) ;
xmlHttpRequest - > AppendToResponseText ( fromRawSegment , count ) ;
2011-05-11 03:18:55 +04:00
}
2006-04-20 07:37:08 +04:00
2016-07-08 19:46:12 +03:00
if ( xmlHttpRequest - > mFlagParseBody ) {
2006-04-20 07:37:59 +04:00
// Give the same data to the parser.
2006-04-20 07:37:22 +04:00
2006-04-20 07:37:59 +04:00
// We need to wrap the data in a new lightweight stream and pass that
// to the parser, because calling ReadSegments() recursively on the same
// stream is not supported.
2006-04-20 07:38:34 +04:00
nsCOMPtr < nsIInputStream > copyStream ;
rv = NS_NewByteInputStream ( getter_AddRefs ( copyStream ) , fromRawSegment , count ) ;
2006-04-20 07:37:22 +04:00
2009-06-15 14:11:04 +04:00
if ( NS_SUCCEEDED ( rv ) & & xmlHttpRequest - > mXMLParserStreamListener ) {
2006-04-20 07:38:34 +04:00
NS_ASSERTION ( copyStream , " NS_NewByteInputStream lied " ) ;
2006-04-20 07:39:41 +04:00
nsresult parsingResult = xmlHttpRequest - > mXMLParserStreamListener
2013-03-04 13:06:15 +04:00
- > OnDataAvailable ( xmlHttpRequest - > mChannel ,
2006-04-20 07:39:41 +04: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 ) ) {
2016-07-08 19:46:12 +03:00
xmlHttpRequest - > mFlagParseBody = false ;
2006-04-20 07:39:41 +04:00
}
2006-04-20 07:37:22 +04:00
}
}
2006-04-20 07:37:08 +04:00
2006-04-20 07:37:22 +04:00
if ( NS_SUCCEEDED ( rv ) ) {
* writeCount = count ;
} else {
* writeCount = 0 ;
}
2006-04-20 07:37:08 +04:00
return rv ;
}
2016-06-27 20:13:41 +03:00
bool XMLHttpRequestMainThread : : CreateDOMBlob ( nsIRequest * request )
2011-05-11 03:18:55 +04:00
{
nsCOMPtr < nsIFile > file ;
2012-11-27 15:48:15 +04:00
nsCOMPtr < nsIFileChannel > fc = do_QueryInterface ( request ) ;
if ( fc ) {
fc - > GetFile ( getter_AddRefs ( file ) ) ;
2011-05-11 03:18:55 +04:00
}
2011-07-01 01:42:15 +04:00
2012-11-27 15:48:15 +04:00
if ( ! file )
return false ;
nsAutoCString contentType ;
mChannel - > GetContentType ( contentType ) ;
2015-05-12 15:09:51 +03:00
mDOMBlob = File : : CreateFromFile ( GetOwner ( ) , file , EmptyString ( ) ,
2014-10-08 20:15:23 +04:00
NS_ConvertASCIItoUTF16 ( contentType ) ) ;
2014-06-26 20:47:44 +04:00
2012-11-27 15:48:15 +04:00
mBlobSet = nullptr ;
NS_ASSERTION ( mResponseBody . IsEmpty ( ) , " mResponseBody should be empty " ) ;
return true ;
2011-05-11 03:18:55 +04:00
}
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : OnDataAvailable ( nsIRequest * request ,
nsISupports * ctxt ,
nsIInputStream * inStr ,
uint64_t sourceOffset ,
uint32_t count )
2006-04-20 07:37:08 +04:00
{
2006-04-20 07:37:22 +04:00
NS_ENSURE_ARG_POINTER ( inStr ) ;
2006-04-20 07:37:08 +04:00
2015-02-10 01:34:50 +03:00
MOZ_ASSERT ( mContext . get ( ) = = ctxt , " start context different from OnDataAvailable context " ) ;
2006-04-20 07:37:08 +04:00
2011-10-26 16:52:19 +04:00
mProgressSinceLastProgressEvent = true ;
2011-10-28 18:05:07 +04:00
bool cancelable = false ;
2016-06-27 20:13:41 +03:00
if ( ( mResponseType = = XMLHttpRequestResponseType : : Blob | |
mResponseType = = XMLHttpRequestResponseType : : Moz_blob ) & & ! mDOMBlob ) {
2015-05-12 15:09:51 +03:00
cancelable = CreateDOMBlob ( request ) ;
2011-10-28 18:05:07 +04:00
// The nsIStreamListener contract mandates us
// to read from the stream before returning.
2011-05-11 03:18:55 +04:00
}
2012-08-22 19:56:38 +04:00
uint32_t totalRead ;
2016-06-27 20:13:41 +03:00
nsresult rv = inStr - > ReadSegments ( XMLHttpRequestMainThread : : StreamReaderFunc ,
2011-09-24 05:57:22 +04:00
( void * ) this , count , & totalRead ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2011-10-28 18:05:07 +04:00
if ( cancelable ) {
// We don't have to read from the local file for the blob response
2015-05-19 17:36:37 +03:00
ErrorResult error ;
mDataAvailable = mDOMBlob - > GetSize ( error ) ;
if ( NS_WARN_IF ( error . Failed ( ) ) ) {
return error . StealNSResult ( ) ;
}
2016-07-08 19:46:12 +03:00
ChangeState ( State : : loading ) ;
2011-10-28 18:05:07 +04:00
return request - > Cancel ( NS_OK ) ;
}
2014-07-24 09:47:00 +04:00
mDataAvailable + = totalRead ;
2011-09-24 05:57:22 +04:00
2016-07-08 19:46:12 +03:00
ChangeState ( State : : loading ) ;
2016-03-16 06:38:27 +03:00
2016-08-04 04:58:17 +03:00
if ( ! mFlagSynchronous & & ! mProgressTimerIsActive ) {
StartProgressEventTimer ( ) ;
}
2011-09-24 05:57:22 +04:00
return NS_OK ;
2006-04-20 07:37:08 +04:00
}
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : OnStartRequest ( nsIRequest * request , nsISupports * ctxt )
2006-04-20 07:37:08 +04:00
{
2016-06-27 20:13:41 +03:00
PROFILER_LABEL ( " XMLHttpRequestMainThread " , " OnStartRequest " ,
2014-05-24 01:12:29 +04:00
js : : ProfileEntry : : Category : : NETWORK ) ;
2008-10-20 01:26:37 +04:00
nsresult rv = NS_OK ;
2008-10-01 03:56:57 +04:00
if ( ! mFirstStartRequestSeen & & mRequestObserver ) {
2011-10-17 18:59:28 +04:00
mFirstStartRequestSeen = true ;
2008-10-01 03:56:57 +04:00
mRequestObserver - > OnStartRequest ( request , ctxt ) ;
}
2013-03-04 13:06:15 +04:00
if ( request ! = mChannel ) {
// Can this still happen?
2007-09-06 07:51:56 +04:00
return NS_OK ;
}
2006-04-20 07:38:48 +04:00
// Don't do anything if we have been aborted
2016-07-08 19:46:12 +03:00
if ( mState = = State : : unsent ) {
2006-04-20 07:38:48 +04:00
return NS_OK ;
2016-07-08 19:46:12 +03:00
}
2006-04-20 07:38:48 +04:00
2016-07-08 19:46:12 +03:00
/* Apparently, Abort() should set State::unsent. See bug 361773.
2012-01-26 14:02:22 +04:00
XHR2 spec says this is correct . */
2016-07-08 19:46:12 +03:00
if ( mFlagAborted ) {
2006-04-20 07:38:52 +04:00
NS_ERROR ( " Ugh, still getting data on an aborted XMLHttpRequest! " ) ;
return NS_ERROR_UNEXPECTED ;
}
2012-01-26 14:02:22 +04:00
// Don't do anything if we have timed out.
2016-07-08 19:46:12 +03:00
if ( mFlagTimedOut ) {
2012-01-26 14:02:22 +04:00
return NS_OK ;
}
2006-04-20 07:38:52 +04:00
nsCOMPtr < nsIChannel > channel ( do_QueryInterface ( request ) ) ;
NS_ENSURE_TRUE ( channel , NS_ERROR_UNEXPECTED ) ;
2011-09-24 05:57:22 +04:00
nsresult status ;
request - > GetStatus ( & status ) ;
mErrorLoad = mErrorLoad | | NS_FAILED ( status ) ;
2016-08-04 04:58:17 +03:00
// Upload phase is now over. If we were uploading anything,
// stop the timer and fire any final progress events.
2016-07-08 19:49:40 +03:00
if ( mUpload & & ! mUploadComplete & & ! mErrorLoad & & ! mFlagSynchronous ) {
2016-08-04 04:58:17 +03:00
StopProgressEventTimer ( ) ;
mUploadTransferred = mUploadTotal ;
if ( mProgressSinceLastProgressEvent ) {
DispatchProgressEvent ( mUpload , ProgressEventType : : progress ,
2016-08-06 06:47:40 +03:00
mUploadTransferred , mUploadTotal ) ;
2016-08-04 04:58:17 +03:00
mProgressSinceLastProgressEvent = false ;
2014-01-09 23:23:08 +04:00
}
2016-08-04 04:58:17 +03:00
2011-10-17 18:59:28 +04:00
mUploadComplete = true ;
2016-07-08 19:44:33 +03:00
DispatchProgressEvent ( mUpload , ProgressEventType : : load ,
2016-08-06 06:47:40 +03:00
mUploadTotal , mUploadTotal ) ;
2011-09-24 05:57:22 +04:00
}
2006-04-20 07:37:08 +04:00
mContext = ctxt ;
2016-07-08 19:46:12 +03:00
mFlagParseBody = true ;
ChangeState ( State : : headers_received ) ;
2011-05-11 03:18:55 +04:00
2011-09-24 05:57:22 +04:00
ResetResponse ( ) ;
2008-10-12 10:30:14 +04:00
2011-09-24 05:57:36 +04:00
if ( ! mOverrideMimeType . IsEmpty ( ) ) {
2012-03-26 19:38:06 +04:00
channel - > SetContentType ( NS_ConvertUTF16toUTF8 ( mOverrideMimeType ) ) ;
2011-09-24 05:57:36 +04:00
}
DetectCharset ( ) ;
2013-05-15 22:42:10 +04:00
// Set up arraybuffer
2016-06-27 20:13:41 +03:00
if ( mResponseType = = XMLHttpRequestResponseType : : Arraybuffer & &
NS_SUCCEEDED ( status ) ) {
2014-05-16 09:34:43 +04:00
if ( mIsMappedArrayBuffer ) {
nsCOMPtr < nsIJARChannel > jarChannel = do_QueryInterface ( channel ) ;
if ( jarChannel ) {
nsCOMPtr < nsIURI > uri ;
rv = channel - > GetURI ( getter_AddRefs ( uri ) ) ;
if ( NS_SUCCEEDED ( rv ) ) {
nsAutoCString file ;
nsAutoCString scheme ;
uri - > GetScheme ( scheme ) ;
if ( scheme . LowerCaseEqualsLiteral ( " app " ) ) {
uri - > GetPath ( file ) ;
// The actual file inside zip package has no leading slash.
file . Trim ( " / " , true , false , false ) ;
} else if ( scheme . LowerCaseEqualsLiteral ( " jar " ) ) {
nsCOMPtr < nsIJARURI > jarURI = do_QueryInterface ( uri ) ;
if ( jarURI ) {
jarURI - > GetJAREntry ( file ) ;
}
}
nsCOMPtr < nsIFile > jarFile ;
jarChannel - > GetJarFile ( getter_AddRefs ( jarFile ) ) ;
2015-03-11 03:00:01 +03:00
if ( ! jarFile ) {
2014-05-16 09:34:43 +04:00
mIsMappedArrayBuffer = false ;
} else {
2015-03-11 03:00:01 +03:00
rv = mArrayBufferBuilder . mapToFileInPackage ( file , jarFile ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
mIsMappedArrayBuffer = false ;
} else {
channel - > SetContentType ( NS_LITERAL_CSTRING ( " application/mem-mapped " ) ) ;
}
2014-05-16 09:34:43 +04:00
}
}
}
}
// If memory mapping failed, mIsMappedArrayBuffer would be set to false,
// and we want it fallback to the malloc way.
if ( ! mIsMappedArrayBuffer ) {
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 ) ) ;
}
2013-05-15 22:42:10 +04:00
}
}
2008-10-12 10:30:14 +04:00
// Set up responseXML
2016-06-27 20:13:41 +03:00
bool parseBody = mResponseType = = XMLHttpRequestResponseType : : _empty | |
mResponseType = = XMLHttpRequestResponseType : : Document ;
2006-04-20 07:39:44 +04:00
nsCOMPtr < nsIHttpChannel > httpChannel ( do_QueryInterface ( mChannel ) ) ;
2011-05-11 03:18:55 +04:00
if ( parseBody & & httpChannel ) {
2012-09-02 06:35:17 +04:00
nsAutoCString method ;
2006-04-20 07:39:44 +04:00
httpChannel - > GetRequestMethod ( method ) ;
parseBody = ! method . EqualsLiteral ( " HEAD " ) ;
}
2011-11-16 11:38:51 +04:00
mIsHtml = false ;
mWarnAboutSyncHtml = false ;
2006-04-20 07:39:44 +04:00
if ( parseBody & & NS_SUCCEEDED ( status ) ) {
2006-04-20 07:39:41 +04:00
// 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-02 06:35:17 +04:00
nsAutoCString type ;
2006-04-20 07:38:52 +04:00
channel - > GetContentType ( type ) ;
2016-06-27 20:13:41 +03:00
if ( ( mResponseType = = XMLHttpRequestResponseType : : Document ) & &
2011-11-24 19:28:12 +04:00
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.
2016-07-08 19:49:40 +03:00
if ( mFlagSynchronous ) {
2011-11-16 11:38:51 +04:00
// We don't make cool new features available in the bad synchronous
// mode. The synchronous mode is for legacy only.
mWarnAboutSyncHtml = true ;
2016-07-08 19:46:12 +03:00
mFlagParseBody = false ;
2011-11-16 11:38:51 +04:00
} else {
mIsHtml = true ;
}
2016-03-16 09:02:34 +03:00
} else if ( ! ( type . EqualsLiteral ( " text/xml " ) | |
type . EqualsLiteral ( " application/xml " ) | |
type . RFind ( " +xml " , true , - 1 , 4 ) ! = kNotFound ) ) {
// Follow https://xhr.spec.whatwg.org/
// If final MIME type is not null, text/html, text/xml, application/xml,
// or does not end in +xml, return null.
2016-07-08 19:46:12 +03:00
mFlagParseBody = false ;
2006-04-20 07:37:59 +04:00
}
} else {
2006-04-20 07:39:41 +04:00
// The request failed, so we shouldn't be parsing anyway
2016-07-08 19:46:12 +03:00
mFlagParseBody = false ;
2006-04-20 07:37:48 +04:00
}
2006-04-20 07:39:09 +04:00
2016-07-08 19:46:12 +03:00
if ( mFlagParseBody ) {
2008-10-12 10:30:14 +04:00
nsCOMPtr < nsIURI > baseURI , docURI ;
2013-09-25 01:56:52 +04:00
rv = mChannel - > GetURI ( getter_AddRefs ( docURI ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
baseURI = docURI ;
2016-04-21 01:04:36 +03:00
nsCOMPtr < nsIDocument > doc = GetDocumentIfCurrent ( ) ;
2013-09-25 01:56:52 +04:00
nsCOMPtr < nsIURI > chromeXHRDocURI , chromeXHRDocBaseURI ;
2008-10-12 10:30:14 +04:00
if ( doc ) {
2013-09-25 01:56:52 +04:00
chromeXHRDocURI = doc - > GetDocumentURI ( ) ;
chromeXHRDocBaseURI = doc - > GetBaseURI ( ) ;
2016-04-21 01:04:36 +03:00
} else {
// If we're no longer current, just kill the load, though it really should
// have been killed already.
2016-07-18 08:38:03 +03:00
if ( NS_WARN_IF ( NS_FAILED ( CheckInnerWindowCorrectness ( ) ) ) ) {
return NS_ERROR_DOM_INVALID_STATE_ERR ;
}
2008-10-12 10:30:14 +04:00
}
2014-09-23 02:34:26 +04:00
// Create an empty document from it.
2008-10-12 10:30:14 +04:00
const nsAString & emptyStr = EmptyString ( ) ;
2012-03-26 19:38:06 +04:00
nsCOMPtr < nsIDOMDocument > responseDoc ;
2014-04-01 10:13:50 +04:00
nsIGlobalObject * global = DOMEventTargetHelper : : GetParentObject ( ) ;
2014-09-23 02:34:26 +04:00
nsCOMPtr < nsIPrincipal > requestingPrincipal ;
rv = nsContentUtils : : GetSecurityManager ( ) - >
GetChannelResultPrincipal ( channel , getter_AddRefs ( requestingPrincipal ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2012-12-10 18:05:33 +04:00
rv = NS_NewDOMDocument ( getter_AddRefs ( responseDoc ) ,
emptyStr , emptyStr , nullptr , docURI ,
2014-09-23 02:34:26 +04:00
baseURI , requestingPrincipal , true , global ,
2012-12-10 18:05:33 +04:00
mIsHtml ? DocumentFlavorHTML :
DocumentFlavorLegacyGuess ) ;
2008-10-12 10:30:14 +04:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2012-03-26 19:38:06 +04:00
mResponseXML = do_QueryInterface ( responseDoc ) ;
2013-09-25 01:56:52 +04:00
mResponseXML - > SetChromeXHRDocURI ( chromeXHRDocURI ) ;
mResponseXML - > SetChromeXHRDocBaseURI ( chromeXHRDocBaseURI ) ;
2008-10-12 10:30:14 +04:00
2012-06-07 22:28:33 +04:00
if ( nsContentUtils : : IsSystemPrincipal ( mPrincipal ) ) {
2012-03-26 19:38:06 +04:00
mResponseXML - > ForceEnableXULXBL ( ) ;
2010-08-26 00:12:28 +04:00
}
2015-12-07 02:33:15 +03:00
nsCOMPtr < nsILoadInfo > loadInfo = mChannel - > GetLoadInfo ( ) ;
MOZ_ASSERT ( loadInfo ) ;
bool isCrossSite = loadInfo - > GetTainting ( ) ! = LoadTainting : : Basic ;
if ( isCrossSite ) {
2008-10-12 10:30:14 +04:00
nsCOMPtr < nsIHTMLDocument > htmlDoc = do_QueryInterface ( mResponseXML ) ;
if ( htmlDoc ) {
htmlDoc - > DisableCookieAccess ( ) ;
}
}
2006-04-20 07:38:37 +04:00
nsCOMPtr < nsIStreamListener > listener ;
nsCOMPtr < nsILoadGroup > loadGroup ;
2006-04-20 07:38:52 +04:00
channel - > GetLoadGroup ( getter_AddRefs ( loadGroup ) ) ;
2012-03-26 19:38:06 +04:00
rv = mResponseXML - > StartDocumentLoad ( kLoadAsData , channel , loadGroup ,
2012-07-30 18:20:58 +04:00
nullptr , getter_AddRefs ( listener ) ,
2015-12-07 02:33:15 +03:00
! isCrossSite ) ;
2006-04-20 07:38:37 +04:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2016-06-30 21:01:25 +03:00
// the spec requires the response document.referrer to be the empty string
mResponseXML - > SetReferrer ( NS_LITERAL_CSTRING ( " " ) ) ;
2006-04-20 07:38:37 +04:00
mXMLParserStreamListener = listener ;
2008-10-12 10:30:14 +04:00
rv = mXMLParserStreamListener - > OnStartRequest ( request , ctxt ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2006-04-20 07:38:37 +04:00
}
2006-04-20 07:39:09 +04:00
2016-08-04 04:58:17 +03:00
// Download phase beginning; start the progress event timer if necessary.
if ( NS_SUCCEEDED ( rv ) & & HasListenersFor ( nsGkAtoms : : onprogress ) ) {
2008-10-20 01:26:37 +04:00
StartProgressEventTimer ( ) ;
}
2006-04-20 07:38:37 +04:00
return NS_OK ;
2006-04-20 07:37:08 +04:00
}
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : OnStopRequest ( nsIRequest * request , nsISupports * ctxt , nsresult status )
2006-04-20 07:37:08 +04:00
{
2016-06-27 20:13:41 +03:00
PROFILER_LABEL ( " XMLHttpRequestMainThread " , " OnStopRequest " ,
2014-05-24 01:12:29 +04:00
js : : ProfileEntry : : Category : : NETWORK ) ;
2013-03-04 13:06:15 +04:00
if ( request ! = mChannel ) {
// Can this still happen?
2007-09-06 07:51:56 +04:00
return NS_OK ;
}
2012-02-16 20:45:25 +04:00
mWaitingForOnStopRequest = false ;
2013-03-04 13:06:15 +04:00
if ( mRequestObserver ) {
2008-11-27 09:16:37 +03:00
NS_ASSERTION ( mFirstStartRequestSeen , " Inconsistent state! " ) ;
2011-10-17 18:59:28 +04:00
mFirstStartRequestSeen = false ;
2008-11-27 09:16:37 +03:00
mRequestObserver - > OnStopRequest ( request , ctxt , status ) ;
}
2010-05-02 12:27:20 +04: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??
2016-07-08 19:46:12 +03:00
// State::unsent is for abort calls. See OnStartRequest above.
if ( mState = = State : : unsent | | mFlagTimedOut ) {
2010-05-02 12:27:20 +04:00
if ( mXMLParserStreamListener )
( void ) mXMLParserStreamListener - > OnStopRequest ( request , ctxt , status ) ;
2008-11-27 09:16:37 +03:00
return NS_OK ;
2010-05-02 12:27:20 +04:00
}
2008-11-27 09:16:37 +03:00
// Is this good enough here?
2016-07-08 19:46:12 +03:00
if ( mXMLParserStreamListener & & mFlagParseBody ) {
2011-06-14 11:53:08 +04:00
mXMLParserStreamListener - > OnStopRequest ( request , ctxt , status ) ;
2008-11-27 09:16:37 +03:00
}
2012-07-30 18:20:58 +04:00
mXMLParserStreamListener = nullptr ;
mContext = nullptr ;
2006-04-20 07:38:52 +04:00
2012-01-30 14:33:59 +04:00
if ( NS_SUCCEEDED ( status ) & &
2016-08-06 06:47:40 +03:00
( mResponseType = = XMLHttpRequestResponseType : : _empty | |
mResponseType = = XMLHttpRequestResponseType : : Text ) ) {
mLoadTotal = mResponseBody . Length ( ) ;
} else if ( NS_SUCCEEDED ( status ) & &
2016-06-27 20:13:41 +03:00
( mResponseType = = XMLHttpRequestResponseType : : Blob | |
mResponseType = = XMLHttpRequestResponseType : : Moz_blob ) ) {
2016-08-06 06:47:40 +03:00
ErrorResult rv ;
2015-05-12 15:09:51 +03:00
if ( ! mDOMBlob ) {
CreateDOMBlob ( request ) ;
2011-05-11 03:18:55 +04:00
}
2015-05-12 15:09:51 +03:00
if ( mDOMBlob ) {
mResponseBlob = mDOMBlob ;
mDOMBlob = nullptr ;
2012-01-30 14:33:59 +04:00
} else {
2012-09-20 11:55:36 +04:00
// mBlobSet can be null if the channel is non-file non-cacheable
2012-09-18 02:42:36 +04:00
// and if the response length is zero.
2012-09-20 11:55:36 +04:00
if ( ! mBlobSet ) {
mBlobSet = new BlobSet ( ) ;
2012-09-18 02:42:36 +04:00
}
2011-05-11 03:18:55 +04: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-02 06:35:17 +04:00
nsAutoCString contentType ;
2011-05-11 03:18:55 +04:00
mChannel - > GetContentType ( contentType ) ;
2015-12-05 00:15:46 +03:00
mResponseBlob = mBlobSet - > GetBlobInternal ( GetOwner ( ) , contentType , rv ) ;
2012-09-20 11:55:36 +04:00
mBlobSet = nullptr ;
2015-12-05 00:15:46 +03:00
if ( NS_WARN_IF ( rv . Failed ( ) ) ) {
return rv . StealNSResult ( ) ;
}
2011-05-11 03:18:55 +04:00
}
2016-08-06 06:47:40 +03:00
mLoadTotal = mResponseBlob - > GetSize ( rv ) ;
if ( NS_WARN_IF ( rv . Failed ( ) ) ) {
status = rv . StealNSResult ( ) ;
}
2012-01-30 14:33:59 +04:00
NS_ASSERTION ( mResponseBody . IsEmpty ( ) , " mResponseBody should be empty " ) ;
NS_ASSERTION ( mResponseText . IsEmpty ( ) , " mResponseText should be empty " ) ;
2013-04-27 23:25:24 +04:00
} else if ( NS_SUCCEEDED ( status ) & &
2016-06-27 20:13:41 +03:00
( ( mResponseType = = XMLHttpRequestResponseType : : Arraybuffer & &
2014-05-16 09:34:43 +04:00
! mIsMappedArrayBuffer ) | |
2016-06-27 20:13:41 +03:00
mResponseType = = XMLHttpRequestResponseType : : Moz_chunked_arraybuffer ) ) {
2013-04-27 23:25:24 +04:00
// set the capacity down to the actual length, to realloc back
// down to the actual size
2016-08-06 06:47:40 +03:00
mLoadTotal = mArrayBufferBuilder . length ( ) ;
if ( ! mArrayBufferBuilder . setCapacity ( mLoadTotal ) ) {
2013-04-27 23:25:24 +04:00
// this should never happen!
status = NS_ERROR_UNEXPECTED ;
}
2011-05-11 03:18:55 +04:00
}
2012-01-30 14:33:59 +04:00
nsCOMPtr < nsIChannel > channel ( do_QueryInterface ( request ) ) ;
NS_ENSURE_TRUE ( channel , NS_ERROR_UNEXPECTED ) ;
2012-07-30 18:20:58 +04:00
channel - > SetNotificationCallbacks ( nullptr ) ;
mNotificationCallbacks = nullptr ;
mChannelEventSink = nullptr ;
mProgressEventSink = nullptr ;
2006-04-20 07:37:31 +04:00
2016-07-08 19:46:12 +03:00
mFlagSyncLooping = false ;
2011-11-16 23:50:48 +04:00
2006-04-20 07:38:10 +04:00
if ( NS_FAILED ( status ) ) {
2006-04-20 07:38:52 +04:00
// This can happen if the server is unreachable. Other possible
// reasons are that the user leaves the page or hits the ESC key.
2006-04-20 07:38:48 +04:00
2011-10-17 18:59:28 +04:00
mErrorLoad = true ;
2012-07-30 18:20:58 +04:00
mResponseXML = nullptr ;
2006-04-20 07:37:35 +04:00
}
2006-04-20 07:37:31 +04:00
2006-04-20 07:37:34 +04:00
// If we're uninitialized at this point, we encountered an error
2006-04-20 07:37:35 +04:00
// earlier and listeners have already been notified. Also we do
// not want to do this if we already completed.
2016-07-08 19:46:12 +03:00
if ( mState = = State : : unsent | | mState = = State : : done ) {
2006-04-20 07:37:34 +04:00
return NS_OK ;
}
2011-11-16 11:38:51 +04:00
if ( ! mResponseXML ) {
2016-08-06 06:47:40 +03:00
mFlagParseBody = false ;
2011-11-16 11:38:51 +04:00
ChangeStateToDone ( ) ;
return NS_OK ;
}
2016-08-06 06:47:40 +03:00
2011-11-16 11:38:51 +04:00
if ( mIsHtml ) {
2016-07-08 19:46:12 +03:00
NS_ASSERTION ( ! mFlagSyncLooping ,
2011-11-16 11:38:51 +04:00
" We weren't supposed to support HTML parsing with XHR! " ) ;
2013-04-06 04:44:26 +04:00
nsCOMPtr < EventTarget > eventTarget = do_QueryInterface ( mResponseXML ) ;
2014-03-17 10:56:53 +04:00
EventListenerManager * manager =
2013-10-23 03:32:04 +04:00
eventTarget - > GetOrCreateListenerManager ( ) ;
2011-11-16 11:38:51 +04:00
manager - > AddEventListenerByType ( new nsXHRParseEndListener ( this ) ,
2016-07-08 19:44:33 +03:00
kLiteralString_DOMContentLoaded ,
2014-03-17 10:56:52 +04:00
TrustedEventsAtSystemGroupBubble ( ) ) ;
2011-11-16 11:38:51 +04:00
return NS_OK ;
2016-08-06 06:47:40 +03:00
} else {
mFlagParseBody = false ;
2011-11-16 11:38:51 +04:00
}
2016-08-06 06:47:40 +03:00
2011-11-16 23:50:48 +04:00
// We might have been sent non-XML data. If that was the case,
// we should null out the document member. The idea in this
// check here is that if there is no document element it is not
// an XML document. We might need a fancier check...
2012-03-26 19:38:06 +04:00
if ( ! mResponseXML - > GetRootElement ( ) ) {
2012-07-30 18:20:58 +04:00
mResponseXML = nullptr ;
2006-04-20 07:37:31 +04:00
}
2011-11-16 11:38:51 +04:00
ChangeStateToDone ( ) ;
return NS_OK ;
}
2006-04-20 07:37:31 +04:00
2016-08-06 06:47:40 +03:00
void
XMLHttpRequestMainThread : : OnBodyParseEnd ( )
{
mFlagParseBody = false ;
ChangeStateToDone ( ) ;
}
2011-11-16 11:38:51 +04:00
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : ChangeStateToDone ( )
2011-11-16 11:38:51 +04:00
{
2016-08-04 04:58:17 +03:00
StopProgressEventTimer ( ) ;
MOZ_ASSERT ( ! mFlagParseBody ,
" ChangeStateToDone() called before async HTML parsing is done. " ) ;
2016-08-06 06:47:40 +03:00
mFlagSend = false ;
if ( mTimeoutTimer ) {
mTimeoutTimer - > Cancel ( ) ;
}
mLoadTotal = mLoadTransferred ;
// Per spec, fire the last download progress event, if any,
// before readystatechange=4/done. (Note that 0-sized responses
// will have not sent a progress event yet, so one must be sent here).
if ( ! mFlagSynchronous & &
( ! mLoadTransferred | | mProgressSinceLastProgressEvent ) ) {
2016-08-04 04:58:17 +03:00
DispatchProgressEvent ( this , ProgressEventType : : progress ,
2016-08-06 06:47:40 +03:00
mLoadTransferred , mLoadTotal ) ;
2016-08-04 04:58:17 +03:00
mProgressSinceLastProgressEvent = false ;
2011-11-16 11:38:51 +04:00
}
2012-01-26 14:02:22 +04:00
2016-08-06 06:47:40 +03:00
// Per spec, fire readystatechange=4/done before final error events.
2016-07-08 19:46:12 +03:00
ChangeState ( State : : done , true ) ;
2016-08-06 06:47:40 +03:00
// Per spec, if we failed in the upload phase, fire a final progress, error,
// and loadend event for the upload after readystatechange=4/done.
if ( ! mFlagSynchronous & & mUpload & & ! mUploadComplete ) {
DispatchProgressEvent ( mUpload , ProgressEventType : : progress , 0 , 0 ) ;
DispatchProgressEvent ( mUpload , ProgressEventType : : error , 0 , 0 ) ;
2012-01-26 14:02:22 +04:00
}
2006-04-20 07:39:23 +04:00
2016-08-06 06:47:40 +03:00
// Per spec, fire download's load/error and loadend events after
// readystatechange=4/done (and of course all upload events).
2008-08-14 15:07:46 +04:00
DispatchProgressEvent ( this ,
2016-08-06 06:47:40 +03:00
mErrorLoad ? ProgressEventType : : error :
ProgressEventType : : load ,
mErrorLoad ? 0 : mLoadTransferred ,
mErrorLoad ? 0 : mLoadTotal ) ;
2006-04-20 07:38:52 +04:00
2011-06-14 11:53:08 +04: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 18:20:58 +04:00
mChannel = nullptr ;
2011-06-14 11:53:08 +04:00
}
2006-04-20 07:37:08 +04:00
}
2016-08-01 21:28:01 +03:00
template < > nsresult
XMLHttpRequestMainThread : : RequestBody < nsIDocument > : : GetAsStream (
nsIInputStream * * aResult , uint64_t * aContentLength ,
nsACString & aContentType , nsACString & aCharset ) const
2012-03-26 19:38:06 +04:00
{
2016-08-01 21:28:01 +03:00
nsCOMPtr < nsIDOMDocument > domdoc ( do_QueryInterface ( mBody ) ) ;
NS_ENSURE_STATE ( domdoc ) ;
2014-12-18 11:50:34 +03:00
aCharset . AssignLiteral ( " UTF-8 " ) ;
2012-03-26 19:38:06 +04:00
nsresult rv ;
nsCOMPtr < nsIStorageStream > storStream ;
2012-09-28 10:57:33 +04:00
rv = NS_NewStorageStream ( 4096 , UINT32_MAX , getter_AddRefs ( storStream ) ) ;
2012-03-26 19:38:06 +04:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
nsCOMPtr < nsIOutputStream > output ;
rv = storStream - > GetOutputStream ( 0 , getter_AddRefs ( output ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2016-08-01 21:28:01 +03:00
if ( mBody - > IsHTMLDocument ( ) ) {
2015-09-23 20:31:33 +03:00
aContentType . AssignLiteral ( " text/html " ) ;
nsString serialized ;
2016-08-01 21:28:01 +03:00
if ( ! nsContentUtils : : SerializeNodeToMarkup ( mBody , true , serialized ) ) {
2015-09-23 20:31:33 +03:00
return NS_ERROR_OUT_OF_MEMORY ;
}
NS_ConvertUTF16toUTF8 utf8Serialized ( serialized ) ;
uint32_t written ;
rv = output - > Write ( utf8Serialized . get ( ) , utf8Serialized . Length ( ) , & written ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
MOZ_ASSERT ( written = = utf8Serialized . Length ( ) ) ;
} else {
aContentType . AssignLiteral ( " application/xml " ) ;
nsCOMPtr < nsIDOMSerializer > serializer =
do_CreateInstance ( NS_XMLSERIALIZER_CONTRACTID , & rv ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
// Make sure to use the encoding we'll send
2016-08-01 21:28:01 +03:00
rv = serializer - > SerializeToStream ( domdoc , output , aCharset ) ;
2015-09-23 20:31:33 +03:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
}
2007-07-25 08:53:21 +04:00
2012-03-26 19:38:06 +04:00
output - > Close ( ) ;
2012-09-20 02:15:32 +04:00
uint32_t length ;
rv = storStream - > GetLength ( & length ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
* aContentLength = length ;
2016-08-01 21:28:01 +03:00
rv = storStream - > NewInputStream ( 0 , aResult ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
return NS_OK ;
2007-07-25 08:53:21 +04:00
}
2016-08-01 21:28:01 +03:00
template < > nsresult
XMLHttpRequestMainThread : : RequestBody < const nsAString > : : GetAsStream (
nsIInputStream * * aResult , uint64_t * aContentLength ,
nsACString & aContentType , nsACString & aCharset ) const
2010-02-25 08:58:17 +03:00
{
aContentType . AssignLiteral ( " text/plain " ) ;
aCharset . AssignLiteral ( " UTF-8 " ) ;
2016-08-01 21:28:01 +03:00
nsCString converted = NS_ConvertUTF16toUTF8 ( * mBody ) ;
2012-09-20 02:15:32 +04:00
* aContentLength = converted . Length ( ) ;
2016-08-01 21:28:01 +03:00
nsresult rv = NS_NewCStringInputStream ( aResult , converted ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
return NS_OK ;
2012-03-26 19:38:06 +04:00
}
2016-08-01 21:28:01 +03:00
template < > nsresult
XMLHttpRequestMainThread : : RequestBody < nsIInputStream > : : GetAsStream (
nsIInputStream * * aResult , uint64_t * aContentLength ,
nsACString & aContentType , nsACString & aCharset ) const
2012-03-26 19:38:06 +04:00
{
aContentType . AssignLiteral ( " text/plain " ) ;
aCharset . Truncate ( ) ;
2016-08-01 21:28:01 +03:00
nsresult rv = mBody - > Available ( aContentLength ) ;
2012-09-20 02:15:32 +04:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2016-08-01 21:28:01 +03:00
nsCOMPtr < nsIInputStream > stream ( mBody ) ;
stream . forget ( aResult ) ;
2016-07-28 19:13:13 +03:00
return NS_OK ;
2016-07-21 07:36:26 +03:00
}
2016-08-01 21:28:01 +03:00
template < > nsresult
XMLHttpRequestMainThread : : RequestBody < Blob > : : GetAsStream (
nsIInputStream * * aResult , uint64_t * aContentLength ,
nsACString & aContentType , nsACString & aCharset ) const
2016-07-21 07:36:26 +03:00
{
2016-08-01 21:28:01 +03:00
return mBody - > GetSendInfo ( aResult , aContentLength , aContentType , aCharset ) ;
2016-07-21 07:36:26 +03:00
}
2016-08-01 21:28:01 +03:00
template < > nsresult
XMLHttpRequestMainThread : : RequestBody < FormData > : : GetAsStream (
nsIInputStream * * aResult , uint64_t * aContentLength ,
nsACString & aContentType , nsACString & aCharset ) const
{
return mBody - > GetSendInfo ( aResult , aContentLength , aContentType , aCharset ) ;
}
template < > nsresult
XMLHttpRequestMainThread : : RequestBody < URLSearchParams > : : GetAsStream (
nsIInputStream * * aResult , uint64_t * aContentLength ,
nsACString & aContentType , nsACString & aCharset ) const
2016-07-21 07:36:26 +03:00
{
2016-08-01 21:28:01 +03:00
return mBody - > GetSendInfo ( aResult , aContentLength , aContentType , aCharset ) ;
}
template < > nsresult
XMLHttpRequestMainThread : : RequestBody < nsIXHRSendable > : : GetAsStream (
nsIInputStream * * aResult , uint64_t * aContentLength ,
nsACString & aContentType , nsACString & aCharset ) const
{
return mBody - > GetSendInfo ( aResult , aContentLength , aContentType , aCharset ) ;
2012-03-26 19:38:06 +04:00
}
static nsresult
2016-08-01 21:28:01 +03:00
GetBufferDataAsStream ( const uint8_t * aData , uint32_t aDataLength ,
nsIInputStream * * aResult , uint64_t * aContentLength ,
nsACString & aContentType , nsACString & aCharset )
2012-03-26 19:38:06 +04:00
{
aContentType . SetIsVoid ( true ) ;
aCharset . Truncate ( ) ;
2012-12-20 05:47:39 +04:00
* aContentLength = aDataLength ;
const char * data = reinterpret_cast < const char * > ( aData ) ;
2012-03-26 19:38:06 +04:00
nsCOMPtr < nsIInputStream > stream ;
2012-12-20 05:47:39 +04:00
nsresult rv = NS_NewByteInputStream ( getter_AddRefs ( stream ) , data , aDataLength ,
2012-03-26 19:38:06 +04:00
NS_ASSIGNMENT_COPY ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
stream . forget ( aResult ) ;
return NS_OK ;
}
2016-08-01 21:28:01 +03:00
template < > nsresult
XMLHttpRequestMainThread : : RequestBody < const ArrayBuffer > : : GetAsStream (
nsIInputStream * * aResult , uint64_t * aContentLength ,
nsACString & aContentType , nsACString & aCharset ) const
{
mBody - > ComputeLengthAndData ( ) ;
return GetBufferDataAsStream ( mBody - > Data ( ) , mBody - > Length ( ) ,
aResult , aContentLength , aContentType , aCharset ) ;
}
template < > nsresult
XMLHttpRequestMainThread : : RequestBody < const ArrayBufferView > : : GetAsStream (
nsIInputStream * * aResult , uint64_t * aContentLength ,
nsACString & aContentType , nsACString & aCharset ) const
{
mBody - > ComputeLengthAndData ( ) ;
return GetBufferDataAsStream ( mBody - > Data ( ) , mBody - > Length ( ) ,
aResult , aContentLength , aContentType , aCharset ) ;
}
nsresult
XMLHttpRequestMainThread : : InitChannel ( )
{
// When we are called from JS we can find the load group for the page,
// and add ourselves to it. This way any pending requests
// will be automatically aborted if the user leaves the page.
nsCOMPtr < nsILoadGroup > loadGroup = GetLoadGroup ( ) ;
nsSecurityFlags secFlags ;
nsLoadFlags loadFlags = nsIRequest : : LOAD_BACKGROUND |
nsIChannel : : LOAD_CLASSIFY_URI ;
if ( nsContentUtils : : IsSystemPrincipal ( mPrincipal ) ) {
// When chrome is loading we want to make sure to sandbox any potential
// result document. We also want to allow cross-origin loads.
secFlags = nsILoadInfo : : SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL |
nsILoadInfo : : SEC_SANDBOXED ;
} else if ( IsSystemXHR ( ) ) {
// For pages that have appropriate permissions, we want to still allow
// cross-origin loads, but make sure that the any potential result
// documents get the same principal as the loader.
secFlags = nsILoadInfo : : SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS |
nsILoadInfo : : SEC_FORCE_INHERIT_PRINCIPAL ;
loadFlags | = nsIChannel : : LOAD_BYPASS_SERVICE_WORKER ;
} else {
// Otherwise use CORS. Again, make sure that potential result documents
// use the same principal as the loader.
secFlags = nsILoadInfo : : SEC_REQUIRE_CORS_DATA_INHERITS |
nsILoadInfo : : SEC_FORCE_INHERIT_PRINCIPAL ;
}
if ( mIsAnon ) {
secFlags | = nsILoadInfo : : SEC_COOKIES_OMIT ;
}
// Use the responsibleDocument if we have it, except for dedicated workers
// where it will be the parent document, which is not the one we want to use.
nsresult rv ;
nsCOMPtr < nsIDocument > responsibleDocument = GetDocumentIfCurrent ( ) ;
if ( responsibleDocument & & responsibleDocument - > NodePrincipal ( ) = = mPrincipal ) {
rv = NS_NewChannel ( getter_AddRefs ( mChannel ) ,
mRequestURL ,
responsibleDocument ,
secFlags ,
nsIContentPolicy : : TYPE_INTERNAL_XMLHTTPREQUEST ,
loadGroup ,
nullptr , // aCallbacks
loadFlags ) ;
} else {
// Otherwise use the principal.
rv = NS_NewChannel ( getter_AddRefs ( mChannel ) ,
mRequestURL ,
mPrincipal ,
secFlags ,
nsIContentPolicy : : TYPE_INTERNAL_XMLHTTPREQUEST ,
loadGroup ,
nullptr , // aCallbacks
loadFlags ) ;
}
NS_ENSURE_SUCCESS ( rv , rv ) ;
nsCOMPtr < nsIHttpChannel > httpChannel ( do_QueryInterface ( mChannel ) ) ;
if ( httpChannel ) {
rv = httpChannel - > SetRequestMethod ( mRequestMethod ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
// Set the initiator type
nsCOMPtr < nsITimedChannel > timedChannel ( do_QueryInterface ( httpChannel ) ) ;
if ( timedChannel ) {
timedChannel - > SetInitiatorType ( NS_LITERAL_STRING ( " xmlhttprequest " ) ) ;
}
}
return NS_OK ;
}
NS_IMETHODIMP
XMLHttpRequestMainThread : : Send ( nsIVariant * aVariant )
2012-03-26 19:38:06 +04:00
{
2016-08-01 21:28:01 +03:00
if ( ! aVariant ) {
return SendInternal ( nullptr ) ;
}
2012-03-26 19:38:06 +04:00
2012-08-22 19:56:38 +04:00
uint16_t dataType ;
2016-08-01 21:28:01 +03:00
nsresult rv = aVariant - > GetDataType ( & dataType ) ;
2010-02-25 08:58:17 +03:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
if ( dataType = = nsIDataType : : VTYPE_INTERFACE | |
dataType = = nsIDataType : : VTYPE_INTERFACE_IS ) {
nsCOMPtr < nsISupports > supports ;
nsID * iid ;
2016-08-01 21:28:01 +03:00
rv = aVariant - > GetAsInterface ( & iid , getter_AddRefs ( supports ) ) ;
2010-02-25 08:58:17 +03:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2015-03-27 03:01:12 +03:00
free ( iid ) ;
2010-02-25 08:58:17 +03:00
// document?
2016-08-01 21:28:01 +03:00
nsCOMPtr < nsIDocument > doc = do_QueryInterface ( supports ) ;
2010-02-25 08:58:17 +03:00
if ( doc ) {
2016-08-01 21:28:01 +03:00
RequestBody < nsIDocument > body ( doc ) ;
return SendInternal ( & body ) ;
2010-02-25 08:58:17 +03:00
}
// nsISupportsString?
nsCOMPtr < nsISupportsString > wstr = do_QueryInterface ( supports ) ;
if ( wstr ) {
nsAutoString string ;
wstr - > GetData ( string ) ;
2016-08-01 21:28:01 +03:00
RequestBody < const nsAString > body ( & string ) ;
return SendInternal ( & body ) ;
2010-02-25 08:58:17 +03:00
}
// nsIInputStream?
nsCOMPtr < nsIInputStream > stream = do_QueryInterface ( supports ) ;
if ( stream ) {
2016-08-01 21:28:01 +03:00
RequestBody < nsIInputStream > body ( stream ) ;
return SendInternal ( & body ) ;
2010-02-25 08:58:17 +03:00
}
2010-02-25 08:58:18 +03:00
// nsIXHRSendable?
nsCOMPtr < nsIXHRSendable > sendable = do_QueryInterface ( supports ) ;
if ( sendable ) {
2016-08-01 21:28:01 +03:00
RequestBody < nsIXHRSendable > body ( sendable ) ;
return SendInternal ( & body ) ;
2010-02-25 08:58:18 +03:00
}
2011-08-18 05:44:56 +04:00
// ArrayBuffer?
2016-08-11 15:39:23 +03:00
JS : : RootingContext * rootingCx = RootingCx ( ) ;
2016-03-18 17:48:38 +03:00
JS : : Rooted < JS : : Value > realVal ( rootingCx ) ;
2012-06-20 14:18:39 +04:00
2016-08-01 21:28:01 +03:00
nsresult rv = aVariant - > GetAsJSVal ( & realVal ) ;
2014-04-28 07:27:54 +04:00
if ( NS_SUCCEEDED ( rv ) & & ! realVal . isPrimitive ( ) ) {
2016-03-18 17:48:38 +03:00
JS : : Rooted < JSObject * > obj ( rootingCx , realVal . toObjectOrNull ( ) ) ;
RootedTypedArray < ArrayBuffer > buf ( rootingCx ) ;
2014-06-04 05:31:43 +04:00
if ( buf . Init ( obj ) ) {
2016-08-01 21:28:01 +03:00
RequestBody < const ArrayBuffer > body ( & buf ) ;
return SendInternal ( & body ) ;
2012-08-22 05:42:53 +04:00
}
2011-08-18 05:44:56 +04:00
}
2016-08-01 21:28:01 +03:00
} else if ( dataType = = nsIDataType : : VTYPE_VOID | |
2010-02-25 08:58:17 +03:00
dataType = = nsIDataType : : VTYPE_EMPTY ) {
2016-08-01 21:28:01 +03:00
return SendInternal ( nullptr ) ;
2010-02-25 08:58:17 +03:00
}
2014-01-04 19:02:17 +04:00
char16_t * data = nullptr ;
2012-08-22 19:56:38 +04:00
uint32_t len = 0 ;
2016-08-01 21:28:01 +03:00
rv = aVariant - > GetAsWStringWithSize ( & len , & data ) ;
2010-02-25 08:58:17 +03:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
nsString string ;
string . Adopt ( data , len ) ;
2016-08-01 21:28:01 +03:00
RequestBody < const nsAString > body ( & string ) ;
return SendInternal ( & body ) ;
2012-03-26 19:38:06 +04:00
}
nsresult
2016-08-01 21:28:01 +03:00
XMLHttpRequestMainThread : : SendInternal ( const RequestBodyBase * aBody )
2006-04-20 07:36:50 +04:00
{
2008-02-20 02:12:23 +03:00
NS_ENSURE_TRUE ( mPrincipal , NS_ERROR_NOT_INITIALIZED ) ;
2015-03-03 04:09:07 +03:00
PopulateNetworkInterfaceId ( ) ;
2007-12-12 11:33:32 +03:00
nsresult rv = CheckInnerWindowCorrectness ( ) ;
2016-07-18 08:38:03 +03:00
if ( NS_FAILED ( rv ) ) {
return NS_ERROR_DOM_INVALID_STATE_ERR ;
}
2006-04-20 07:38:48 +04:00
2016-07-08 19:50:19 +03:00
if ( mState ! = State : : opened | | // Step 1
mFlagSend | | // Step 2
! mChannel ) { // Gecko-specific
2016-02-27 05:15:56 +03:00
return NS_ERROR_DOM_INVALID_STATE_ERR ;
2006-04-20 07:36:50 +04:00
}
2010-09-08 21:42:08 +04:00
// nsIRequest::LOAD_BACKGROUND prevents throbber from becoming active, which
// in turn keeps STOP button from becoming active. If the consumer passed in
// a progress event handler we must load with nsIRequest::LOAD_NORMAL or
// necko won't generate any progress notifications.
2012-10-29 08:33:51 +04:00
if ( HasListenersFor ( nsGkAtoms : : onprogress ) | |
( mUpload & & mUpload - > HasListenersFor ( nsGkAtoms : : onprogress ) ) ) {
2010-09-08 21:42:08 +04:00
nsLoadFlags loadFlags ;
mChannel - > GetLoadFlags ( & loadFlags ) ;
loadFlags & = ~ nsIRequest : : LOAD_BACKGROUND ;
loadFlags | = nsIRequest : : LOAD_NORMAL ;
mChannel - > SetLoadFlags ( loadFlags ) ;
}
2006-04-20 07:38:26 +04:00
// XXX We should probably send a warning to the JS console
// if there are no event listeners set and we are doing
// an asynchronous call.
2006-04-20 07:38:50 +04:00
// Ignore argument if method is GET, there is no point in trying to
// upload anything
2012-09-02 06:35:17 +04:00
nsAutoCString method ;
2006-04-20 07:37:29 +04:00
nsCOMPtr < nsIHttpChannel > httpChannel ( do_QueryInterface ( mChannel ) ) ;
if ( httpChannel ) {
2016-08-02 19:50:10 +03:00
// Spec step 5
SetAuthorRequestHeadersOnChannel ( httpChannel ) ;
2008-10-15 04:12:28 +04:00
httpChannel - > GetRequestMethod ( method ) ; // If GET, method name will be uppercase
2006-07-07 02:10:04 +04:00
2011-03-17 19:19:13 +03:00
if ( ! IsSystemXHR ( ) ) {
2016-01-30 20:05:36 +03:00
nsCOMPtr < nsPIDOMWindowInner > owner = GetOwner ( ) ;
2015-06-05 00:05:00 +03:00
nsCOMPtr < nsIDocument > doc = owner ? owner - > GetExtantDoc ( ) : nullptr ;
nsContentUtils : : SetFetchReferrerURIWithPolicy ( mPrincipal , doc ,
2016-02-27 01:36:45 +03:00
httpChannel , mozilla : : net : : RP_Default ) ;
2008-03-13 14:43:06 +03:00
}
2009-11-19 02:21:13 +03:00
2016-08-04 19:33:36 +03:00
// If the user hasn't overridden the Accept header, set it to */* as per spec
nsAutoCString acceptHeader ;
GetAuthorRequestHeaderValue ( " accept " , acceptHeader ) ;
if ( acceptHeader . IsVoid ( ) ) {
httpChannel - > SetRequestHeader ( NS_LITERAL_CSTRING ( " Accept " ) ,
NS_LITERAL_CSTRING ( " */* " ) ,
false ) ;
}
2009-11-19 02:21:13 +03: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-19 03:22:25 +03: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-19 02:21:13 +03:00
}
}
2006-04-20 07:37:29 +04:00
}
2006-04-20 07:37:22 +04:00
2008-08-14 15:07:46 +04:00
mUploadTransferred = 0 ;
mUploadTotal = 0 ;
// By default we don't have any upload, so mark upload complete.
2011-10-17 18:59:28 +04:00
mUploadComplete = true ;
mErrorLoad = false ;
2008-10-20 01:26:37 +04:00
mLoadTotal = 0 ;
2016-08-01 21:28:01 +03:00
if ( aBody & & httpChannel & &
2013-05-15 15:48:59 +04:00
! method . LowerCaseEqualsLiteral ( " get " ) & &
! method . LowerCaseEqualsLiteral ( " head " ) ) {
2008-10-15 04:12:28 +04:00
2012-09-02 06:35:17 +04:00
nsAutoCString charset ;
nsAutoCString defaultContentType ;
2010-02-25 08:58:17 +03:00
nsCOMPtr < nsIInputStream > postDataStream ;
2008-10-15 04:12:28 +04:00
2015-01-08 22:48:52 +03:00
uint64_t size_u64 ;
2016-08-01 21:28:01 +03:00
rv = aBody - > GetAsStream ( getter_AddRefs ( postDataStream ) ,
& size_u64 , defaultContentType , charset ) ;
2010-02-25 08:58:17 +03:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2008-10-15 04:12:28 +04:00
2015-01-08 22:48:52 +03:00
// make sure it fits within js MAX_SAFE_INTEGER
mUploadTotal =
net : : InScriptableRange ( size_u64 ) ? static_cast < int64_t > ( size_u64 ) : - 1 ;
2008-10-15 04:12:28 +04:00
if ( postDataStream ) {
2016-08-01 21:28:01 +03:00
// If author set no Content-Type, use the default from GetAsStream().
2012-09-02 06:35:17 +04:00
nsAutoCString contentType ;
2016-08-02 19:50:10 +03:00
GetAuthorRequestHeaderValue ( " content-type " , contentType ) ;
if ( contentType . IsVoid ( ) ) {
2009-01-14 09:53:43 +03:00
contentType = defaultContentType ;
2015-08-29 00:13:46 +03:00
2016-08-02 19:50:10 +03:00
if ( ! charset . IsEmpty ( ) ) {
2015-08-29 00:13:46 +03:00
// If we are providing the default content type, then we also need to
// provide a charset declaration.
contentType . Append ( NS_LITERAL_CSTRING ( " ;charset= " ) ) ;
contentType . Append ( charset ) ;
}
2008-10-15 04:12:28 +04:00
}
// We don't want to set a charset for streams.
if ( ! charset . IsEmpty ( ) ) {
2012-09-02 06:35:17 +04:00
nsAutoCString specifiedCharset ;
2011-09-29 10:19:26 +04:00
bool haveCharset ;
2012-08-22 19:56:38 +04:00
int32_t charsetStart , charsetEnd ;
2008-10-15 04:12:28 +04:00
rv = NS_ExtractCharsetFromContentType ( contentType , specifiedCharset ,
& haveCharset , & charsetStart ,
& charsetEnd ) ;
2015-08-29 00:13:46 +03:00
while ( NS_SUCCEEDED ( rv ) & & haveCharset ) {
2011-11-30 02:06:32 +04: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-14 09:53:43 +03: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 ( ) ) ) {
2015-08-29 00:13:46 +03:00
// Find the start of the actual charset declaration, skipping the
// "; charset=" to avoid modifying whitespace.
int32_t charIdx =
Substring ( contentType , charsetStart ,
charsetEnd - charsetStart ) . FindChar ( ' = ' ) + 1 ;
MOZ_ASSERT ( charIdx ! = - 1 ) ;
contentType . Replace ( charsetStart + charIdx ,
charsetEnd - charsetStart - charIdx ,
charset ) ;
2009-01-14 09:53:43 +03:00
}
2015-08-29 00:13:46 +03:00
// Look for another charset declaration in the string, limiting the
// search to only look for charsets before the current charset, to
// prevent finding the same charset twice.
nsDependentCSubstring interestingSection =
Substring ( contentType , 0 , charsetStart ) ;
rv = NS_ExtractCharsetFromContentType ( interestingSection ,
specifiedCharset , & haveCharset ,
& charsetStart , & charsetEnd ) ;
2008-10-15 04:12:28 +04:00
}
}
2009-09-09 03:29:41 +04: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 ) ,
2016-03-16 06:38:27 +03:00
postDataStream ,
2009-09-09 03:29:41 +04:00
4096 ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
postDataStream = bufferedStream ;
}
2011-10-17 18:59:28 +04:00
mUploadComplete = false ;
2009-09-09 03:29:41 +04: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-19 02:21:13 +03:00
nsCOMPtr < nsIUploadChannel2 > uploadChannel2 ( do_QueryInterface ( httpChannel ) ) ;
// This assertion will fire if buggy extensions are installed
2010-10-05 04:41:07 +04:00
NS_ASSERTION ( uploadChannel2 , " http must support nsIUploadChannel2 " ) ;
2009-11-19 02:21:13 +03:00
if ( uploadChannel2 ) {
uploadChannel2 - > ExplicitSetUploadStream ( postDataStream , contentType ,
2012-09-20 02:15:32 +04:00
mUploadTotal , method , false ) ;
2009-11-19 02:21:13 +03: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-20 02:15:32 +04:00
uploadChannel - > SetUploadStream ( postDataStream , contentType , mUploadTotal ) ;
2009-11-19 02:21:13 +03:00
// Reset the method to its original value
httpChannel - > SetRequestMethod ( method ) ;
}
2008-10-15 04:12:28 +04:00
}
}
2008-10-15 01:05:41 +04:00
2011-09-24 05:57:22 +04:00
ResetResponse ( ) ;
2006-04-20 07:36:54 +04:00
2016-07-08 19:46:12 +03:00
if ( ! IsSystemXHR ( ) & & ! mIsAnon & & mFlagACwithCredentials ) {
2015-10-19 21:14:54 +03:00
// This is quite sad. We have to create the channel in .open(), since the
// chrome-only xhr.channel API depends on that. However .withCredentials
// can be modified after, so we don't know what to set the
2015-12-07 02:33:15 +03:00
// SEC_COOKIES_INCLUDE flag to when the channel is
2015-10-19 21:14:54 +03:00
// created. So set it here using a hacky internal API.
// Not doing this for system XHR uses since those don't use CORS.
nsCOMPtr < nsILoadInfo > loadInfo = mChannel - > GetLoadInfo ( ) ;
2016-06-27 03:47:00 +03:00
static_cast < net : : LoadInfo * > ( loadInfo . get ( ) ) - > SetIncludeCookiesSecFlag ( ) ;
2015-10-19 21:14:54 +03:00
}
2006-04-20 07:38:01 +04:00
2012-03-23 03:39:31 +04: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 ) ;
2014-12-06 22:26:50 +03:00
nsCOMPtr < nsIClassOfService > cos ( do_QueryInterface ( mChannel ) ) ;
if ( cos ) {
2012-12-05 03:06:29 +04:00
// 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.
2014-12-06 22:26:50 +03:00
cos - > AddClassFlags ( nsIClassOfService : : Unblocked ) ;
}
2013-12-19 03:03:48 +04:00
2014-12-06 22:26:50 +03:00
nsCOMPtr < nsIHttpChannelInternal >
internalHttpChannel ( do_QueryInterface ( mChannel ) ) ;
if ( internalHttpChannel ) {
2013-12-19 03:03:48 +04:00
// Disable Necko-internal response timeouts.
internalHttpChannel - > SetResponseTimeoutEnabled ( false ) ;
2012-12-05 03:06:29 +04:00
}
2015-12-07 02:33:15 +03:00
if ( ! mIsAnon ) {
2012-10-24 18:05:13 +04:00
AddLoadFlags ( mChannel , nsIChannel : : LOAD_EXPLICIT_CREDENTIALS ) ;
}
2012-06-07 22:28:33 +04:00
2016-02-16 11:34:00 +03:00
// Bypass the network cache in cases where it makes no sense:
// 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 " ) ) {
AddLoadFlags ( mChannel ,
nsICachingChannel : : LOAD_BYPASS_LOCAL_CACHE |
nsIRequest : : INHIBIT_CACHING ) ;
} else {
// 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).
//
// Also don't block on the cache entry on async if it is busy - favoring parallelism
// over cache hit rate for xhr. This does not disable the cache everywhere -
// only in cases where more than one channel for the same URI is accessed
// simultanously.
AddLoadFlags ( mChannel ,
nsICachingChannel : : LOAD_BYPASS_LOCAL_CACHE_IF_BUSY ) ;
}
2006-04-20 07:38:52 +04:00
2008-10-15 04:12:28 +04:00
// Since we expect XML data, set the type hint accordingly
2012-08-28 03:34:30 +04:00
// if the channel doesn't know any content type.
2008-10-15 04:12:28 +04:00
// This means that we always try to parse local files as XML
// ignoring return value, as this is not critical
2012-09-02 06:35:17 +04:00
nsAutoCString contentType ;
2012-08-28 03:34:30 +04:00
if ( NS_FAILED ( mChannel - > GetContentType ( contentType ) ) | |
contentType . IsEmpty ( ) | |
contentType . Equals ( UNKNOWN_CONTENT_TYPE ) ) {
mChannel - > SetContentType ( NS_LITERAL_CSTRING ( " application/xml " ) ) ;
}
2006-04-20 07:39:43 +04:00
2012-01-26 14:02:22 +04:00
// We're about to send the request. Start our timeout.
mRequestSentTime = PR_Now ( ) ;
StartTimeoutTimer ( ) ;
2015-12-07 02:33:14 +03:00
// Check if we should enabled cross-origin upload listeners.
if ( mUpload & & mUpload - > HasListeners ( ) ) {
2016-07-08 19:46:12 +03:00
mFlagHadUploadListenersOnSend = true ;
2015-10-19 21:14:54 +03:00
}
2011-03-29 00:11:09 +04:00
// Set up the preflight if needed
2015-12-07 02:33:14 +03:00
if ( ! IsSystemXHR ( ) ) {
2016-08-02 19:50:10 +03:00
nsTArray < nsCString > CORSUnsafeHeaders ;
const char * kCrossOriginSafeHeaders [ ] = {
" accept " , " accept-language " , " content-language " , " content-type " ,
" last-event-id "
} ;
for ( RequestHeader & header : mAuthorRequestHeaders ) {
bool safe = false ;
for ( uint32_t i = 0 ; i < ArrayLength ( kCrossOriginSafeHeaders ) ; + + i ) {
2016-08-10 02:43:26 +03:00
if ( header . name . LowerCaseEqualsASCII ( kCrossOriginSafeHeaders [ i ] ) ) {
2016-08-02 19:50:10 +03:00
safe = true ;
break ;
}
}
if ( ! safe ) {
CORSUnsafeHeaders . AppendElement ( header . name ) ;
}
}
2015-12-07 02:33:14 +03:00
nsCOMPtr < nsILoadInfo > loadInfo = mChannel - > GetLoadInfo ( ) ;
2016-08-02 19:50:10 +03:00
loadInfo - > SetCorsPreflightInfo ( CORSUnsafeHeaders ,
2016-07-08 19:46:12 +03:00
mFlagHadUploadListenersOnSend ) ;
2008-10-01 04:49:30 +04:00
}
2015-08-28 01:04:26 +03:00
mIsMappedArrayBuffer = false ;
2016-06-27 20:13:41 +03:00
if ( mResponseType = = XMLHttpRequestResponseType : : Arraybuffer & &
2016-06-30 15:32:13 +03:00
Preferences : : GetBool ( " dom.mapped_arraybuffer.enabled " , true ) ) {
2015-08-28 01:04:26 +03:00
nsCOMPtr < nsIURI > uri ;
nsAutoCString scheme ;
rv = mChannel - > GetURI ( getter_AddRefs ( uri ) ) ;
if ( NS_SUCCEEDED ( rv ) ) {
uri - > GetScheme ( scheme ) ;
if ( scheme . LowerCaseEqualsLiteral ( " app " ) | |
scheme . LowerCaseEqualsLiteral ( " jar " ) ) {
mIsMappedArrayBuffer = true ;
2014-05-16 09:34:43 +04:00
}
}
2008-10-01 04:49:30 +04:00
}
2006-04-20 07:36:54 +04:00
2015-10-19 21:14:54 +03:00
// Hook us up to listen to redirects and the like
// Only do this very late since this creates a cycle between
// the channel and us. This cycle has to be manually broken if anything
// below fails.
mChannel - > GetNotificationCallbacks ( getter_AddRefs ( mNotificationCallbacks ) ) ;
mChannel - > SetNotificationCallbacks ( this ) ;
2015-12-30 21:47:55 +03:00
if ( internalHttpChannel ) {
internalHttpChannel - > SetBlockAuthPrompt ( ShouldBlockAuthPrompt ( ) ) ;
}
2015-08-28 01:04:26 +03:00
// Start reading from the channel
2015-10-19 21:14:54 +03:00
// Because of bug 682305, we can't let listener be the XHR object itself
// because JS wouldn't be able to use it. So create a listener around 'this'.
// Make sure to hold a strong reference so that we don't leak the wrapper.
2016-06-27 03:47:00 +03:00
nsCOMPtr < nsIStreamListener > listener = new net : : nsStreamListenerWrapper ( this ) ;
2015-10-19 21:14:54 +03:00
rv = mChannel - > AsyncOpen2 ( listener ) ;
listener = nullptr ;
2015-08-28 01:04:26 +03:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
2015-10-19 21:14:54 +03:00
// Drop our ref to the channel to avoid cycles. Also drop channel's
// ref to us to be extra safe.
mChannel - > SetNotificationCallbacks ( mNotificationCallbacks ) ;
2012-07-30 18:20:58 +04:00
mChannel = nullptr ;
2015-10-19 21:14:54 +03:00
2016-07-30 07:24:56 +03:00
mErrorLoad = true ;
// Per spec, we throw on sync errors, but not async.
if ( mFlagSynchronous ) {
return rv ;
}
2006-04-20 07:39:09 +04:00
}
2006-04-20 07:36:54 +04:00
2012-02-16 20:45:25 +04:00
mWaitingForOnStopRequest = true ;
2016-07-28 19:13:13 +03:00
// Step 8
2016-07-08 19:50:19 +03:00
mFlagSend = true ;
2006-04-20 07:36:54 +04:00
// If we're synchronous, spin an event loop here and wait
2016-07-08 19:49:40 +03:00
if ( mFlagSynchronous ) {
2016-07-08 19:46:12 +03:00
mFlagSyncLooping = true ;
2009-02-17 23:07:39 +03:00
2009-03-03 23:11:14 +03:00
nsCOMPtr < nsIDocument > suspendedDoc ;
2009-02-17 23:07:39 +03:00
nsCOMPtr < nsIRunnable > resumeTimeoutRunnable ;
2012-03-13 04:56:07 +04:00
if ( GetOwner ( ) ) {
2016-01-30 20:05:36 +03:00
if ( nsCOMPtr < nsPIDOMWindowOuter > topWindow = GetOwner ( ) - > GetOuterWindow ( ) - > GetTop ( ) ) {
if ( nsCOMPtr < nsPIDOMWindowInner > topInner = topWindow - > GetCurrentInnerWindow ( ) ) {
2015-10-27 00:37:32 +03:00
suspendedDoc = topWindow - > GetExtantDoc ( ) ;
2009-03-03 23:11:14 +03:00
if ( suspendedDoc ) {
2014-02-27 03:58:21 +04:00
suspendedDoc - > SuppressEventHandling ( nsIDocument : : eEvents ) ;
2009-03-03 23:11:14 +03:00
}
2015-10-27 00:37:32 +03:00
topWindow - > SuspendTimeouts ( 1 , false ) ;
2016-01-30 20:05:36 +03:00
resumeTimeoutRunnable = new nsResumeTimeoutsEvent ( topInner ) ;
2009-02-17 23:07:39 +03:00
}
}
}
2016-08-04 04:58:17 +03:00
StopProgressEventTimer ( ) ;
2012-03-31 20:30:13 +04:00
{
nsAutoSyncOperation sync ( suspendedDoc ) ;
nsIThread * thread = NS_GetCurrentThread ( ) ;
2016-07-08 19:46:12 +03:00
while ( mFlagSyncLooping ) {
2012-03-31 20:30:13 +04:00
if ( ! NS_ProcessNextEvent ( thread ) ) {
rv = NS_ERROR_UNEXPECTED ;
break ;
}
2006-05-10 21:30:15 +04:00
}
2006-04-20 07:38:20 +04:00
}
2009-02-17 23:07:39 +03:00
2009-03-03 23:11:14 +03:00
if ( suspendedDoc ) {
2014-02-27 03:58:21 +04:00
suspendedDoc - > UnsuppressEventHandlingAndFireEvents ( nsIDocument : : eEvents ,
true ) ;
2009-03-03 23:11:14 +03:00
}
2009-02-17 23:07:39 +03:00
if ( resumeTimeoutRunnable ) {
NS_DispatchToCurrentThread ( resumeTimeoutRunnable ) ;
}
2008-08-14 15:07:46 +04:00
} else {
2010-09-17 13:30:35 +04: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.
2016-08-04 04:58:17 +03:00
StopProgressEventTimer ( ) ;
2016-07-08 19:50:19 +03:00
2016-08-04 04:58:17 +03:00
// Upload phase beginning; start the progress event timer if necessary.
2012-10-29 08:33:51 +04:00
if ( mUpload & & mUpload - > HasListenersFor ( nsGkAtoms : : onprogress ) ) {
2008-10-20 01:26:37 +04:00
StartProgressEventTimer ( ) ;
}
2016-08-06 06:47:40 +03:00
// Dispatch loadstart events
DispatchProgressEvent ( this , ProgressEventType : : loadstart , 0 , 0 ) ;
2008-08-14 15:07:46 +04:00
if ( mUpload & & ! mUploadComplete ) {
2016-08-06 06:47:40 +03:00
DispatchProgressEvent ( mUpload , ProgressEventType : : loadstart ,
2008-08-14 15:07:46 +04:00
0 , mUploadTotal ) ;
}
2006-04-20 07:36:50 +04:00
}
2006-04-20 07:38:52 +04:00
2006-04-20 07:38:23 +04:00
if ( ! mChannel ) {
2016-07-30 07:24:56 +03:00
// Per spec, silently fail on async request failures; throw for sync.
if ( mFlagSynchronous ) {
return NS_ERROR_FAILURE ;
} else {
// Defer the actual sending of async events just in case listeners
// are attached after the send() method is called.
NS_DispatchToCurrentThread (
NewRunnableMethod < ProgressEventType > ( this ,
& XMLHttpRequestMainThread : : CloseRequestWithError ,
ProgressEventType : : error ) ) ;
return NS_OK ;
}
2006-04-20 07:38:23 +04:00
}
2006-05-10 21:30:15 +04:00
return rv ;
2006-04-20 07:36:50 +04:00
}
2012-08-04 11:44:01 +04:00
// http://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-setrequestheader
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2016-08-02 19:50:10 +03:00
XMLHttpRequestMainThread : : SetRequestHeader ( const nsACString & aName ,
const nsACString & aValue )
2006-04-20 07:36:50 +04:00
{
2016-07-08 19:50:19 +03:00
// Steps 1 and 2
if ( mState ! = State : : opened | | mFlagSend ) {
2012-08-04 11:44:01 +04:00
return NS_ERROR_DOM_INVALID_STATE_ERR ;
}
2007-07-27 06:49:18 +04:00
2012-08-04 11:44:01 +04:00
// Step 3
2016-08-02 19:50:10 +03:00
nsAutoCString value ( aValue ) ;
static const char kHTTPWhitespace [ ] = " \n \t \r " ;
value . Trim ( kHTTPWhitespace ) ;
// Step 4
if ( ! NS_IsValidHTTPToken ( aName ) | | ! NS_IsReasonableHTTPHeaderValue ( value ) ) {
2012-08-04 11:44:01 +04:00
return NS_ERROR_DOM_SYNTAX_ERR ;
2008-10-01 04:50:42 +04:00
}
2016-08-02 19:50:10 +03:00
// Step 5
bool isPrivilegedCaller = IsSystemXHR ( ) ;
bool isForbiddenHeader = nsContentUtils : : IsForbiddenRequestHeader ( aName ) ;
if ( ! isPrivilegedCaller & & isForbiddenHeader ) {
NS_WARNING ( " refusing to set request header " ) ;
2007-07-31 04:42:16 +04:00
return NS_OK ;
}
2016-08-02 19:50:10 +03:00
// Step 6.1
2016-08-10 02:43:26 +03:00
// Skipping for now, as normalizing the case of header names may not be
// web-compatible. See bug 1285036.
2013-02-04 04:56:09 +04:00
2016-08-02 19:50:10 +03:00
// Step 6.2
bool notAlreadySet = true ;
2016-08-10 02:43:26 +03:00
const nsCaseInsensitiveCStringComparator ignoreCase ;
2016-08-02 19:50:10 +03:00
for ( RequestHeader & header : mAuthorRequestHeaders ) {
2016-08-10 02:43:26 +03:00
if ( header . name . Equals ( aName , ignoreCase ) ) {
2016-08-02 19:50:10 +03:00
// Gecko-specific: invalid headers can be set by privileged
// callers, but will not merge.
if ( isPrivilegedCaller & & isForbiddenHeader ) {
header . value . Assign ( value ) ;
} else {
header . value . AppendLiteral ( " , " ) ;
header . value . Append ( value ) ;
2016-07-28 19:13:43 +03:00
}
2016-08-02 19:50:10 +03:00
notAlreadySet = false ;
break ;
2016-07-21 21:56:01 +03:00
}
2016-07-21 07:14:41 +03:00
}
2016-07-20 19:22:43 +03:00
2016-08-02 19:50:10 +03:00
// Step 6.3
if ( notAlreadySet ) {
RequestHeader newHeader = {
2016-08-10 02:43:26 +03:00
nsCString ( aName ) , nsCString ( value )
2016-07-28 19:13:43 +03:00
} ;
2016-08-02 19:50:10 +03:00
mAuthorRequestHeaders . AppendElement ( newHeader ) ;
2016-07-28 19:13:43 +03:00
}
2016-08-02 19:50:10 +03:00
return NS_OK ;
2006-04-20 07:36:50 +04:00
}
2012-01-26 14:02:22 +04:00
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetTimeout ( uint32_t * aTimeout )
2012-01-26 14:02:22 +04:00
{
2012-09-11 23:08:24 +04:00
* aTimeout = Timeout ( ) ;
2012-01-26 14:02:22 +04:00
return NS_OK ;
}
2012-03-26 19:38:06 +04:00
2012-01-26 14:02:22 +04:00
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : SetTimeout ( uint32_t aTimeout )
2012-01-26 14:02:22 +04:00
{
2012-05-06 05:15:11 +04:00
ErrorResult rv ;
2012-03-26 19:38:06 +04:00
SetTimeout ( aTimeout , rv ) ;
2015-04-27 16:18:51 +03:00
return rv . StealNSResult ( ) ;
2012-03-26 19:38:06 +04:00
}
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : SetTimeout ( uint32_t aTimeout , ErrorResult & aRv )
2012-03-26 19:38:06 +04:00
{
2016-07-08 19:49:40 +03:00
if ( mFlagSynchronous & & mState ! = State : : unsent & & HasOrHasHadOwner ( ) ) {
2012-03-26 19:38:06 +04:00
/* Timeout is not supported for synchronous requests with an owning window,
per XHR2 spec . */
LogMessage ( " TimeoutSyncXHRWarning " , GetOwner ( ) ) ;
2012-05-06 05:15:11 +04:00
aRv . Throw ( NS_ERROR_DOM_INVALID_ACCESS_ERR ) ;
2012-03-26 19:38:06 +04:00
return ;
2012-01-26 14:02:22 +04:00
}
2012-03-26 19:38:06 +04:00
mTimeoutMilliseconds = aTimeout ;
if ( mRequestSentTime ) {
StartTimeoutTimer ( ) ;
}
2012-01-26 14:02:22 +04:00
}
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : StartTimeoutTimer ( )
2012-01-26 14:02:22 +04:00
{
2015-02-10 01:34:50 +03:00
MOZ_ASSERT ( mRequestSentTime ,
" StartTimeoutTimer mustn't be called before the request was sent! " ) ;
2016-07-08 19:46:12 +03:00
if ( mState = = State : : done ) {
2012-01-26 14:02:22 +04:00
// do nothing!
return ;
}
if ( mTimeoutTimer ) {
mTimeoutTimer - > Cancel ( ) ;
}
if ( ! mTimeoutMilliseconds ) {
return ;
}
if ( ! mTimeoutTimer ) {
mTimeoutTimer = do_CreateInstance ( NS_TIMER_CONTRACTID ) ;
}
2012-08-22 19:56:38 +04:00
uint32_t elapsed =
( uint32_t ) ( ( PR_Now ( ) - mRequestSentTime ) / PR_USEC_PER_MSEC ) ;
2012-01-26 14:02:22 +04:00
mTimeoutTimer - > InitWithCallback (
this ,
mTimeoutMilliseconds > elapsed ? mTimeoutMilliseconds - elapsed : 0 ,
nsITimer : : TYPE_ONE_SHOT
) ;
}
2006-04-20 07:39:09 +04:00
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetReadyState ( uint16_t * aState )
2006-04-20 07:37:31 +04:00
{
2012-09-11 23:08:24 +04:00
* aState = ReadyState ( ) ;
2012-03-26 19:38:06 +04:00
return NS_OK ;
}
uint16_t
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : ReadyState ( ) const
2012-03-26 19:38:06 +04:00
{
2006-04-20 07:37:35 +04:00
// Translate some of our internal states for external consumers
2016-07-08 19:50:19 +03:00
switch ( mState ) {
case State : : unsent :
return UNSENT ;
case State : : opened :
return OPENED ;
case State : : headers_received :
return HEADERS_RECEIVED ;
case State : : loading :
return LOADING ;
case State : : done :
return DONE ;
default :
MOZ_CRASH ( " Unknown state " ) ;
2016-07-08 04:57:49 +03:00
}
2016-07-08 19:50:19 +03:00
return 0 ;
2006-04-20 07:37:31 +04:00
}
2016-06-27 20:13:41 +03:00
void XMLHttpRequestMainThread : : OverrideMimeType ( const nsAString & aMimeType , ErrorResult & aRv )
2016-06-14 04:56:15 +03:00
{
2016-07-08 19:46:12 +03:00
if ( mState = = State : : loading | | mState = = State : : done ) {
2016-06-14 04:56:15 +03:00
ResetResponse ( ) ;
aRv . Throw ( NS_ERROR_DOM_INVALID_STATE_ERR ) ;
return ;
}
mOverrideMimeType = aMimeType ;
}
2006-04-20 07:37:48 +04:00
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : SlowOverrideMimeType ( const nsAString & aMimeType )
2006-04-20 07:37:48 +04:00
{
2016-06-14 04:56:15 +03:00
ErrorResult aRv ;
OverrideMimeType ( aMimeType , aRv ) ;
return aRv . StealNSResult ( ) ;
2006-04-20 07:37:48 +04:00
}
2008-03-19 03:14:38 +03:00
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetMozBackgroundRequest ( bool * _retval )
2008-03-19 03:14:38 +03:00
{
2012-09-11 23:08:24 +04:00
* _retval = MozBackgroundRequest ( ) ;
2008-03-19 03:14:38 +03:00
return NS_OK ;
}
2012-03-26 19:38:06 +04:00
bool
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : MozBackgroundRequest ( ) const
2012-03-26 19:38:06 +04:00
{
2016-07-08 19:46:12 +03:00
return mFlagBackgroundRequest ;
2012-03-26 19:38:06 +04:00
}
2008-03-19 03:14:38 +03:00
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : SetMozBackgroundRequest ( bool aMozBackgroundRequest )
2012-03-26 19:38:06 +04:00
{
2013-07-04 01:04:43 +04:00
if ( ! IsSystemXHR ( ) ) {
2016-06-27 20:13:41 +03:00
return NS_ERROR_DOM_SECURITY_ERR ;
2012-03-26 19:38:06 +04:00
}
2008-03-19 03:14:38 +03:00
2016-07-08 19:46:12 +03:00
if ( mState ! = State : : unsent ) {
2008-03-19 03:14:38 +03:00
// Can't change this while we're in the middle of something.
2016-06-27 20:13:41 +03:00
return NS_ERROR_IN_PROGRESS ;
2008-03-19 03:14:38 +03:00
}
2016-07-08 19:46:12 +03:00
mFlagBackgroundRequest = aMozBackgroundRequest ;
2016-06-27 20:13:41 +03:00
return NS_OK ;
}
void
XMLHttpRequestMainThread : : SetMozBackgroundRequest ( bool aMozBackgroundRequest ,
ErrorResult & aRv )
{
// No errors for this webIDL method on main-thread.
SetMozBackgroundRequest ( aMozBackgroundRequest ) ;
2008-03-19 03:14:38 +03:00
}
2008-10-01 04:52:52 +04:00
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetWithCredentials ( bool * _retval )
2008-10-01 04:52:52 +04:00
{
2012-09-11 23:08:24 +04:00
* _retval = WithCredentials ( ) ;
2008-10-01 04:52:52 +04:00
return NS_OK ;
}
2012-03-26 19:38:06 +04:00
bool
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : WithCredentials ( ) const
2012-03-26 19:38:06 +04:00
{
2016-07-08 19:46:12 +03:00
return mFlagACwithCredentials ;
2012-03-26 19:38:06 +04:00
}
2008-10-01 04:52:52 +04:00
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : SetWithCredentials ( bool aWithCredentials )
2012-03-26 19:38:06 +04:00
{
2012-11-28 00:20:40 +04:00
ErrorResult rv ;
2012-03-26 19:38:06 +04:00
SetWithCredentials ( aWithCredentials , rv ) ;
2015-04-27 16:18:51 +03:00
return rv . StealNSResult ( ) ;
2012-03-26 19:38:06 +04:00
}
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : SetWithCredentials ( bool aWithCredentials , ErrorResult & aRv )
2008-10-01 04:52:52 +04:00
{
2015-02-19 04:56:21 +03:00
// Return error if we're already processing a request. Note that we can't use
// ReadyState() here, because it can't differentiate between "opened" and
// "sent", so we use mState directly.
2016-07-08 19:50:19 +03:00
if ( ( mState ! = State : : unsent & & mState ! = State : : opened ) | |
mFlagSend | | mIsAnon ) {
2015-02-19 04:56:21 +03:00
aRv . Throw ( NS_ERROR_DOM_INVALID_STATE_ERR ) ;
2012-03-26 19:38:06 +04:00
return ;
2008-10-01 04:52:52 +04:00
}
2011-12-08 17:54:05 +04:00
2016-07-08 19:46:12 +03:00
mFlagACwithCredentials = aWithCredentials ;
2008-10-01 04:52:52 +04:00
}
2006-04-20 07:37:31 +04:00
nsresult
2016-07-08 19:46:12 +03:00
XMLHttpRequestMainThread : : ChangeState ( State aState , bool aBroadcast )
2006-04-20 07:37:31 +04:00
{
2016-07-08 19:46:12 +03:00
mState = aState ;
2006-04-20 07:37:31 +04:00
nsresult rv = NS_OK ;
2006-04-20 07:39:23 +04:00
2016-08-04 04:58:17 +03:00
if ( aState ! = State : : headers_received & & aState ! = State : : loading ) {
StopProgressEventTimer ( ) ;
2008-10-20 01:26:37 +04:00
}
2016-07-08 19:50:19 +03:00
if ( aBroadcast & & ( ! mFlagSynchronous | |
aState = = State : : opened | |
aState = = State : : done ) ) {
2016-07-08 19:50:48 +03:00
rv = FireReadystatechangeEvent ( ) ;
2006-04-20 07:37:31 +04:00
}
return rv ;
}
2006-04-20 07:38:01 +04:00
/////////////////////////////////////////////////////
2006-04-20 07:39:29 +04:00
// nsIChannelEventSink methods:
2006-04-20 07:38:01 +04:00
//
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : AsyncOnChannelRedirect ( nsIChannel * aOldChannel ,
nsIChannel * aNewChannel ,
uint32_t aFlags ,
nsIAsyncVerifyRedirectCallback * callback )
2006-04-20 07:38:01 +04:00
{
2006-04-20 07:39:29 +04:00
NS_PRECONDITION ( aNewChannel , " Redirect without a channel? " ) ;
2006-04-20 07:38:01 +04:00
2010-08-05 06:15:55 +04:00
// Prepare to receive callback
mRedirectCallback = callback ;
mNewRedirectChannel = aNewChannel ;
2006-04-20 07:39:34 +04:00
if ( mChannelEventSink ) {
2015-12-07 02:33:15 +03:00
nsCOMPtr < nsIAsyncVerifyRedirectCallback > fwd =
EnsureXPCOMifier ( ) ;
2010-08-05 06:15:55 +04:00
2015-12-07 02:33:15 +03:00
nsresult rv = mChannelEventSink - > AsyncOnChannelRedirect ( aOldChannel ,
aNewChannel ,
aFlags , fwd ) ;
2008-08-14 15:07:46 +04:00
if ( NS_FAILED ( rv ) ) {
2012-07-30 18:20:58 +04:00
mRedirectCallback = nullptr ;
mNewRedirectChannel = nullptr ;
2008-08-14 15:07:46 +04:00
}
2010-08-05 06:15:55 +04:00
return rv ;
2006-04-20 07:39:34 +04:00
}
2010-08-05 06:15:55 +04:00
OnRedirectVerifyCallback ( NS_OK ) ;
return NS_OK ;
}
2006-04-20 07:39:34 +04:00
2016-08-02 19:50:10 +03:00
void
XMLHttpRequestMainThread : : GetAuthorRequestHeaderValue ( const char * aName ,
nsACString & outValue )
{
for ( RequestHeader & header : mAuthorRequestHeaders ) {
2016-08-10 02:43:26 +03:00
if ( header . name . EqualsIgnoreCase ( aName ) ) {
2016-08-02 19:50:10 +03:00
outValue . Assign ( header . value ) ;
return ;
}
}
outValue . SetIsVoid ( true ) ;
}
void
XMLHttpRequestMainThread : : SetAuthorRequestHeadersOnChannel (
nsCOMPtr < nsIHttpChannel > aHttpChannel )
{
for ( RequestHeader & header : mAuthorRequestHeaders ) {
if ( header . value . IsEmpty ( ) ) {
aHttpChannel - > SetEmptyRequestHeader ( header . name ) ;
} else {
aHttpChannel - > SetRequestHeader ( header . name , header . value , false ) ;
}
}
}
2015-12-07 02:33:15 +03:00
nsresult
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : OnRedirectVerifyCallback ( nsresult result )
2010-08-05 06:15:55 +04:00
{
NS_ASSERTION ( mRedirectCallback , " mRedirectCallback not set in callback " ) ;
NS_ASSERTION ( mNewRedirectChannel , " mNewRedirectChannel not set in callback " ) ;
2007-07-27 06:49:18 +04:00
2010-03-22 04:52:35 +03:00
if ( NS_SUCCEEDED ( result ) ) {
2010-08-05 06:15:55 +04:00
mChannel = mNewRedirectChannel ;
2010-03-22 04:52:35 +03:00
nsCOMPtr < nsIHttpChannel > httpChannel ( do_QueryInterface ( mChannel ) ) ;
if ( httpChannel ) {
// Ensure all original headers are duplicated for the new channel (bug #553888)
2016-08-02 19:50:10 +03:00
SetAuthorRequestHeadersOnChannel ( httpChannel ) ;
2010-03-22 04:52:35 +03:00
}
} else {
2011-10-17 18:59:28 +04:00
mErrorLoad = true ;
2010-03-22 04:52:35 +03:00
}
2010-08-05 06:15:55 +04:00
2012-07-30 18:20:58 +04:00
mNewRedirectChannel = nullptr ;
2010-08-05 06:15:55 +04:00
mRedirectCallback - > OnRedirectVerifyCallback ( result ) ;
2012-07-30 18:20:58 +04:00
mRedirectCallback = nullptr ;
2015-12-07 02:33:15 +03:00
return result ;
2006-04-20 07:38:01 +04:00
}
2006-04-20 07:39:18 +04:00
/////////////////////////////////////////////////////
// nsIProgressEventSink methods:
//
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : OnProgress ( nsIRequest * aRequest , nsISupports * aContext , int64_t aProgress , int64_t aProgressMax )
2006-04-20 07:39:18 +04:00
{
2008-08-14 15:07:46 +04:00
// When uploading, OnProgress reports also headers in aProgress and aProgressMax.
// So, try to remove the headers, if possible.
2015-01-08 22:48:52 +03:00
bool lengthComputable = ( aProgressMax ! = - 1 ) ;
2016-08-04 04:58:17 +03:00
if ( InUploadPhase ( ) ) {
2015-01-08 22:48:52 +03:00
int64_t loaded = aProgress ;
2011-09-24 05:57:22 +04:00
if ( lengthComputable ) {
2015-01-08 22:48:52 +03:00
int64_t headerSize = aProgressMax - mUploadTotal ;
2014-07-28 19:19:51 +04:00
loaded - = headerSize ;
2008-08-14 15:07:46 +04:00
}
2014-07-28 19:19:51 +04:00
mUploadTransferred = loaded ;
2011-10-17 18:59:28 +04:00
mProgressSinceLastProgressEvent = true ;
2011-09-24 05:57:22 +04:00
2016-08-04 04:58:17 +03:00
if ( ! mFlagSynchronous & & ! mProgressTimerIsActive ) {
StartProgressEventTimer ( ) ;
}
2008-10-20 01:26:37 +04:00
} else {
2011-09-24 05:57:22 +04:00
mLoadTotal = lengthComputable ? aProgressMax : 0 ;
2014-07-24 09:47:00 +04:00
mLoadTransferred = aProgress ;
2016-08-04 04:58:17 +03:00
// OnDataAvailable() handles mProgressSinceLastProgressEvent
// for the download phase.
2008-08-14 15:07:46 +04:00
}
2006-04-20 07:39:18 +04:00
2006-04-20 07:39:34 +04:00
if ( mProgressEventSink ) {
mProgressEventSink - > OnProgress ( aRequest , aContext , aProgress ,
aProgressMax ) ;
}
2006-04-20 07:39:18 +04:00
return NS_OK ;
}
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : OnStatus ( nsIRequest * aRequest , nsISupports * aContext , nsresult aStatus , const char16_t * aStatusArg )
2006-04-20 07:39:18 +04:00
{
2006-04-20 07:39:34 +04:00
if ( mProgressEventSink ) {
mProgressEventSink - > OnStatus ( aRequest , aContext , aStatus , aStatusArg ) ;
}
2006-04-20 07:39:18 +04:00
return NS_OK ;
}
2011-09-29 10:19:26 +04:00
bool
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : AllowUploadProgress ( )
2008-10-01 04:51:53 +04:00
{
2015-12-07 02:33:15 +03:00
return ! IsCrossSiteCORSRequest ( ) | |
2016-07-08 19:46:12 +03:00
mFlagHadUploadListenersOnSend ;
2008-10-01 04:51:53 +04:00
}
2006-04-20 07:38:01 +04:00
/////////////////////////////////////////////////////
// nsIInterfaceRequestor methods:
//
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetInterface ( const nsIID & aIID , void * * aResult )
2006-04-20 07:38:01 +04:00
{
2008-04-09 04:27:50 +04:00
nsresult rv ;
2006-04-20 07:39:34 +04:00
// Make sure to return ourselves for the channel event sink interface and
// progress event sink interface, no matter what. We can forward these to
// mNotificationCallbacks if it wants to get notifications for them. But we
// need to see these notifications for proper functioning.
if ( aIID . Equals ( NS_GET_IID ( nsIChannelEventSink ) ) ) {
mChannelEventSink = do_GetInterface ( mNotificationCallbacks ) ;
2014-03-15 23:00:15 +04:00
* aResult = static_cast < nsIChannelEventSink * > ( EnsureXPCOMifier ( ) . take ( ) ) ;
2006-04-20 07:39:34 +04:00
return NS_OK ;
} else if ( aIID . Equals ( NS_GET_IID ( nsIProgressEventSink ) ) ) {
mProgressEventSink = do_GetInterface ( mNotificationCallbacks ) ;
2014-03-15 23:00:15 +04:00
* aResult = static_cast < nsIProgressEventSink * > ( EnsureXPCOMifier ( ) . take ( ) ) ;
2006-04-20 07:39:34 +04:00
return NS_OK ;
}
// Now give mNotificationCallbacks (if non-null) a chance to return the
2008-03-18 21:18:29 +03:00
// desired interface.
2006-04-20 07:39:34 +04:00
if ( mNotificationCallbacks ) {
2008-04-09 04:27:50 +04:00
rv = mNotificationCallbacks - > GetInterface ( aIID , aResult ) ;
2006-04-20 07:39:34 +04:00
if ( NS_SUCCEEDED ( rv ) ) {
NS_ASSERTION ( * aResult , " Lying nsIInterfaceRequestor implementation! " ) ;
return rv ;
}
}
2006-04-20 07:38:01 +04:00
2016-07-08 19:46:12 +03:00
if ( mFlagBackgroundRequest ) {
2008-03-19 03:14:38 +03:00
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-09 04:27:50 +04:00
else if ( aIID . Equals ( NS_GET_IID ( nsIAuthPrompt ) ) | |
aIID . Equals ( NS_GET_IID ( nsIAuthPrompt2 ) ) ) {
nsCOMPtr < nsIPromptFactory > wwatch =
do_GetService ( NS_WINDOWWATCHER_CONTRACTID , & rv ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
// Get the an auth prompter for our window so that the parenting
// of the dialogs works as it should when using tabs.
2016-01-30 20:05:36 +03:00
nsCOMPtr < nsPIDOMWindowOuter > window ;
2012-03-13 04:56:07 +04:00
if ( GetOwner ( ) ) {
window = GetOwner ( ) - > GetOuterWindow ( ) ;
2008-04-09 04:27:50 +04:00
}
return wwatch - > GetPrompt ( window , aIID ,
reinterpret_cast < void * * > ( aResult ) ) ;
2012-09-07 18:51:35 +04: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 ) ) ) {
2014-03-15 23:00:15 +04:00
* aResult = static_cast < nsIStreamListener * > ( EnsureXPCOMifier ( ) . take ( ) ) ;
2012-09-07 18:51:35 +04:00
return NS_OK ;
}
else if ( aIID . Equals ( NS_GET_IID ( nsIRequestObserver ) ) ) {
2014-03-15 23:00:15 +04:00
* aResult = static_cast < nsIRequestObserver * > ( EnsureXPCOMifier ( ) . take ( ) ) ;
2012-09-07 18:51:35 +04:00
return NS_OK ;
}
else if ( aIID . Equals ( NS_GET_IID ( nsITimerCallback ) ) ) {
2014-03-15 23:00:15 +04:00
* aResult = static_cast < nsITimerCallback * > ( EnsureXPCOMifier ( ) . take ( ) ) ;
2012-09-07 18:51:35 +04:00
return NS_OK ;
2008-04-09 04:27:50 +04:00
}
2008-03-19 03:14:38 +03:00
2006-04-20 07:38:01 +04:00
return QueryInterface ( aIID , aResult ) ;
}
2014-06-12 00:26:52 +04:00
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetInterface ( JSContext * aCx , nsIJSID * aIID ,
JS : : MutableHandle < JS : : Value > aRetval ,
ErrorResult & aRv )
2012-03-31 08:42:20 +04:00
{
2014-06-12 00:26:52 +04:00
dom : : GetInterface ( aCx , this , aIID , aRetval , aRv ) ;
2012-03-31 08:42:20 +04:00
}
2016-06-27 20:13:41 +03:00
XMLHttpRequestUpload *
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetUpload ( ErrorResult & aRv )
2008-08-14 15:04:43 +04:00
{
2008-08-14 15:07:46 +04:00
if ( ! mUpload ) {
2016-06-27 20:13:41 +03:00
mUpload = new XMLHttpRequestUpload ( this ) ;
2008-08-14 15:04:43 +04:00
}
2012-03-26 19:38:06 +04:00
return mUpload ;
}
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetUpload ( nsIXMLHttpRequestUpload * * aUpload )
2012-03-26 19:38:06 +04:00
{
2016-06-27 20:13:41 +03:00
ErrorResult rv ;
RefPtr < XMLHttpRequestUpload > upload = GetUpload ( rv ) ;
2012-03-26 19:38:06 +04:00
upload . forget ( aUpload ) ;
2016-06-27 20:13:41 +03:00
return rv . StealNSResult ( ) ;
2008-08-14 15:04:43 +04:00
}
2006-05-26 05:00:21 +04:00
2012-06-07 22:28:33 +04:00
bool
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : MozAnon ( ) const
2012-06-07 22:28:33 +04:00
{
return mIsAnon ;
}
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetMozAnon ( bool * aAnon )
2012-06-07 22:28:33 +04:00
{
2012-09-11 23:08:24 +04:00
* aAnon = MozAnon ( ) ;
2012-06-07 22:28:33 +04:00
return NS_OK ;
}
bool
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : MozSystem ( ) const
2012-06-07 22:28:33 +04:00
{
return IsSystemXHR ( ) ;
}
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : GetMozSystem ( bool * aSystem )
2012-06-07 22:28:33 +04:00
{
2012-09-11 23:08:24 +04:00
* aSystem = MozSystem ( ) ;
2012-06-07 22:28:33 +04:00
return NS_OK ;
}
2012-01-26 14:02:22 +04:00
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : HandleTimeoutCallback ( )
2012-01-26 14:02:22 +04:00
{
2016-07-08 19:46:12 +03:00
if ( mState = = State : : done ) {
2016-06-27 20:13:41 +03:00
NS_NOTREACHED ( " XMLHttpRequestMainThread::HandleTimeoutCallback with completed request " ) ;
2012-01-26 14:02:22 +04:00
// do nothing!
return ;
}
2016-07-08 19:46:12 +03:00
mFlagTimedOut = true ;
CloseRequestWithError ( ProgressEventType : : timeout ) ;
2012-01-26 14:02:22 +04:00
}
2008-10-20 01:26:37 +04:00
NS_IMETHODIMP
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : Notify ( nsITimer * aTimer )
2008-10-20 01:26:37 +04:00
{
2012-01-26 14:02:22 +04: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
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : HandleProgressTimerCallback ( )
2012-01-26 14:02:22 +04:00
{
mProgressTimerIsActive = false ;
2016-08-04 04:58:17 +03:00
if ( ! mProgressSinceLastProgressEvent | | mErrorLoad ) {
return ;
}
if ( InUploadPhase ( ) ) {
if ( mUpload & & ! mUploadComplete ) {
DispatchProgressEvent ( mUpload , ProgressEventType : : progress ,
2016-08-06 06:47:40 +03:00
mUploadTransferred , mUploadTotal ) ;
2016-08-04 04:58:17 +03:00
}
} else {
DispatchProgressEvent ( this , ProgressEventType : : progress ,
2016-08-06 06:47:40 +03:00
mLoadTransferred , mLoadTotal ) ;
2016-08-04 04:58:17 +03:00
}
mProgressSinceLastProgressEvent = false ;
StartProgressEventTimer ( ) ;
}
void
XMLHttpRequestMainThread : : StopProgressEventTimer ( )
{
if ( mProgressNotifier ) {
mProgressTimerIsActive = false ;
mProgressNotifier - > Cancel ( ) ;
}
2008-10-20 01:26:37 +04:00
}
void
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : StartProgressEventTimer ( )
2008-10-20 01:26:37 +04:00
{
if ( ! mProgressNotifier ) {
mProgressNotifier = do_CreateInstance ( NS_TIMER_CONTRACTID ) ;
}
if ( mProgressNotifier ) {
2012-01-26 14:02:22 +04:00
mProgressTimerIsActive = true ;
2008-10-20 01:26:37 +04:00
mProgressNotifier - > Cancel ( ) ;
mProgressNotifier - > InitWithCallback ( this , NS_PROGRESS_EVENT_INTERVAL ,
nsITimer : : TYPE_ONE_SHOT ) ;
}
}
2012-09-07 18:51:35 +04:00
already_AddRefed < nsXMLHttpRequestXPCOMifier >
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : EnsureXPCOMifier ( )
2012-09-07 18:51:35 +04:00
{
if ( ! mXPCOMifier ) {
mXPCOMifier = new nsXMLHttpRequestXPCOMifier ( this ) ;
}
2015-10-18 08:24:48 +03:00
RefPtr < nsXMLHttpRequestXPCOMifier > newRef ( mXPCOMifier ) ;
2012-09-07 18:51:35 +04:00
return newRef . forget ( ) ;
}
2015-12-30 21:47:55 +03:00
bool
2016-06-27 20:13:41 +03:00
XMLHttpRequestMainThread : : ShouldBlockAuthPrompt ( )
2015-12-30 21:47:55 +03:00
{
// Verify that it's ok to prompt for credentials here, per spec
// http://xhr.spec.whatwg.org/#the-send%28%29-method
2016-08-04 19:33:36 +03:00
nsAutoCString contentType ;
GetAuthorRequestHeaderValue ( " authorization " , contentType ) ;
if ( ! contentType . IsVoid ( ) ) {
return true ;
2015-12-30 21:47:55 +03:00
}
nsCOMPtr < nsIURI > uri ;
nsresult rv = mChannel - > GetURI ( getter_AddRefs ( uri ) ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return false ;
}
// Also skip if a username and/or password is provided in the URI.
nsCString username ;
rv = uri - > GetUsername ( username ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return false ;
}
nsCString password ;
rv = uri - > GetPassword ( password ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return false ;
}
if ( ! username . IsEmpty ( ) | | ! password . IsEmpty ( ) ) {
return true ;
}
return false ;
}
2016-06-27 20:13:41 +03:00
NS_IMPL_ISUPPORTS ( XMLHttpRequestMainThread : : nsHeaderVisitor , nsIHttpHeaderVisitor )
2006-04-20 07:37:18 +04:00
2016-06-27 20:13:41 +03:00
NS_IMETHODIMP XMLHttpRequestMainThread : :
2006-04-20 07:37:53 +04:00
nsHeaderVisitor : : VisitHeader ( const nsACString & header , const nsACString & value )
2006-04-20 07:37:18 +04:00
{
2016-06-09 09:11:00 +03:00
if ( mXHR . IsSafeHeader ( header , mHttpChannel ) ) {
2013-01-11 02:47:43 +04:00
mHeaders . Append ( header ) ;
2014-05-22 07:48:51 +04:00
mHeaders . AppendLiteral ( " : " ) ;
2013-01-11 02:47:43 +04:00
mHeaders . Append ( value ) ;
2014-05-22 07:48:51 +04:00
mHeaders . AppendLiteral ( " \r \n " ) ;
2013-01-11 02:47:43 +04:00
}
return NS_OK ;
2006-04-20 07:37:18 +04:00
}
2006-04-20 07:39:18 +04:00
2012-09-07 18:51:35 +04: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 )
2015-12-07 02:33:15 +03:00
NS_INTERFACE_MAP_ENTRY ( nsIAsyncVerifyRedirectCallback )
2012-09-07 18:51:35 +04:00
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 )
2014-04-25 20:49:00 +04:00
// Can't NS_IMPL_CYCLE_COLLECTION( because mXHR has ambiguous
2012-09-07 18:51:35 +04:00
// inheritance from nsISupports.
2013-08-02 05:29:05 +04:00
NS_IMPL_CYCLE_COLLECTION_CLASS ( nsXMLHttpRequestXPCOMifier )
2012-09-07 18:51:35 +04:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN ( nsXMLHttpRequestXPCOMifier )
if ( tmp - > mXHR ) {
tmp - > mXHR - > mXPCOMifier = nullptr ;
}
2012-11-15 11:32:40 +04:00
NS_IMPL_CYCLE_COLLECTION_UNLINK ( mXHR )
2012-09-07 18:51:35 +04:00
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN ( nsXMLHttpRequestXPCOMifier )
2012-11-15 11:32:40 +04:00
NS_IMPL_CYCLE_COLLECTION_TRAVERSE ( mXHR )
2012-09-07 18:51:35 +04: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-28 03:55:31 +04:00
ArrayBufferBuilder : : ArrayBufferBuilder ( )
2014-03-17 21:46:04 +04:00
: mDataPtr ( nullptr ) ,
2013-08-28 03:55:31 +04:00
mCapacity ( 0 ) ,
2014-05-16 09:34:43 +04:00
mLength ( 0 ) ,
mMapPtr ( nullptr )
2013-08-28 03:55:31 +04:00
{
}
ArrayBufferBuilder : : ~ ArrayBufferBuilder ( )
{
reset ( ) ;
}
void
ArrayBufferBuilder : : reset ( )
{
2014-03-17 21:46:04 +04:00
if ( mDataPtr ) {
JS_free ( nullptr , mDataPtr ) ;
2013-08-28 03:55:31 +04:00
}
2014-05-16 09:34:43 +04:00
if ( mMapPtr ) {
JS_ReleaseMappedArrayBufferContents ( mMapPtr , mLength ) ;
mMapPtr = nullptr ;
}
2014-03-17 21:46:04 +04:00
mDataPtr = nullptr ;
2013-08-28 03:55:31 +04:00
mCapacity = mLength = 0 ;
}
bool
ArrayBufferBuilder : : setCapacity ( uint32_t aNewCap )
{
2014-05-16 09:34:43 +04:00
MOZ_ASSERT ( ! mMapPtr ) ;
2014-11-12 01:47:14 +03:00
// To ensure that realloc won't free mDataPtr, use a size of 1
// instead of 0.
uint8_t * newdata = ( uint8_t * ) js_realloc ( mDataPtr , aNewCap ? aNewCap : 1 ) ;
2014-03-17 21:46:04 +04:00
if ( ! newdata ) {
2013-08-28 03:55:31 +04:00
return false ;
}
2014-08-13 03:59:12 +04:00
if ( aNewCap > mCapacity ) {
memset ( newdata + mCapacity , 0 , aNewCap - mCapacity ) ;
}
2014-03-17 21:46:04 +04:00
mDataPtr = newdata ;
2013-08-28 03:55:31 +04:00
mCapacity = aNewCap ;
if ( mLength > aNewCap ) {
mLength = aNewCap ;
}
return true ;
}
bool
ArrayBufferBuilder : : append ( const uint8_t * aNewData , uint32_t aDataLen ,
uint32_t aMaxGrowth )
{
2014-05-16 09:34:43 +04:00
MOZ_ASSERT ( ! mMapPtr ) ;
2015-05-29 22:46:12 +03:00
CheckedUint32 neededCapacity = mLength ;
neededCapacity + = aDataLen ;
if ( ! neededCapacity . isValid ( ) ) {
return false ;
}
2013-08-28 03:55:31 +04:00
if ( mLength + aDataLen > mCapacity ) {
2015-05-29 22:46:12 +03:00
CheckedUint32 newcap = mCapacity ;
2013-08-28 03:55:31 +04:00
// Double while under aMaxGrowth or if not specified.
if ( ! aMaxGrowth | | mCapacity < aMaxGrowth ) {
2015-05-29 22:46:12 +03:00
newcap * = 2 ;
2013-08-28 03:55:31 +04:00
} else {
2015-05-29 22:46:12 +03:00
newcap + = aMaxGrowth ;
2013-08-28 03:55:31 +04:00
}
2015-05-29 22:46:12 +03:00
if ( ! newcap . isValid ( ) ) {
return false ;
2013-08-28 03:55:31 +04:00
}
2015-05-29 22:46:12 +03:00
// But make sure there's always enough to satisfy our request.
if ( newcap . value ( ) < neededCapacity . value ( ) ) {
newcap = neededCapacity ;
2013-08-28 03:55:31 +04:00
}
2015-05-29 22:46:12 +03:00
if ( ! setCapacity ( newcap . value ( ) ) ) {
2013-08-28 03:55:31 +04:00
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 )
{
2014-05-16 09:34:43 +04:00
if ( mMapPtr ) {
JSObject * obj = JS_NewMappedArrayBufferWithContents ( aCx , mLength , mMapPtr ) ;
if ( ! obj ) {
JS_ReleaseMappedArrayBufferContents ( mMapPtr , mLength ) ;
}
mMapPtr = nullptr ;
2016-01-29 03:09:12 +03:00
// The memory-mapped contents will be released when the ArrayBuffer becomes
// detached or is GC'd.
2014-05-16 09:34:43 +04:00
return obj ;
}
2013-08-28 03:55:31 +04:00
// we need to check for mLength == 0, because nothing may have been
// added
if ( mCapacity > mLength | | mLength = = 0 ) {
if ( ! setCapacity ( mLength ) ) {
return nullptr ;
}
}
2014-03-17 21:46:04 +04:00
JSObject * obj = JS_NewArrayBufferWithContents ( aCx , mLength , mDataPtr ) ;
2014-04-27 09:22:00 +04:00
mLength = mCapacity = 0 ;
2013-08-28 03:55:31 +04:00
if ( ! obj ) {
2014-04-27 09:22:00 +04:00
js_free ( mDataPtr ) ;
2013-08-28 03:55:31 +04:00
}
2014-07-01 16:36:00 +04:00
mDataPtr = nullptr ;
2013-08-28 03:55:31 +04:00
return obj ;
}
2014-05-16 09:34:43 +04:00
nsresult
ArrayBufferBuilder : : mapToFileInPackage ( const nsCString & aFile ,
nsIFile * aJarFile )
{
nsresult rv ;
// Open Jar file to get related attributes of target file.
2015-10-18 08:24:48 +03:00
RefPtr < nsZipArchive > zip = new nsZipArchive ( ) ;
2014-05-16 09:34:43 +04:00
rv = zip - > OpenArchive ( aJarFile ) ;
if ( NS_FAILED ( rv ) ) {
return rv ;
}
nsZipItem * zipItem = zip - > GetItem ( aFile . get ( ) ) ;
2014-09-04 21:55:00 +04:00
if ( ! zipItem ) {
return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST ;
2014-05-16 09:34:43 +04:00
}
// If file was added to the package as stored(uncompressed), map to the
// offset of file in zip package.
if ( ! zipItem - > Compression ( ) ) {
uint32_t offset = zip - > GetDataOffset ( zipItem ) ;
uint32_t size = zipItem - > RealSize ( ) ;
mozilla : : AutoFDClose pr_fd ;
rv = aJarFile - > OpenNSPRFileDesc ( PR_RDONLY , 0 , & pr_fd . rwget ( ) ) ;
if ( NS_FAILED ( rv ) ) {
return rv ;
}
2015-04-24 16:18:13 +03:00
mMapPtr = JS_CreateMappedArrayBufferContents ( PR_FileDesc2NativeHandle ( pr_fd ) ,
offset , size ) ;
2014-05-16 09:34:43 +04:00
if ( mMapPtr ) {
mLength = size ;
return NS_OK ;
}
}
return NS_ERROR_FAILURE ;
}
2013-08-28 03:55:31 +04:00
/* 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 ;
}
2016-06-27 20:13:41 +03:00
} // dom namespace
} // mozilla namespaceo