LCOV - code coverage report
Current view: directory - content/base/src - nsXMLHttpRequest.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1739 854 49.1 %
Date: 2012-04-21 Functions: 155 72 46.5 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "mozilla/Util.h"
      39                 : 
      40                 : #include "nsXMLHttpRequest.h"
      41                 : #include "nsISimpleEnumerator.h"
      42                 : #include "nsIXPConnect.h"
      43                 : #include "nsICharsetConverterManager.h"
      44                 : #include "nsLayoutCID.h"
      45                 : #include "nsXPIDLString.h"
      46                 : #include "nsReadableUtils.h"
      47                 : #include "nsIURI.h"
      48                 : #include "nsILoadGroup.h"
      49                 : #include "nsNetUtil.h"
      50                 : #include "nsStreamUtils.h"
      51                 : #include "nsThreadUtils.h"
      52                 : #include "nsIUploadChannel.h"
      53                 : #include "nsIUploadChannel2.h"
      54                 : #include "nsIDOMSerializer.h"
      55                 : #include "nsXPCOM.h"
      56                 : #include "nsISupportsPrimitives.h"
      57                 : #include "nsGUIEvent.h"
      58                 : #include "nsIPrivateDOMEvent.h"
      59                 : #include "prprf.h"
      60                 : #include "nsIDOMEventListener.h"
      61                 : #include "nsIJSContextStack.h"
      62                 : #include "nsIScriptSecurityManager.h"
      63                 : #include "nsWeakPtr.h"
      64                 : #include "nsCharsetAlias.h"
      65                 : #include "nsIScriptGlobalObject.h"
      66                 : #include "nsDOMClassInfoID.h"
      67                 : #include "nsIDOMElement.h"
      68                 : #include "nsIDOMWindow.h"
      69                 : #include "nsIMIMEService.h"
      70                 : #include "nsCExternalHandlerService.h"
      71                 : #include "nsIVariant.h"
      72                 : #include "nsVariant.h"
      73                 : #include "nsIScriptError.h"
      74                 : #include "xpcpublic.h"
      75                 : #include "nsStringStream.h"
      76                 : #include "nsIStreamConverterService.h"
      77                 : #include "nsICachingChannel.h"
      78                 : #include "nsContentUtils.h"
      79                 : #include "nsEventDispatcher.h"
      80                 : #include "nsDOMJSUtils.h"
      81                 : #include "nsCOMArray.h"
      82                 : #include "nsIScriptableUConv.h"
      83                 : #include "nsCycleCollectionParticipant.h"
      84                 : #include "nsIContentPolicy.h"
      85                 : #include "nsContentPolicyUtils.h"
      86                 : #include "nsContentErrors.h"
      87                 : #include "nsLayoutStatics.h"
      88                 : #include "nsCrossSiteListenerProxy.h"
      89                 : #include "nsDOMError.h"
      90                 : #include "nsIHTMLDocument.h"
      91                 : #include "nsIMultiPartChannel.h"
      92                 : #include "nsIScriptObjectPrincipal.h"
      93                 : #include "nsIStorageStream.h"
      94                 : #include "nsIPromptFactory.h"
      95                 : #include "nsIWindowWatcher.h"
      96                 : #include "nsCharSeparatedTokenizer.h"
      97                 : #include "nsIConsoleService.h"
      98                 : #include "nsIChannelPolicy.h"
      99                 : #include "nsChannelPolicy.h"
     100                 : #include "nsIContentSecurityPolicy.h"
     101                 : #include "nsAsyncRedirectVerifyHelper.h"
     102                 : #include "jstypedarray.h"
     103                 : #include "nsStringBuffer.h"
     104                 : #include "nsDOMFile.h"
     105                 : #include "nsIFileChannel.h"
     106                 : #include "mozilla/Telemetry.h"
     107                 : #include "sampler.h"
     108                 : #include "nsWrapperCacheInlines.h"
     109                 : 
     110                 : using namespace mozilla;
     111                 : 
     112                 : #define LOAD_STR "load"
     113                 : #define ERROR_STR "error"
     114                 : #define ABORT_STR "abort"
     115                 : #define TIMEOUT_STR "timeout"
     116                 : #define LOADSTART_STR "loadstart"
     117                 : #define PROGRESS_STR "progress"
     118                 : #define UPLOADPROGRESS_STR "uploadprogress"
     119                 : #define READYSTATE_STR "readystatechange"
     120                 : #define LOADEND_STR "loadend"
     121                 : 
     122                 : // CIDs
     123                 : 
     124                 : // State
     125                 : #define XML_HTTP_REQUEST_UNSENT           (1 << 0) // 0 UNSENT
     126                 : #define XML_HTTP_REQUEST_OPENED           (1 << 1) // 1 OPENED
     127                 : #define XML_HTTP_REQUEST_HEADERS_RECEIVED (1 << 2) // 2 HEADERS_RECEIVED
     128                 : #define XML_HTTP_REQUEST_LOADING          (1 << 3) // 3 LOADING
     129                 : #define XML_HTTP_REQUEST_DONE             (1 << 4) // 4 DONE
     130                 : #define XML_HTTP_REQUEST_SENT             (1 << 5) // Internal, OPENED in IE and external view
     131                 : #define XML_HTTP_REQUEST_STOPPED          (1 << 6) // Internal, LOADING in IE and external view
     132                 : // The above states are mutually exclusive, change with ChangeState() only.
     133                 : // The states below can be combined.
     134                 : #define XML_HTTP_REQUEST_ABORTED        (1 << 7)  // Internal
     135                 : #define XML_HTTP_REQUEST_ASYNC          (1 << 8)  // Internal
     136                 : #define XML_HTTP_REQUEST_PARSEBODY      (1 << 9)  // Internal
     137                 : #define XML_HTTP_REQUEST_SYNCLOOPING    (1 << 10) // Internal
     138                 : #define XML_HTTP_REQUEST_MULTIPART      (1 << 11) // Internal
     139                 : #define XML_HTTP_REQUEST_GOT_FINAL_STOP (1 << 12) // Internal
     140                 : #define XML_HTTP_REQUEST_BACKGROUND     (1 << 13) // Internal
     141                 : // This is set when we've got the headers for a multipart XMLHttpRequest,
     142                 : // but haven't yet started to process the first part.
     143                 : #define XML_HTTP_REQUEST_MPART_HEADERS  (1 << 14) // Internal
     144                 : #define XML_HTTP_REQUEST_USE_XSITE_AC   (1 << 15) // Internal
     145                 : #define XML_HTTP_REQUEST_NEED_AC_PREFLIGHT (1 << 16) // Internal
     146                 : #define XML_HTTP_REQUEST_AC_WITH_CREDENTIALS (1 << 17) // Internal
     147                 : #define XML_HTTP_REQUEST_TIMED_OUT (1 << 18) // Internal
     148                 : #define XML_HTTP_REQUEST_DELETED (1 << 19) // Internal
     149                 : 
     150                 : #define XML_HTTP_REQUEST_LOADSTATES         \
     151                 :   (XML_HTTP_REQUEST_UNSENT |                \
     152                 :    XML_HTTP_REQUEST_OPENED |                \
     153                 :    XML_HTTP_REQUEST_HEADERS_RECEIVED |      \
     154                 :    XML_HTTP_REQUEST_LOADING |               \
     155                 :    XML_HTTP_REQUEST_DONE |                  \
     156                 :    XML_HTTP_REQUEST_SENT |                  \
     157                 :    XML_HTTP_REQUEST_STOPPED)
     158                 : 
     159                 : #define NS_BADCERTHANDLER_CONTRACTID \
     160                 :   "@mozilla.org/content/xmlhttprequest-bad-cert-handler;1"
     161                 : 
     162                 : #define NS_PROGRESS_EVENT_INTERVAL 50
     163                 : 
     164               0 : NS_IMPL_ISUPPORTS1(nsXHRParseEndListener, nsIDOMEventListener)
     165                 : 
     166                 : class nsResumeTimeoutsEvent : public nsRunnable
     167               0 : {
     168                 : public:
     169               0 :   nsResumeTimeoutsEvent(nsPIDOMWindow* aWindow) : mWindow(aWindow) {}
     170                 : 
     171               0 :   NS_IMETHOD Run()
     172                 :   {
     173               0 :     mWindow->ResumeTimeouts(false);
     174               0 :     return NS_OK;
     175                 :   }
     176                 : 
     177                 : private:
     178                 :   nsCOMPtr<nsPIDOMWindow> mWindow;
     179                 : };
     180                 : 
     181                 : 
     182                 : // This helper function adds the given load flags to the request's existing
     183                 : // load flags.
     184              61 : static void AddLoadFlags(nsIRequest *request, nsLoadFlags newFlags)
     185                 : {
     186                 :   nsLoadFlags flags;
     187              61 :   request->GetLoadFlags(&flags);
     188              61 :   flags |= newFlags;
     189              61 :   request->SetLoadFlags(flags);
     190              61 : }
     191                 : 
     192             200 : static nsresult IsCapabilityEnabled(const char *capability, bool *enabled)
     193                 : {
     194             200 :   nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
     195             200 :   if (!secMan)
     196               0 :     return NS_ERROR_FAILURE;
     197                 : 
     198             200 :   return secMan->IsCapabilityEnabled(capability, enabled);
     199                 : }
     200                 : 
     201                 : // Helper proxy class to be used when expecting an
     202                 : // multipart/x-mixed-replace stream of XML documents.
     203                 : 
     204                 : class nsMultipartProxyListener : public nsIStreamListener
     205                 : {
     206                 : public:
     207                 :   nsMultipartProxyListener(nsIStreamListener *dest);
     208                 :   virtual ~nsMultipartProxyListener();
     209                 : 
     210                 :   /* additional members */
     211                 :   NS_DECL_ISUPPORTS
     212                 :   NS_DECL_NSISTREAMLISTENER
     213                 :   NS_DECL_NSIREQUESTOBSERVER
     214                 : 
     215                 : private:
     216                 :   nsCOMPtr<nsIStreamListener> mDestListener;
     217                 : };
     218                 : 
     219                 : 
     220               0 : nsMultipartProxyListener::nsMultipartProxyListener(nsIStreamListener *dest)
     221               0 :   : mDestListener(dest)
     222                 : {
     223               0 : }
     224                 : 
     225               0 : nsMultipartProxyListener::~nsMultipartProxyListener()
     226                 : {
     227               0 : }
     228                 : 
     229               0 : NS_IMPL_ISUPPORTS2(nsMultipartProxyListener, nsIStreamListener,
     230                 :                    nsIRequestObserver)
     231                 : 
     232                 : /** nsIRequestObserver methods **/
     233                 : 
     234                 : NS_IMETHODIMP
     235               0 : nsMultipartProxyListener::OnStartRequest(nsIRequest *aRequest,
     236                 :                                          nsISupports *ctxt)
     237                 : {
     238               0 :   nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
     239               0 :   NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED);
     240                 : 
     241               0 :   nsCAutoString contentType;
     242               0 :   nsresult rv = channel->GetContentType(contentType);
     243                 : 
     244               0 :   if (!contentType.EqualsLiteral("multipart/x-mixed-replace")) {
     245               0 :     return NS_ERROR_INVALID_ARG;
     246                 :   }
     247                 : 
     248                 :   // If multipart/x-mixed-replace content, we'll insert a MIME
     249                 :   // decoder in the pipeline to handle the content and pass it along
     250                 :   // to our original listener.
     251                 : 
     252               0 :   nsCOMPtr<nsIXMLHttpRequest> xhr = do_QueryInterface(mDestListener);
     253                 : 
     254                 :   nsCOMPtr<nsIStreamConverterService> convServ =
     255               0 :     do_GetService("@mozilla.org/streamConverters;1", &rv);
     256               0 :   if (NS_SUCCEEDED(rv)) {
     257               0 :     nsCOMPtr<nsIStreamListener> toListener(mDestListener);
     258               0 :     nsCOMPtr<nsIStreamListener> fromListener;
     259                 : 
     260               0 :     rv = convServ->AsyncConvertData("multipart/x-mixed-replace",
     261                 :                                     "*/*",
     262                 :                                     toListener,
     263                 :                                     nsnull,
     264               0 :                                     getter_AddRefs(fromListener));
     265               0 :     NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && fromListener, NS_ERROR_UNEXPECTED);
     266                 : 
     267               0 :     mDestListener = fromListener;
     268                 :   }
     269                 : 
     270               0 :   if (xhr) {
     271               0 :     static_cast<nsXMLHttpRequest*>(xhr.get())->mState |=
     272               0 :       XML_HTTP_REQUEST_MPART_HEADERS;
     273                 :    }
     274                 : 
     275               0 :   return mDestListener->OnStartRequest(aRequest, ctxt);
     276                 : }
     277                 : 
     278                 : NS_IMETHODIMP
     279               0 : nsMultipartProxyListener::OnStopRequest(nsIRequest *aRequest,
     280                 :                                         nsISupports *ctxt,
     281                 :                                         nsresult status)
     282                 : {
     283               0 :   return mDestListener->OnStopRequest(aRequest, ctxt, status);
     284                 : }
     285                 : 
     286                 : /** nsIStreamListener methods **/
     287                 : 
     288                 : NS_IMETHODIMP
     289               0 : nsMultipartProxyListener::OnDataAvailable(nsIRequest *aRequest,
     290                 :                                           nsISupports *ctxt,
     291                 :                                           nsIInputStream *inStr,
     292                 :                                           PRUint32 sourceOffset,
     293                 :                                           PRUint32 count)
     294                 : {
     295               0 :   return mDestListener->OnDataAvailable(aRequest, ctxt, inStr, sourceOffset,
     296               0 :                                         count);
     297                 : }
     298                 : 
     299                 : /////////////////////////////////////////////
     300                 : 
     301            1396 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXHREventTarget)
     302                 : 
     303              59 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXHREventTarget,
     304                 :                                                   nsDOMEventTargetHelper)
     305              59 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnLoadListener)
     306              59 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnErrorListener)
     307              59 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnAbortListener)
     308              59 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnLoadStartListener)
     309              59 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnProgressListener)
     310              59 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnLoadendListener)
     311              59 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnTimeoutListener)
     312              59 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     313                 : 
     314              10 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXHREventTarget,
     315                 :                                                 nsDOMEventTargetHelper)
     316              10 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnLoadListener)
     317              10 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnErrorListener)
     318              10 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnAbortListener)
     319              10 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnLoadStartListener)
     320              10 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnProgressListener)
     321              10 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnLoadendListener)
     322              10 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnTimeoutListener)
     323              10 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     324                 : 
     325           38510 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXHREventTarget)
     326           38510 :   NS_INTERFACE_MAP_ENTRY(nsIXMLHttpRequestEventTarget)
     327           38510 : NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
     328                 : 
     329           83894 : NS_IMPL_ADDREF_INHERITED(nsXHREventTarget, nsDOMEventTargetHelper)
     330           83894 : NS_IMPL_RELEASE_INHERITED(nsXHREventTarget, nsDOMEventTargetHelper)
     331                 : 
     332                 : void
     333               0 : nsXHREventTarget::DisconnectFromOwner()
     334                 : {
     335               0 :   nsDOMEventTargetHelper::DisconnectFromOwner();
     336               0 :   NS_DISCONNECT_EVENT_HANDLER(Load)
     337               0 :   NS_DISCONNECT_EVENT_HANDLER(Error)
     338               0 :   NS_DISCONNECT_EVENT_HANDLER(Abort)
     339               0 :   NS_DISCONNECT_EVENT_HANDLER(Load)
     340               0 :   NS_DISCONNECT_EVENT_HANDLER(Progress)
     341               0 :   NS_DISCONNECT_EVENT_HANDLER(Loadend)
     342               0 :   NS_DISCONNECT_EVENT_HANDLER(Timeout)
     343               0 : }
     344                 : 
     345                 : NS_IMETHODIMP
     346               0 : nsXHREventTarget::GetOnload(nsIDOMEventListener** aOnLoad)
     347                 : {
     348               0 :   return GetInnerEventListener(mOnLoadListener, aOnLoad);
     349                 : }
     350                 : 
     351                 : NS_IMETHODIMP
     352               0 : nsXHREventTarget::SetOnload(nsIDOMEventListener* aOnLoad)
     353                 : {
     354               0 :   return RemoveAddEventListener(NS_LITERAL_STRING(LOAD_STR),
     355               0 :                                 mOnLoadListener, aOnLoad);
     356                 : }
     357                 : 
     358                 : NS_IMETHODIMP
     359               0 : nsXHREventTarget::GetOnerror(nsIDOMEventListener** aOnerror)
     360                 : {
     361               0 :   return GetInnerEventListener(mOnErrorListener, aOnerror);
     362                 : }
     363                 : 
     364                 : NS_IMETHODIMP
     365               0 : nsXHREventTarget::SetOnerror(nsIDOMEventListener* aOnerror)
     366                 : {
     367               0 :   return RemoveAddEventListener(NS_LITERAL_STRING(ERROR_STR),
     368               0 :                                 mOnErrorListener, aOnerror);
     369                 : }
     370                 : 
     371                 : NS_IMETHODIMP
     372               0 : nsXHREventTarget::GetOnabort(nsIDOMEventListener** aOnabort)
     373                 : {
     374               0 :   return GetInnerEventListener(mOnAbortListener, aOnabort);
     375                 : }
     376                 : 
     377                 : NS_IMETHODIMP
     378               0 : nsXHREventTarget::SetOnabort(nsIDOMEventListener* aOnabort)
     379                 : {
     380               0 :   return RemoveAddEventListener(NS_LITERAL_STRING(ABORT_STR),
     381               0 :                                 mOnAbortListener, aOnabort);
     382                 : }
     383                 : 
     384                 : NS_IMETHODIMP
     385               0 : nsXHREventTarget::GetOnloadstart(nsIDOMEventListener** aOnloadstart)
     386                 : {
     387               0 :   return GetInnerEventListener(mOnLoadStartListener, aOnloadstart);
     388                 : }
     389                 : 
     390                 : NS_IMETHODIMP
     391               0 : nsXHREventTarget::SetOnloadstart(nsIDOMEventListener* aOnloadstart)
     392                 : {
     393               0 :   return RemoveAddEventListener(NS_LITERAL_STRING(LOADSTART_STR),
     394               0 :                                 mOnLoadStartListener, aOnloadstart);
     395                 : }
     396                 : 
     397                 : NS_IMETHODIMP
     398               0 : nsXHREventTarget::GetOnprogress(nsIDOMEventListener** aOnprogress)
     399                 : {
     400               0 :   return GetInnerEventListener(mOnProgressListener, aOnprogress);
     401                 : }
     402                 : 
     403                 : NS_IMETHODIMP
     404               0 : nsXHREventTarget::SetOnprogress(nsIDOMEventListener* aOnprogress)
     405                 : {
     406               0 :   return RemoveAddEventListener(NS_LITERAL_STRING(PROGRESS_STR),
     407               0 :                                 mOnProgressListener, aOnprogress);
     408                 : }
     409                 : 
     410                 : /* attribute nsIDOMEventListener ontimeout; */
     411                 : NS_IMETHODIMP
     412               0 : nsXHREventTarget::GetOntimeout(nsIDOMEventListener * *aOntimeout)
     413                 : {
     414               0 :   return GetInnerEventListener(mOnTimeoutListener, aOntimeout);
     415                 : }
     416                 : NS_IMETHODIMP
     417               0 : nsXHREventTarget::SetOntimeout(nsIDOMEventListener *aOntimeout)
     418                 : {
     419               0 :   return RemoveAddEventListener(NS_LITERAL_STRING(TIMEOUT_STR),
     420               0 :                                 mOnTimeoutListener, aOntimeout);
     421                 : }
     422                 : 
     423                 : NS_IMETHODIMP
     424               0 : nsXHREventTarget::GetOnloadend(nsIDOMEventListener** aOnLoadend)
     425                 : {
     426               0 :   return GetInnerEventListener(mOnLoadendListener, aOnLoadend);
     427                 : }
     428                 : 
     429                 : NS_IMETHODIMP
     430               0 : nsXHREventTarget::SetOnloadend(nsIDOMEventListener* aOnLoadend)
     431                 : {
     432               0 :   return RemoveAddEventListener(NS_LITERAL_STRING(LOADEND_STR),
     433               0 :                                 mOnLoadendListener, aOnLoadend);
     434                 : }
     435                 : 
     436                 : /////////////////////////////////////////////
     437                 : 
     438                 : DOMCI_DATA(XMLHttpRequestUpload, nsXMLHttpRequestUpload)
     439                 : 
     440               0 : NS_INTERFACE_MAP_BEGIN(nsXMLHttpRequestUpload)
     441               0 :   NS_INTERFACE_MAP_ENTRY(nsIXMLHttpRequestUpload)
     442               0 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XMLHttpRequestUpload)
     443               0 : NS_INTERFACE_MAP_END_INHERITING(nsXHREventTarget)
     444                 : 
     445               0 : NS_IMPL_ADDREF_INHERITED(nsXMLHttpRequestUpload, nsXHREventTarget)
     446               0 : NS_IMPL_RELEASE_INHERITED(nsXMLHttpRequestUpload, nsXHREventTarget)
     447                 : 
     448                 : /////////////////////////////////////////////
     449                 : //
     450                 : //
     451                 : /////////////////////////////////////////////
     452                 : 
     453             595 : nsXMLHttpRequest::nsXMLHttpRequest()
     454                 :   : mResponseBodyDecodedPos(0),
     455                 :     mResponseType(XML_HTTP_RESPONSE_TYPE_DEFAULT),
     456                 :     mRequestObserver(nsnull), mState(XML_HTTP_REQUEST_UNSENT),
     457                 :     mUploadTransferred(0), mUploadTotal(0), mUploadComplete(true),
     458                 :     mProgressSinceLastProgressEvent(false),
     459                 :     mUploadProgress(0), mUploadProgressMax(0),
     460                 :     mRequestSentTime(0), mTimeoutMilliseconds(0),
     461                 :     mErrorLoad(false), mWaitingForOnStopRequest(false),
     462                 :     mProgressTimerIsActive(false), mProgressEventWasDelayed(false),
     463                 :     mIsHtml(false),
     464                 :     mWarnAboutMultipartHtml(false),
     465                 :     mWarnAboutSyncHtml(false),
     466                 :     mLoadLengthComputable(false), mLoadTotal(0),
     467                 :     mFirstStartRequestSeen(false),
     468                 :     mInLoadProgressEvent(false),
     469                 :     mResultJSON(JSVAL_VOID),
     470             595 :     mResultArrayBuffer(nsnull)
     471                 : {
     472             595 :   nsLayoutStatics::AddRef();
     473             595 : }
     474                 : 
     475            1785 : nsXMLHttpRequest::~nsXMLHttpRequest()
     476                 : {
     477             595 :   mState |= XML_HTTP_REQUEST_DELETED;
     478                 : 
     479             595 :   if (mState & (XML_HTTP_REQUEST_STOPPED |
     480                 :                 XML_HTTP_REQUEST_SENT |
     481                 :                 XML_HTTP_REQUEST_LOADING)) {
     482               0 :     Abort();
     483                 :   }
     484                 : 
     485             595 :   NS_ABORT_IF_FALSE(!(mState & XML_HTTP_REQUEST_SYNCLOOPING), "we rather crash than hang");
     486             595 :   mState &= ~XML_HTTP_REQUEST_SYNCLOOPING;
     487                 : 
     488             595 :   nsLayoutStatics::Release();
     489            2380 : }
     490                 : 
     491                 : void
     492               0 : nsXMLHttpRequest::RootResultArrayBuffer()
     493                 : {
     494                 :   nsContentUtils::PreserveWrapper(
     495                 :     static_cast<nsIDOMEventTarget*>(
     496               0 :       static_cast<nsDOMEventTargetHelper*>(this)), this);
     497               0 : }
     498                 : 
     499                 : /**
     500                 :  * This Init method is called from the factory constructor.
     501                 :  */
     502                 : nsresult
     503             595 : nsXMLHttpRequest::Init()
     504                 : {
     505                 :   // Set the original mPrincipal, if available.
     506                 :   // Get JSContext from stack.
     507                 :   nsCOMPtr<nsIJSContextStack> stack =
     508            1190 :     do_GetService("@mozilla.org/js/xpc/ContextStack;1");
     509                 : 
     510             595 :   if (!stack) {
     511               0 :     return NS_OK;
     512                 :   }
     513                 : 
     514                 :   JSContext *cx;
     515                 : 
     516             595 :   if (NS_FAILED(stack->Peek(&cx)) || !cx) {
     517               0 :     return NS_OK;
     518                 :   }
     519                 : 
     520             595 :   nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
     521            1190 :   nsCOMPtr<nsIPrincipal> subjectPrincipal;
     522             595 :   if (secMan) {
     523             595 :     nsresult rv = secMan->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
     524             595 :     NS_ENSURE_SUCCESS(rv, rv);
     525                 :   }
     526             595 :   NS_ENSURE_STATE(subjectPrincipal);
     527             595 :   mPrincipal = subjectPrincipal;
     528                 : 
     529             595 :   nsIScriptContext* context = GetScriptContextFromJSContext(cx);
     530             595 :   if (context) {
     531                 :     nsCOMPtr<nsPIDOMWindow> window =
     532               0 :       do_QueryInterface(context->GetGlobalObject());
     533               0 :     BindToOwner(window ? window->GetCurrentInnerWindow() : nsnull);
     534                 :   }
     535                 : 
     536             595 :   return NS_OK;
     537                 : }
     538                 : /**
     539                 :  * This Init method should only be called by C++ consumers.
     540                 :  */
     541                 : NS_IMETHODIMP
     542               0 : nsXMLHttpRequest::Init(nsIPrincipal* aPrincipal,
     543                 :                        nsIScriptContext* aScriptContext,
     544                 :                        nsPIDOMWindow* aOwnerWindow,
     545                 :                        nsIURI* aBaseURI)
     546                 : {
     547               0 :   NS_ENSURE_ARG_POINTER(aPrincipal);
     548                 : 
     549               0 :   mPrincipal = aPrincipal;
     550               0 :   BindToOwner(aOwnerWindow ? aOwnerWindow->GetCurrentInnerWindow() : nsnull);
     551               0 :   mBaseURI = aBaseURI;
     552                 : 
     553               0 :   return NS_OK;
     554                 : }
     555                 : 
     556                 : /**
     557                 :  * This Initialize method is called from XPConnect via nsIJSNativeInitializer.
     558                 :  */
     559                 : NS_IMETHODIMP
     560               0 : nsXMLHttpRequest::Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
     561                 :                              PRUint32 argc, jsval *argv)
     562                 : {
     563               0 :   nsCOMPtr<nsPIDOMWindow> owner = do_QueryInterface(aOwner);
     564               0 :   if (!owner) {
     565               0 :     NS_WARNING("Unexpected nsIJSNativeInitializer owner");
     566               0 :     return NS_OK;
     567                 :   }
     568                 : 
     569                 :   // This XHR object is bound to a |window|,
     570                 :   // so re-set principal and script context.
     571               0 :   nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal = do_QueryInterface(aOwner);
     572               0 :   NS_ENSURE_STATE(scriptPrincipal);
     573               0 :   mPrincipal = scriptPrincipal->GetPrincipal();
     574               0 :   BindToOwner(owner);
     575               0 :   return NS_OK; 
     576                 : }
     577                 : 
     578                 : void
     579            1192 : nsXMLHttpRequest::ResetResponse()
     580                 : {
     581            1192 :   mResponseXML = nsnull;
     582            1192 :   mResponseBody.Truncate();
     583            1192 :   mResponseText.Truncate();
     584            1192 :   mResponseBlob = nsnull;
     585            1192 :   mDOMFile = nsnull;
     586            1192 :   mBuilder = nsnull;
     587            1192 :   mResultArrayBuffer = nsnull;
     588            1192 :   mResultJSON = JSVAL_VOID;
     589            1192 :   mLoadTransferred = 0;
     590            1192 :   mResponseBodyDecodedPos = 0;
     591            1192 : }
     592                 : 
     593                 : void
     594               0 : nsXMLHttpRequest::SetRequestObserver(nsIRequestObserver* aObserver)
     595                 : {
     596               0 :   mRequestObserver = aObserver;
     597               0 : }
     598                 : 
     599            1396 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLHttpRequest)
     600                 : 
     601             450 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsXMLHttpRequest)
     602             450 :   bool isBlack = tmp->IsBlack();
     603             450 :   if (isBlack || tmp->mWaitingForOnStopRequest) {
     604             227 :     if (tmp->mListenerManager) {
     605             226 :       tmp->mListenerManager->UnmarkGrayJSListeners();
     606             226 :       NS_UNMARK_LISTENER_WRAPPER(Load)
     607             226 :       NS_UNMARK_LISTENER_WRAPPER(Error)
     608             226 :       NS_UNMARK_LISTENER_WRAPPER(Abort)
     609             226 :       NS_UNMARK_LISTENER_WRAPPER(LoadStart)
     610             226 :       NS_UNMARK_LISTENER_WRAPPER(Progress)
     611             226 :       NS_UNMARK_LISTENER_WRAPPER(Loadend)
     612             226 :       NS_UNMARK_LISTENER_WRAPPER(UploadProgress)
     613             226 :       NS_UNMARK_LISTENER_WRAPPER(Readystatechange)
     614                 :     }
     615             227 :     if (!isBlack) {
     616              44 :       xpc_UnmarkGrayObject(tmp->PreservingWrapper() ? 
     617               0 :                            tmp->GetWrapperPreserveColor() :
     618              44 :                            tmp->GetExpandoObjectPreserveColor());
     619                 :     }
     620             227 :     return true;
     621                 :   }
     622             223 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
     623                 : 
     624              50 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsXMLHttpRequest)
     625              50 :   return tmp->IsBlack();
     626                 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
     627                 : 
     628              58 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsXMLHttpRequest)
     629              58 :   return tmp->IsBlack();
     630                 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
     631                 : 
     632              59 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLHttpRequest,
     633                 :                                                   nsXHREventTarget)
     634              59 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
     635              59 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannel)
     636              59 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mReadRequest)
     637              59 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mResponseXML)
     638              59 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCORSPreflightChannel)
     639                 : 
     640              59 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnUploadProgressListener)
     641              59 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnReadystatechangeListener)
     642                 : 
     643              59 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mXMLParserStreamListener)
     644                 : 
     645              59 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannelEventSink)
     646              59 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mProgressEventSink)
     647                 : 
     648              59 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mUpload,
     649                 :                                                        nsIXMLHttpRequestUpload)
     650              59 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     651                 : 
     652              10 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXMLHttpRequest,
     653                 :                                                 nsXHREventTarget)
     654              10 :   tmp->mResultArrayBuffer = nsnull;
     655              10 :   tmp->mResultJSON = JSVAL_VOID;
     656              10 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
     657              10 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChannel)
     658              10 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mReadRequest)
     659              10 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mResponseXML)
     660              10 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCORSPreflightChannel)
     661                 : 
     662              10 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnUploadProgressListener)
     663              10 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnReadystatechangeListener)
     664                 : 
     665              10 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mXMLParserStreamListener)
     666                 : 
     667              10 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChannelEventSink)
     668              10 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mProgressEventSink)
     669                 : 
     670              10 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mUpload)
     671              10 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     672                 : 
     673              59 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsXMLHttpRequest,
     674                 :                                                nsXHREventTarget)
     675              59 :   if(tmp->mResultArrayBuffer) {
     676               0 :     NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(tmp->mResultArrayBuffer,
     677                 :                                                "mResultArrayBuffer")
     678                 :   }
     679              59 :   if (JSVAL_IS_GCTHING(tmp->mResultJSON)) {
     680               0 :     void *gcThing = JSVAL_TO_GCTHING(tmp->mResultJSON);
     681               0 :     NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mResultJSON")
     682                 :   }
     683              59 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
     684                 : 
     685                 : DOMCI_DATA(XMLHttpRequest, nsXMLHttpRequest)
     686                 : 
     687                 : // QueryInterface implementation for nsXMLHttpRequest
     688           88088 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLHttpRequest)
     689           46935 :   NS_INTERFACE_MAP_ENTRY(nsIXMLHttpRequest)
     690           42912 :   NS_INTERFACE_MAP_ENTRY(nsIJSXMLHttpRequest)
     691           42772 :   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
     692           42772 :   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
     693           41079 :   NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
     694           41044 :   NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
     695           40429 :   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
     696           39139 :   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     697           39139 :   NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
     698           39139 :   NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
     699           39127 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XMLHttpRequest)
     700           38510 : NS_INTERFACE_MAP_END_INHERITING(nsXHREventTarget)
     701                 : 
     702           83894 : NS_IMPL_ADDREF_INHERITED(nsXMLHttpRequest, nsXHREventTarget)
     703           83894 : NS_IMPL_RELEASE_INHERITED(nsXMLHttpRequest, nsXHREventTarget)
     704                 : 
     705                 : void
     706               0 : nsXMLHttpRequest::DisconnectFromOwner()
     707                 : {
     708               0 :   nsXHREventTarget::DisconnectFromOwner();
     709               0 :   NS_DISCONNECT_EVENT_HANDLER(UploadProgress)
     710               0 :   NS_DISCONNECT_EVENT_HANDLER(Readystatechange)
     711               0 :   Abort();
     712               0 : }
     713                 : 
     714                 : NS_IMETHODIMP
     715               0 : nsXMLHttpRequest::GetOnreadystatechange(nsIDOMEventListener * *aOnreadystatechange)
     716                 : {
     717                 :   return
     718                 :     nsXHREventTarget::GetInnerEventListener(mOnReadystatechangeListener,
     719               0 :                                             aOnreadystatechange);
     720                 : }
     721                 : 
     722                 : NS_IMETHODIMP
     723               0 : nsXMLHttpRequest::SetOnreadystatechange(nsIDOMEventListener * aOnreadystatechange)
     724                 : {
     725                 :   return
     726               0 :     nsXHREventTarget::RemoveAddEventListener(NS_LITERAL_STRING(READYSTATE_STR),
     727                 :                                              mOnReadystatechangeListener,
     728               0 :                                              aOnreadystatechange);
     729                 : }
     730                 : 
     731                 : NS_IMETHODIMP
     732               0 : nsXMLHttpRequest::GetOnuploadprogress(nsIDOMEventListener * *aOnuploadprogress)
     733                 : {
     734                 :   return
     735                 :     nsXHREventTarget::GetInnerEventListener(mOnUploadProgressListener,
     736               0 :                                             aOnuploadprogress);
     737                 : }
     738                 : 
     739                 : NS_IMETHODIMP
     740               0 : nsXMLHttpRequest::SetOnuploadprogress(nsIDOMEventListener * aOnuploadprogress)
     741                 : {
     742                 :   return
     743               0 :     nsXHREventTarget::RemoveAddEventListener(NS_LITERAL_STRING(UPLOADPROGRESS_STR),
     744                 :                                              mOnUploadProgressListener,
     745               0 :                                              aOnuploadprogress);
     746                 : }
     747                 : 
     748                 : /* readonly attribute nsIChannel channel; */
     749                 : NS_IMETHODIMP
     750            1913 : nsXMLHttpRequest::GetChannel(nsIChannel **aChannel)
     751                 : {
     752            1913 :   NS_ENSURE_ARG_POINTER(aChannel);
     753            1913 :   NS_IF_ADDREF(*aChannel = mChannel);
     754                 : 
     755            1913 :   return NS_OK;
     756                 : }
     757                 : 
     758               0 : static void LogMessage(const char* aWarning, nsPIDOMWindow* aWindow)
     759                 : {
     760               0 :   nsCOMPtr<nsIDocument> doc;
     761               0 :   if (aWindow) {
     762               0 :     doc = do_QueryInterface(aWindow->GetExtantDocument());
     763                 :   }
     764                 :   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
     765                 :                                   "DOM", doc,
     766                 :                                   nsContentUtils::eDOM_PROPERTIES,
     767               0 :                                   aWarning);
     768               0 : }
     769                 : 
     770                 : /* readonly attribute nsIDOMDocument responseXML; */
     771                 : NS_IMETHODIMP
     772             392 : nsXMLHttpRequest::GetResponseXML(nsIDOMDocument **aResponseXML)
     773                 : {
     774             392 :   NS_ENSURE_ARG_POINTER(aResponseXML);
     775             392 :   *aResponseXML = nsnull;
     776             392 :   if (mResponseType != XML_HTTP_RESPONSE_TYPE_DEFAULT &&
     777                 :       mResponseType != XML_HTTP_RESPONSE_TYPE_DOCUMENT) {
     778               0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
     779                 :   }
     780             392 :   if ((XML_HTTP_REQUEST_DONE & mState) && mResponseXML) {
     781             392 :     *aResponseXML = mResponseXML;
     782             392 :     NS_ADDREF(*aResponseXML);
     783                 :   }
     784             392 :   if (mWarnAboutMultipartHtml) {
     785               0 :     mWarnAboutMultipartHtml = false;
     786               0 :     LogMessage("HTMLMultipartXHRWarning", GetOwner());
     787                 :   }
     788             392 :   if (mWarnAboutSyncHtml) {
     789               0 :     mWarnAboutSyncHtml = false;
     790               0 :     LogMessage("HTMLSyncXHRWarning", GetOwner());
     791                 :   }
     792             392 :   return NS_OK;
     793                 : }
     794                 : 
     795                 : /*
     796                 :  * This piece copied from nsXMLDocument, we try to get the charset
     797                 :  * from HTTP headers.
     798                 :  */
     799                 : nsresult
     800             584 : nsXMLHttpRequest::DetectCharset()
     801                 : {
     802             584 :   mResponseCharset.Truncate();
     803             584 :   mDecoder = nsnull;
     804                 : 
     805             584 :   if (mResponseType != XML_HTTP_RESPONSE_TYPE_DEFAULT &&
     806                 :       mResponseType != XML_HTTP_RESPONSE_TYPE_TEXT &&
     807                 :       mResponseType != XML_HTTP_RESPONSE_TYPE_JSON &&
     808                 :       mResponseType != XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT) {
     809               0 :     return NS_OK;
     810                 :   }
     811                 : 
     812            1168 :   nsCOMPtr<nsIChannel> channel = do_QueryInterface(mReadRequest);
     813             584 :   if (!channel) {
     814               0 :     channel = mChannel;
     815                 :   }
     816                 : 
     817            1168 :   nsCAutoString charsetVal;
     818             584 :   nsresult rv = channel ? channel->GetContentCharset(charsetVal) :
     819            1168 :                 NS_ERROR_FAILURE;
     820             584 :   if (NS_SUCCEEDED(rv)) {
     821             513 :     rv = nsCharsetAlias::GetPreferred(charsetVal, mResponseCharset);
     822                 :   }
     823                 : 
     824             584 :   if (NS_FAILED(rv) || mResponseCharset.IsEmpty()) {
     825                 :     // MS documentation states UTF-8 is default for responseText
     826             584 :     mResponseCharset.AssignLiteral("UTF-8");
     827                 :   }
     828                 : 
     829             584 :   if (mResponseType == XML_HTTP_RESPONSE_TYPE_JSON &&
     830               0 :       !mResponseCharset.EqualsLiteral("UTF-8")) {
     831                 :     // The XHR spec says only UTF-8 is supported for responseType == "json"
     832               0 :     LogMessage("JSONCharsetWarning", GetOwner());
     833               0 :     mResponseCharset.AssignLiteral("UTF-8");
     834                 :   }
     835                 : 
     836                 :   nsCOMPtr<nsICharsetConverterManager> ccm =
     837            1168 :     do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
     838             584 :   NS_ENSURE_SUCCESS(rv, rv);
     839                 : 
     840             584 :   return ccm->GetUnicodeDecoderRaw(mResponseCharset.get(),
     841             584 :                                    getter_AddRefs(mDecoder));
     842                 : }
     843                 : 
     844                 : nsresult
     845             308 : nsXMLHttpRequest::AppendToResponseText(const char * aSrcBuffer,
     846                 :                                        PRUint32 aSrcBufferLen)
     847                 : {
     848             308 :   NS_ENSURE_STATE(mDecoder);
     849                 : 
     850                 :   PRInt32 destBufferLen;
     851             308 :   nsresult rv = mDecoder->GetMaxLength(aSrcBuffer, aSrcBufferLen,
     852             308 :                                        &destBufferLen);
     853             308 :   NS_ENSURE_SUCCESS(rv, rv);
     854                 : 
     855             308 :   if (!mResponseText.SetCapacity(mResponseText.Length() + destBufferLen)) {
     856               0 :     return NS_ERROR_OUT_OF_MEMORY;
     857                 :   }
     858                 : 
     859             308 :   PRUnichar* destBuffer = mResponseText.BeginWriting() + mResponseText.Length();
     860                 : 
     861             308 :   PRInt32 totalChars = mResponseText.Length();
     862                 : 
     863                 :   // This code here is basically a copy of a similar thing in
     864                 :   // nsScanner::Append(const char* aBuffer, PRUint32 aLen).
     865                 :   // If we get illegal characters in the input we replace
     866                 :   // them and don't just fail.
     867             600 :   do {
     868             600 :     PRInt32 srclen = (PRInt32)aSrcBufferLen;
     869             600 :     PRInt32 destlen = (PRInt32)destBufferLen;
     870             600 :     rv = mDecoder->Convert(aSrcBuffer,
     871                 :                            &srclen,
     872                 :                            destBuffer,
     873             600 :                            &destlen);
     874             600 :     if (NS_FAILED(rv)) {
     875                 :       // We consume one byte, replace it with U+FFFD
     876                 :       // and try the conversion again.
     877                 : 
     878             292 :       destBuffer[destlen] = (PRUnichar)0xFFFD; // add replacement character
     879             292 :       destlen++; // skip written replacement character
     880             292 :       destBuffer += destlen;
     881             292 :       destBufferLen -= destlen;
     882                 : 
     883             292 :       if (srclen < (PRInt32)aSrcBufferLen) {
     884             292 :         srclen++; // Consume the invalid character
     885                 :       }
     886             292 :       aSrcBuffer += srclen;
     887             292 :       aSrcBufferLen -= srclen;
     888                 : 
     889             292 :       mDecoder->Reset();
     890                 :     }
     891                 : 
     892             600 :     totalChars += destlen;
     893                 : 
     894             600 :   } while (NS_FAILED(rv) && aSrcBufferLen > 0);
     895                 : 
     896             308 :   mResponseText.SetLength(totalChars);
     897                 : 
     898             308 :   return NS_OK;
     899                 : }
     900                 : 
     901                 : /* readonly attribute AString responseText; */
     902             351 : NS_IMETHODIMP nsXMLHttpRequest::GetResponseText(nsAString& aResponseText)
     903                 : {
     904             351 :   aResponseText.Truncate();
     905                 : 
     906             351 :   if (mResponseType != XML_HTTP_RESPONSE_TYPE_DEFAULT &&
     907                 :       mResponseType != XML_HTTP_RESPONSE_TYPE_TEXT &&
     908                 :       mResponseType != XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT) {
     909               0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
     910                 :   }
     911                 : 
     912             351 :   if (mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT &&
     913               0 :       !mInLoadProgressEvent) {
     914               0 :     aResponseText.SetIsVoid(true);
     915               0 :     return NS_OK;
     916                 :   }
     917                 : 
     918             351 :   if (!(mState & (XML_HTTP_REQUEST_DONE | XML_HTTP_REQUEST_LOADING))) {
     919               0 :     return NS_OK;
     920                 :   }
     921                 : 
     922                 :   // We only decode text lazily if we're also parsing to a doc.
     923                 :   // Also, if we've decoded all current data already, then no need to decode
     924                 :   // more.
     925             696 :   if (!mResponseXML ||
     926             345 :       mResponseBodyDecodedPos == mResponseBody.Length()) {
     927              50 :     aResponseText = mResponseText;
     928              50 :     return NS_OK;
     929                 :   }
     930                 : 
     931                 :   nsresult rv;
     932                 : 
     933             602 :   nsCOMPtr<nsIDocument> document = do_QueryInterface(mResponseXML);
     934             301 :   if (mResponseCharset != document->GetDocumentCharacterSet()) {
     935               0 :     mResponseCharset = document->GetDocumentCharacterSet();
     936               0 :     mResponseText.Truncate();
     937               0 :     mResponseBodyDecodedPos = 0;
     938                 : 
     939                 :     nsCOMPtr<nsICharsetConverterManager> ccm =
     940               0 :       do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
     941               0 :     NS_ENSURE_SUCCESS(rv, rv);
     942                 : 
     943               0 :     rv = ccm->GetUnicodeDecoderRaw(mResponseCharset.get(),
     944               0 :                                    getter_AddRefs(mDecoder));
     945               0 :     NS_ENSURE_SUCCESS(rv, rv);
     946                 :   }
     947                 : 
     948             301 :   NS_ASSERTION(mResponseBodyDecodedPos < mResponseBody.Length(),
     949                 :                "Unexpected mResponseBodyDecodedPos");
     950             301 :   rv = AppendToResponseText(mResponseBody.get() + mResponseBodyDecodedPos,
     951             602 :                             mResponseBody.Length() - mResponseBodyDecodedPos);
     952             301 :   NS_ENSURE_SUCCESS(rv, rv);
     953                 : 
     954             301 :   mResponseBodyDecodedPos = mResponseBody.Length();
     955                 :   
     956             301 :   if (mState & XML_HTTP_REQUEST_DONE) {
     957                 :     // Free memory buffer which we no longer need
     958             301 :     mResponseBody.Truncate();
     959             301 :     mResponseBodyDecodedPos = 0;
     960                 :   }
     961                 : 
     962             301 :   aResponseText = mResponseText;
     963                 : 
     964             301 :   return NS_OK;
     965                 : }
     966                 : 
     967                 : nsresult
     968               0 : nsXMLHttpRequest::CreateResponseParsedJSON(JSContext* aCx)
     969                 : {
     970               0 :   if (!aCx) {
     971               0 :     return NS_ERROR_FAILURE;
     972                 :   }
     973                 :   // The Unicode converter has already zapped the BOM if there was one
     974               0 :   if (!JS_ParseJSON(aCx,
     975               0 :                     (jschar*)mResponseText.get(),
     976               0 :                     mResponseText.Length(), &mResultJSON)) {
     977               0 :     return NS_ERROR_FAILURE;
     978                 :   }
     979                 : 
     980               0 :   return NS_OK;
     981                 : }
     982                 : 
     983                 : nsresult
     984               0 : nsXMLHttpRequest::CreatePartialBlob()
     985                 : {
     986               0 :   if (mDOMFile) {
     987               0 :     if (mLoadTotal == mLoadTransferred) {
     988               0 :       mResponseBlob = mDOMFile;
     989                 :     } else {
     990                 :       mResponseBlob =
     991               0 :         mDOMFile->CreateSlice(0, mLoadTransferred, EmptyString());
     992                 :     }
     993               0 :     return NS_OK;
     994                 :   }
     995                 : 
     996               0 :   nsCAutoString contentType;
     997               0 :   if (mLoadTotal == mLoadTransferred) {
     998               0 :     mChannel->GetContentType(contentType);
     999                 :   }
    1000                 : 
    1001               0 :   return mBuilder->GetBlobInternal(NS_ConvertASCIItoUTF16(contentType),
    1002               0 :                                    false, getter_AddRefs(mResponseBlob));
    1003                 : }
    1004                 : 
    1005                 : /* attribute AString responseType; */
    1006               0 : NS_IMETHODIMP nsXMLHttpRequest::GetResponseType(nsAString& aResponseType)
    1007                 : {
    1008               0 :   switch (mResponseType) {
    1009                 :   case XML_HTTP_RESPONSE_TYPE_DEFAULT:
    1010               0 :     aResponseType.Truncate();
    1011               0 :     break;
    1012                 :   case XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER:
    1013               0 :     aResponseType.AssignLiteral("arraybuffer");
    1014               0 :     break;
    1015                 :   case XML_HTTP_RESPONSE_TYPE_BLOB:
    1016               0 :     aResponseType.AssignLiteral("blob");
    1017               0 :     break;
    1018                 :   case XML_HTTP_RESPONSE_TYPE_DOCUMENT:
    1019               0 :     aResponseType.AssignLiteral("document");
    1020               0 :     break;
    1021                 :   case XML_HTTP_RESPONSE_TYPE_TEXT:
    1022               0 :     aResponseType.AssignLiteral("text");
    1023               0 :     break;
    1024                 :   case XML_HTTP_RESPONSE_TYPE_JSON:
    1025               0 :     aResponseType.AssignLiteral("json");
    1026               0 :     break;
    1027                 :   case XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT:
    1028               0 :     aResponseType.AssignLiteral("moz-chunked-text");
    1029               0 :     break;
    1030                 :   case XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER:
    1031               0 :     aResponseType.AssignLiteral("moz-chunked-arraybuffer");
    1032               0 :     break;
    1033                 :   case XML_HTTP_RESPONSE_TYPE_MOZ_BLOB:
    1034               0 :     aResponseType.AssignLiteral("moz-blob");
    1035               0 :     break;
    1036                 :   default:
    1037               0 :     NS_ERROR("Should not happen");
    1038                 :   }
    1039                 : 
    1040               0 :   return NS_OK;
    1041                 : }
    1042                 : 
    1043                 : /* attribute AString responseType; */
    1044               1 : NS_IMETHODIMP nsXMLHttpRequest::SetResponseType(const nsAString& aResponseType)
    1045                 : {
    1046                 :   // If the state is not OPENED or HEADERS_RECEIVED raise an
    1047                 :   // INVALID_STATE_ERR exception and terminate these steps.
    1048               1 :   if (!(mState & (XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT |
    1049               1 :                   XML_HTTP_REQUEST_HEADERS_RECEIVED)))
    1050               0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
    1051                 : 
    1052                 :   // sync request is not allowed setting responseType in window context
    1053               1 :   if (HasOrHasHadOwner() &&
    1054               0 :       !(mState & (XML_HTTP_REQUEST_UNSENT | XML_HTTP_REQUEST_ASYNC))) {
    1055               0 :     LogMessage("ResponseTypeSyncXHRWarning", GetOwner());
    1056               0 :     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
    1057                 :   }
    1058                 : 
    1059                 :   // Set the responseType attribute's value to the given value.
    1060               1 :   if (aResponseType.IsEmpty()) {
    1061               1 :     mResponseType = XML_HTTP_RESPONSE_TYPE_DEFAULT;
    1062               0 :   } else if (aResponseType.EqualsLiteral("arraybuffer")) {
    1063               0 :     mResponseType = XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER;
    1064               0 :   } else if (aResponseType.EqualsLiteral("blob")) {
    1065               0 :     mResponseType = XML_HTTP_RESPONSE_TYPE_BLOB;
    1066               0 :   } else if (aResponseType.EqualsLiteral("document")) {
    1067               0 :     mResponseType = XML_HTTP_RESPONSE_TYPE_DOCUMENT;
    1068               0 :   } else if (aResponseType.EqualsLiteral("text")) {
    1069               0 :     mResponseType = XML_HTTP_RESPONSE_TYPE_TEXT;
    1070               0 :   } else if (aResponseType.EqualsLiteral("json")) {
    1071               0 :     mResponseType = XML_HTTP_RESPONSE_TYPE_JSON;
    1072               0 :   } else if (aResponseType.EqualsLiteral("moz-chunked-text")) {
    1073               0 :     if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
    1074               0 :       return NS_ERROR_DOM_INVALID_STATE_ERR;
    1075                 :     }
    1076               0 :     mResponseType = XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT;
    1077               0 :   } else if (aResponseType.EqualsLiteral("moz-chunked-arraybuffer")) {
    1078               0 :     if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
    1079               0 :       return NS_ERROR_DOM_INVALID_STATE_ERR;
    1080                 :     }
    1081               0 :     mResponseType = XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER;
    1082               0 :   } else if (aResponseType.EqualsLiteral("moz-blob")) {
    1083               0 :     mResponseType = XML_HTTP_RESPONSE_TYPE_MOZ_BLOB;
    1084                 :   }
    1085                 :   // If the given value is not the empty string, "arraybuffer",
    1086                 :   // "blob", "document", or "text" terminate these steps.
    1087                 : 
    1088                 :   // If the state is OPENED, SetCacheAsFile would have no effect here
    1089                 :   // because the channel hasn't initialized the cache entry yet.
    1090                 :   // SetCacheAsFile will be called from OnStartRequest.
    1091                 :   // If the state is HEADERS_RECEIVED, however, we need to call
    1092                 :   // it immediately because OnStartRequest is already dispatched.
    1093               1 :   if (mState & XML_HTTP_REQUEST_HEADERS_RECEIVED) {
    1094               0 :     nsCOMPtr<nsICachingChannel> cc(do_QueryInterface(mChannel));
    1095               0 :     if (cc) {
    1096               0 :       cc->SetCacheAsFile(mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB ||
    1097               0 :                          mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB);
    1098                 :     }
    1099                 :   }
    1100                 : 
    1101               1 :   return NS_OK;
    1102                 : }
    1103                 : 
    1104                 : /* readonly attribute jsval response; */
    1105               0 : NS_IMETHODIMP nsXMLHttpRequest::GetResponse(JSContext *aCx, jsval *aResult)
    1106                 : {
    1107               0 :   nsresult rv = NS_OK;
    1108                 : 
    1109               0 :   switch (mResponseType) {
    1110                 :   case XML_HTTP_RESPONSE_TYPE_DEFAULT:
    1111                 :   case XML_HTTP_RESPONSE_TYPE_TEXT:
    1112                 :   case XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT:
    1113                 :     {
    1114               0 :       nsString str;
    1115               0 :       rv = GetResponseText(str);
    1116               0 :       if (NS_FAILED(rv)) return rv;
    1117               0 :       NS_ENSURE_TRUE(xpc::StringToJsval(aCx, str, aResult),
    1118                 :                      NS_ERROR_OUT_OF_MEMORY);
    1119                 :     }
    1120               0 :     break;
    1121                 : 
    1122                 :   case XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER:
    1123                 :   case XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER:
    1124               0 :     if ((mResponseType == XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER &&
    1125                 :          mState & XML_HTTP_REQUEST_DONE) ||
    1126                 :         (mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER &&
    1127                 :          mInLoadProgressEvent)) {
    1128               0 :       if (!mResultArrayBuffer) {
    1129               0 :          RootResultArrayBuffer();
    1130                 :          rv = nsContentUtils::CreateArrayBuffer(aCx, mResponseBody,
    1131               0 :                                                 &mResultArrayBuffer);
    1132               0 :          NS_ENSURE_SUCCESS(rv, rv);
    1133                 :       }
    1134               0 :       *aResult = OBJECT_TO_JSVAL(mResultArrayBuffer);
    1135                 :     } else {
    1136               0 :       *aResult = JSVAL_NULL;
    1137                 :     }
    1138               0 :     break;
    1139                 : 
    1140                 :   case XML_HTTP_RESPONSE_TYPE_BLOB:
    1141                 :   case XML_HTTP_RESPONSE_TYPE_MOZ_BLOB:
    1142               0 :     *aResult = JSVAL_NULL;
    1143               0 :     if (mState & XML_HTTP_REQUEST_DONE) {
    1144                 :       // do nothing here
    1145               0 :     } else if (mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB) {
    1146               0 :       if (!mResponseBlob) {
    1147               0 :         rv = CreatePartialBlob();
    1148               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1149                 :       }
    1150                 :     } else {
    1151               0 :       return rv;
    1152                 :     }
    1153               0 :     if (mResponseBlob) {
    1154               0 :       JSObject* scope = JS_GetGlobalForScopeChain(aCx);
    1155                 :       rv = nsContentUtils::WrapNative(aCx, scope, mResponseBlob, aResult,
    1156               0 :                                       nsnull, true);
    1157                 :     }
    1158               0 :     break;
    1159                 : 
    1160                 :   case XML_HTTP_RESPONSE_TYPE_DOCUMENT:
    1161               0 :     if (mState & XML_HTTP_REQUEST_DONE && mResponseXML) {
    1162               0 :       JSObject* scope = JS_GetGlobalForScopeChain(aCx);
    1163                 :       rv = nsContentUtils::WrapNative(aCx, scope, mResponseXML, aResult,
    1164               0 :                                       nsnull, true);
    1165                 :     } else {
    1166               0 :       *aResult = JSVAL_NULL;
    1167                 :     }
    1168               0 :     break;
    1169                 : 
    1170                 :   case XML_HTTP_RESPONSE_TYPE_JSON:
    1171               0 :     if (mState & XML_HTTP_REQUEST_DONE) {
    1172               0 :       if (mResultJSON == JSVAL_VOID) {
    1173               0 :         rv = CreateResponseParsedJSON(aCx);
    1174               0 :         mResponseText.Truncate();
    1175               0 :         if (NS_FAILED(rv)) {
    1176                 :           // Per spec, errors aren't propagated. null is returned instead.
    1177               0 :           rv = NS_OK;
    1178                 :           // It would be nice to log the error to the console. That's hard to
    1179                 :           // do without calling window.onerror as a side effect, though.
    1180               0 :           JS_ClearPendingException(aCx);
    1181               0 :           mResultJSON = JSVAL_NULL;
    1182                 :         }
    1183                 :       }
    1184               0 :       *aResult = mResultJSON;
    1185                 :     } else {
    1186               0 :       *aResult = JSVAL_NULL;
    1187                 :     }
    1188               0 :     break;
    1189                 : 
    1190                 :   default:
    1191               0 :     NS_ERROR("Should not happen");
    1192                 :   }
    1193                 : 
    1194               0 :   return rv;
    1195                 : }
    1196                 : 
    1197                 : /* readonly attribute unsigned long status; */
    1198                 : NS_IMETHODIMP
    1199             538 : nsXMLHttpRequest::GetStatus(PRUint32 *aStatus)
    1200                 : {
    1201             538 :   *aStatus = 0;
    1202                 : 
    1203             538 :   if (mState & XML_HTTP_REQUEST_USE_XSITE_AC) {
    1204                 :     // Make sure we don't leak status information from denied cross-site
    1205                 :     // requests.
    1206               0 :     if (mChannel) {
    1207                 :       nsresult status;
    1208               0 :       mChannel->GetStatus(&status);
    1209               0 :       if (NS_FAILED(status)) {
    1210               0 :         return NS_OK;
    1211                 :       }
    1212                 :     }
    1213                 :   }
    1214                 : 
    1215            1076 :   nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
    1216                 : 
    1217             538 :   if (httpChannel) {
    1218             538 :     nsresult rv = httpChannel->GetResponseStatus(aStatus);
    1219             538 :     if (rv == NS_ERROR_NOT_AVAILABLE) {
    1220                 :       // Someone's calling this before we got a response... Check our
    1221                 :       // ReadyState.  If we're at 3 or 4, then this means the connection
    1222                 :       // errored before we got any data; return 0 in that case.
    1223                 :       PRUint16 readyState;
    1224              68 :       GetReadyState(&readyState);
    1225              68 :       if (readyState >= LOADING) {
    1226              68 :         *aStatus = 0;
    1227              68 :         return NS_OK;
    1228                 :       }
    1229                 :     }
    1230                 : 
    1231             470 :     return rv;
    1232                 :   }
    1233                 : 
    1234               0 :   return NS_OK;
    1235                 : }
    1236                 : 
    1237                 : /* readonly attribute AUTF8String statusText; */
    1238                 : NS_IMETHODIMP
    1239               0 : nsXMLHttpRequest::GetStatusText(nsACString& aStatusText)
    1240                 : {
    1241               0 :   nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
    1242                 : 
    1243               0 :   aStatusText.Truncate();
    1244                 : 
    1245               0 :   if (httpChannel) {
    1246               0 :     if (mState & XML_HTTP_REQUEST_USE_XSITE_AC) {
    1247                 :       // Make sure we don't leak status information from denied cross-site
    1248                 :       // requests.
    1249               0 :       if (mChannel) {
    1250                 :         nsresult status;
    1251               0 :         mChannel->GetStatus(&status);
    1252               0 :         if (NS_FAILED(status)) {
    1253               0 :           return NS_OK;
    1254                 :         }
    1255                 :       }
    1256                 :     }
    1257                 : 
    1258               0 :     httpChannel->GetResponseStatusText(aStatusText);
    1259                 :   }
    1260                 : 
    1261               0 :   return NS_OK;
    1262                 : }
    1263                 : 
    1264                 : void
    1265              12 : nsXMLHttpRequest::CloseRequestWithError(const nsAString& aType,
    1266                 :                                         const PRUint32 aFlag)
    1267                 : {
    1268              12 :   if (mReadRequest) {
    1269               0 :     mReadRequest->Cancel(NS_BINDING_ABORTED);
    1270                 :   }
    1271              12 :   if (mChannel) {
    1272              12 :     mChannel->Cancel(NS_BINDING_ABORTED);
    1273                 :   }
    1274              12 :   if (mCORSPreflightChannel) {
    1275               0 :     mCORSPreflightChannel->Cancel(NS_BINDING_ABORTED);
    1276                 :   }
    1277              12 :   if (mTimeoutTimer) {
    1278               0 :     mTimeoutTimer->Cancel();
    1279                 :   }
    1280              12 :   PRUint32 responseLength = mResponseBody.Length();
    1281              12 :   ResetResponse();
    1282              12 :   mState |= aFlag;
    1283                 : 
    1284                 :   // If we're in the destructor, don't risk dispatching an event.
    1285              12 :   if (mState & XML_HTTP_REQUEST_DELETED) {
    1286               0 :     mState &= ~XML_HTTP_REQUEST_SYNCLOOPING;
    1287               0 :     return;
    1288                 :   }
    1289                 : 
    1290              12 :   if (!(mState & (XML_HTTP_REQUEST_UNSENT |
    1291                 :                   XML_HTTP_REQUEST_OPENED |
    1292              12 :                   XML_HTTP_REQUEST_DONE))) {
    1293              12 :     ChangeState(XML_HTTP_REQUEST_DONE, true);
    1294                 : 
    1295              12 :     if (!(mState & XML_HTTP_REQUEST_SYNCLOOPING)) {
    1296                 :       DispatchProgressEvent(this, aType, mLoadLengthComputable, responseLength,
    1297              12 :                             mLoadTotal);
    1298              12 :       if (mUpload && !mUploadComplete) {
    1299               0 :         mUploadComplete = true;
    1300                 :         DispatchProgressEvent(mUpload, aType, true, mUploadTransferred,
    1301               0 :                               mUploadTotal);
    1302                 :       }
    1303                 :     }
    1304                 :   }
    1305                 : 
    1306                 :   // The ChangeState call above calls onreadystatechange handlers which
    1307                 :   // if they load a new url will cause nsXMLHttpRequest::Open to clear
    1308                 :   // the abort state bit. If this occurs we're not uninitialized (bug 361773).
    1309              12 :   if (mState & XML_HTTP_REQUEST_ABORTED) {
    1310              12 :     ChangeState(XML_HTTP_REQUEST_UNSENT, false);  // IE seems to do it
    1311                 :   }
    1312                 : 
    1313              12 :   mState &= ~XML_HTTP_REQUEST_SYNCLOOPING;
    1314                 : }
    1315                 : 
    1316                 : /* void abort (); */
    1317                 : NS_IMETHODIMP
    1318              12 : nsXMLHttpRequest::Abort()
    1319                 : {
    1320              12 :   CloseRequestWithError(NS_LITERAL_STRING(ABORT_STR), XML_HTTP_REQUEST_ABORTED);
    1321              12 :   return NS_OK;
    1322                 : }
    1323                 : 
    1324                 : /* DOMString getAllResponseHeaders(); */
    1325                 : NS_IMETHODIMP
    1326               0 : nsXMLHttpRequest::GetAllResponseHeaders(nsAString& aResponseHeaders)
    1327                 : {
    1328               0 :   aResponseHeaders.Truncate();
    1329                 : 
    1330                 :   // If the state is UNSENT or OPENED,
    1331                 :   // return the empty string and terminate these steps.
    1332               0 :   if (mState & (XML_HTTP_REQUEST_UNSENT |
    1333                 :                 XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT)) {
    1334               0 :     return NS_OK;
    1335                 :   }
    1336                 : 
    1337               0 :   if (mState & XML_HTTP_REQUEST_USE_XSITE_AC) {
    1338               0 :     return NS_OK;
    1339                 :   }
    1340                 : 
    1341               0 :   if (nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel()) {
    1342               0 :     nsRefPtr<nsHeaderVisitor> visitor = new nsHeaderVisitor();
    1343               0 :     if (NS_SUCCEEDED(httpChannel->VisitResponseHeaders(visitor))) {
    1344               0 :       aResponseHeaders = NS_ConvertUTF8toUTF16(visitor->Headers());
    1345                 :     }
    1346               0 :     return NS_OK;
    1347                 :   }
    1348                 : 
    1349               0 :   if (!mChannel) {
    1350               0 :     return NS_OK;
    1351                 :   }
    1352                 : 
    1353                 :   // Even non-http channels supply content type.
    1354               0 :   nsCAutoString value;
    1355               0 :   if (NS_SUCCEEDED(mChannel->GetContentType(value))) {
    1356               0 :     aResponseHeaders.AppendLiteral("Content-Type: ");
    1357               0 :     aResponseHeaders.Append(NS_ConvertUTF8toUTF16(value));
    1358               0 :     if (NS_SUCCEEDED(mChannel->GetContentCharset(value)) &&
    1359               0 :         !value.IsEmpty()) {
    1360               0 :       aResponseHeaders.AppendLiteral(";charset=");
    1361               0 :       aResponseHeaders.Append(NS_ConvertUTF8toUTF16(value));
    1362                 :     }
    1363               0 :     aResponseHeaders.Append('\n');
    1364                 :   }
    1365               0 :   return NS_OK;
    1366                 : }
    1367                 : 
    1368                 : /* ACString getResponseHeader (in AUTF8String header); */
    1369                 : NS_IMETHODIMP
    1370              34 : nsXMLHttpRequest::GetResponseHeader(const nsACString& header,
    1371                 :                                     nsACString& _retval)
    1372                 : {
    1373              34 :   nsresult rv = NS_OK;
    1374              34 :   _retval.SetIsVoid(true);
    1375                 : 
    1376              68 :   nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
    1377                 : 
    1378              34 :   if (!httpChannel) {
    1379                 :     // If the state is UNSENT or OPENED,
    1380                 :     // return null and terminate these steps.
    1381               0 :     if (mState & (XML_HTTP_REQUEST_UNSENT |
    1382                 :                   XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT)) {
    1383               0 :       return NS_OK;
    1384                 :     }
    1385                 : 
    1386                 :     // Even non-http channels supply content type.
    1387                 :     // Remember we don't leak header information from denied cross-site
    1388                 :     // requests.
    1389                 :     nsresult status;
    1390               0 :     if (!mChannel ||
    1391               0 :         NS_FAILED(mChannel->GetStatus(&status)) ||
    1392               0 :         NS_FAILED(status) ||
    1393               0 :         !header.LowerCaseEqualsASCII("content-type")) {
    1394               0 :       return NS_OK;
    1395                 :     }
    1396                 : 
    1397               0 :     if (NS_FAILED(mChannel->GetContentType(_retval))) {
    1398                 :       // Means no content type
    1399               0 :       _retval.SetIsVoid(true);
    1400               0 :       return NS_OK;
    1401                 :     }
    1402                 : 
    1403               0 :     nsCString value;
    1404               0 :     if (NS_SUCCEEDED(mChannel->GetContentCharset(value)) &&
    1405               0 :         !value.IsEmpty()) {
    1406               0 :       _retval.Append(";charset=");
    1407               0 :       _retval.Append(value);
    1408                 :     }
    1409                 : 
    1410               0 :     return NS_OK;
    1411                 :   }
    1412                 : 
    1413                 :   // See bug #380418. Hide "Set-Cookie" headers from non-chrome scripts.
    1414              34 :   bool chrome = false; // default to false in case IsCapabilityEnabled fails
    1415              34 :   IsCapabilityEnabled("UniversalXPConnect", &chrome);
    1416              34 :   if (!chrome &&
    1417               0 :        (header.LowerCaseEqualsASCII("set-cookie") ||
    1418               0 :         header.LowerCaseEqualsASCII("set-cookie2"))) {
    1419               0 :     NS_WARNING("blocked access to response header");
    1420               0 :     return NS_OK;
    1421                 :   }
    1422                 : 
    1423                 :   // Check for dangerous headers
    1424              34 :   if (mState & XML_HTTP_REQUEST_USE_XSITE_AC) {
    1425                 :     // Make sure we don't leak header information from denied cross-site
    1426                 :     // requests.
    1427               0 :     if (mChannel) {
    1428                 :       nsresult status;
    1429               0 :       mChannel->GetStatus(&status);
    1430               0 :       if (NS_FAILED(status)) {
    1431               0 :         return NS_OK;
    1432                 :       }
    1433                 :     }
    1434                 : 
    1435                 :     const char *kCrossOriginSafeHeaders[] = {
    1436                 :       "cache-control", "content-language", "content-type", "expires",
    1437                 :       "last-modified", "pragma"
    1438               0 :     };
    1439               0 :     bool safeHeader = false;
    1440                 :     PRUint32 i;
    1441               0 :     for (i = 0; i < ArrayLength(kCrossOriginSafeHeaders); ++i) {
    1442               0 :       if (header.LowerCaseEqualsASCII(kCrossOriginSafeHeaders[i])) {
    1443               0 :         safeHeader = true;
    1444               0 :         break;
    1445                 :       }
    1446                 :     }
    1447                 : 
    1448               0 :     if (!safeHeader) {
    1449               0 :       nsCAutoString headerVal;
    1450                 :       // The "Access-Control-Expose-Headers" header contains a comma separated
    1451                 :       // list of method names.
    1452               0 :       httpChannel->
    1453               0 :         GetResponseHeader(NS_LITERAL_CSTRING("Access-Control-Expose-Headers"),
    1454               0 :                           headerVal);
    1455               0 :       nsCCharSeparatedTokenizer exposeTokens(headerVal, ',');
    1456               0 :       while(exposeTokens.hasMoreTokens()) {
    1457               0 :         const nsDependentCSubstring& token = exposeTokens.nextToken();
    1458               0 :         if (token.IsEmpty()) {
    1459               0 :           continue;
    1460                 :         }
    1461               0 :         if (!IsValidHTTPToken(token)) {
    1462               0 :           return NS_OK;
    1463                 :         }
    1464               0 :         if (header.Equals(token, nsCaseInsensitiveCStringComparator())) {
    1465               0 :           safeHeader = true;
    1466                 :         }
    1467                 :       }
    1468                 :     }
    1469                 : 
    1470               0 :     if (!safeHeader) {
    1471               0 :       return NS_OK;
    1472                 :     }
    1473                 :   }
    1474                 : 
    1475              34 :   rv = httpChannel->GetResponseHeader(header, _retval);
    1476              34 :   if (rv == NS_ERROR_NOT_AVAILABLE) {
    1477                 :     // Means no header
    1478               0 :     _retval.SetIsVoid(true);
    1479               0 :     rv = NS_OK;
    1480                 :   }
    1481                 : 
    1482              34 :   return rv;
    1483                 : }
    1484                 : 
    1485                 : already_AddRefed<nsILoadGroup>
    1486             597 : nsXMLHttpRequest::GetLoadGroup() const
    1487                 : {
    1488             597 :   if (mState & XML_HTTP_REQUEST_BACKGROUND) {                 
    1489              87 :     return nsnull;
    1490                 :   }
    1491                 : 
    1492             510 :   nsresult rv = NS_ERROR_FAILURE;
    1493                 :   nsIScriptContext* sc =
    1494             510 :     const_cast<nsXMLHttpRequest*>(this)->GetContextForEventHandlers(&rv);
    1495                 :   nsCOMPtr<nsIDocument> doc =
    1496            1020 :     nsContentUtils::GetDocumentFromScriptContext(sc);
    1497             510 :   if (doc) {
    1498               0 :     return doc->GetDocumentLoadGroup();
    1499                 :   }
    1500                 : 
    1501             510 :   return nsnull;
    1502                 : }
    1503                 : 
    1504                 : nsresult
    1505            2813 : nsXMLHttpRequest::CreateReadystatechangeEvent(nsIDOMEvent** aDOMEvent)
    1506                 : {
    1507                 :   nsresult rv = nsEventDispatcher::CreateEvent(nsnull, nsnull,
    1508            2813 :                                                NS_LITERAL_STRING("Events"),
    1509            2813 :                                                aDOMEvent);
    1510            2813 :   if (NS_FAILED(rv)) {
    1511               0 :     return rv;
    1512                 :   }
    1513                 : 
    1514            5626 :   nsCOMPtr<nsIPrivateDOMEvent> privevent(do_QueryInterface(*aDOMEvent));
    1515            2813 :   if (!privevent) {
    1516               0 :     NS_IF_RELEASE(*aDOMEvent);
    1517               0 :     return NS_ERROR_FAILURE;
    1518                 :   }
    1519                 : 
    1520            2813 :   (*aDOMEvent)->InitEvent(NS_LITERAL_STRING(READYSTATE_STR),
    1521            2813 :                           false, false);
    1522                 : 
    1523                 :   // We assume anyone who managed to call CreateReadystatechangeEvent is trusted
    1524            2813 :   privevent->SetTrusted(true);
    1525                 : 
    1526            2813 :   return NS_OK;
    1527                 : }
    1528                 : 
    1529                 : void
    1530            2253 : nsXMLHttpRequest::DispatchProgressEvent(nsDOMEventTargetHelper* aTarget,
    1531                 :                                         const nsAString& aType,
    1532                 :                                         bool aUseLSEventWrapper,
    1533                 :                                         bool aLengthComputable,
    1534                 :                                         PRUint64 aLoaded, PRUint64 aTotal,
    1535                 :                                         PRUint64 aPosition, PRUint64 aTotalSize)
    1536                 : {
    1537            2253 :   NS_ASSERTION(aTarget, "null target");
    1538            2253 :   NS_ASSERTION(!aType.IsEmpty(), "missing event type");
    1539                 : 
    1540            4506 :   if (NS_FAILED(CheckInnerWindowCorrectness()) ||
    1541            2253 :       (!AllowUploadProgress() &&
    1542               0 :        (aTarget == mUpload || aType.EqualsLiteral(UPLOADPROGRESS_STR)))) {
    1543               0 :     return;
    1544                 :   }
    1545                 : 
    1546            2253 :   bool dispatchLoadend = aType.EqualsLiteral(LOAD_STR) ||
    1547            1740 :                            aType.EqualsLiteral(ERROR_STR) ||
    1548            1669 :                            aType.EqualsLiteral(TIMEOUT_STR) ||
    1549            5662 :                            aType.EqualsLiteral(ABORT_STR);
    1550                 :   
    1551            4506 :   nsCOMPtr<nsIDOMEvent> event;
    1552                 :   nsresult rv = nsEventDispatcher::CreateEvent(nsnull, nsnull,
    1553            2253 :                                                NS_LITERAL_STRING("ProgressEvent"),
    1554            4506 :                                                getter_AddRefs(event));
    1555            2253 :   if (NS_FAILED(rv)) {
    1556                 :     return;
    1557                 :   }
    1558                 : 
    1559            4506 :   nsCOMPtr<nsIPrivateDOMEvent> privevent(do_QueryInterface(event));
    1560            2253 :   if (!privevent) {
    1561                 :     return;
    1562                 :   }
    1563            2253 :   privevent->SetTrusted(true);
    1564                 : 
    1565            4506 :   nsCOMPtr<nsIDOMProgressEvent> progress = do_QueryInterface(event);
    1566            2253 :   if (!progress) {
    1567                 :     return;
    1568                 :   }
    1569                 : 
    1570            2253 :   progress->InitProgressEvent(aType, false, false, aLengthComputable,
    1571            2253 :                               aLoaded, (aTotal == LL_MAXUINT) ? 0 : aTotal);
    1572                 : 
    1573            2253 :   if (aUseLSEventWrapper) {
    1574                 :     nsCOMPtr<nsIDOMProgressEvent> xhrprogressEvent =
    1575            1566 :       new nsXMLHttpProgressEvent(progress, aPosition, aTotalSize, GetOwner());
    1576             522 :     event = xhrprogressEvent;
    1577                 :   }
    1578            2253 :   aTarget->DispatchDOMEvent(nsnull, event, nsnull, nsnull);
    1579                 :   
    1580            2253 :   if (dispatchLoadend) {
    1581             596 :     DispatchProgressEvent(aTarget, NS_LITERAL_STRING(LOADEND_STR),
    1582                 :                           aUseLSEventWrapper, aLengthComputable,
    1583             596 :                           aLoaded, aTotal, aPosition, aTotalSize);
    1584                 :   }
    1585                 : }
    1586                 :                                           
    1587                 : already_AddRefed<nsIHttpChannel>
    1588             572 : nsXMLHttpRequest::GetCurrentHttpChannel()
    1589                 : {
    1590             572 :   nsIHttpChannel *httpChannel = nsnull;
    1591                 : 
    1592             572 :   if (mReadRequest) {
    1593               0 :     CallQueryInterface(mReadRequest, &httpChannel);
    1594                 :   }
    1595                 : 
    1596             572 :   if (!httpChannel && mChannel) {
    1597             572 :     CallQueryInterface(mChannel, &httpChannel);
    1598                 :   }
    1599                 : 
    1600             572 :   return httpChannel;
    1601                 : }
    1602                 : 
    1603                 : bool
    1604            2874 : nsXMLHttpRequest::IsSystemXHR()
    1605                 : {
    1606            2874 :   return !!nsContentUtils::IsSystemPrincipal(mPrincipal);
    1607                 : }
    1608                 : 
    1609                 : nsresult
    1610             631 : nsXMLHttpRequest::CheckChannelForCrossSiteRequest(nsIChannel* aChannel)
    1611                 : {
    1612                 :   // First check if cross-site requests are enabled...
    1613             631 :   if (IsSystemXHR()) {
    1614             631 :     return NS_OK;
    1615                 :   }
    1616                 : 
    1617                 :   // ...or if this is a same-origin request.
    1618               0 :   if (nsContentUtils::CheckMayLoad(mPrincipal, aChannel)) {
    1619               0 :     return NS_OK;
    1620                 :   }
    1621                 : 
    1622                 :   // exempt data URIs from the same origin check.
    1623               0 :   nsCOMPtr<nsIURI> channelURI;
    1624               0 :   bool dataScheme = false;
    1625               0 :   if (NS_SUCCEEDED(NS_GetFinalChannelURI(aChannel,
    1626                 :                                          getter_AddRefs(channelURI))) &&
    1627               0 :       NS_SUCCEEDED(channelURI->SchemeIs("data", &dataScheme)) &&
    1628                 :       dataScheme) {
    1629               0 :     return NS_OK;
    1630                 :   }
    1631                 : 
    1632                 :   // This is a cross-site request
    1633               0 :   mState |= XML_HTTP_REQUEST_USE_XSITE_AC;
    1634                 : 
    1635                 :   // Check if we need to do a preflight request.
    1636               0 :   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
    1637               0 :   NS_ENSURE_TRUE(httpChannel, NS_ERROR_DOM_BAD_URI);
    1638                 : 
    1639               0 :   nsCAutoString method;
    1640               0 :   httpChannel->GetRequestMethod(method);
    1641               0 :   if (!mCORSUnsafeHeaders.IsEmpty() ||
    1642               0 :       HasListenersFor(NS_LITERAL_STRING(UPLOADPROGRESS_STR)) ||
    1643               0 :       (mUpload && mUpload->HasListeners()) ||
    1644               0 :       (!method.LowerCaseEqualsLiteral("get") &&
    1645               0 :        !method.LowerCaseEqualsLiteral("post") &&
    1646               0 :        !method.LowerCaseEqualsLiteral("head"))) {
    1647               0 :     mState |= XML_HTTP_REQUEST_NEED_AC_PREFLIGHT;
    1648                 :   }
    1649                 : 
    1650               0 :   return NS_OK;
    1651                 : }
    1652                 : 
    1653                 : NS_IMETHODIMP
    1654             597 : nsXMLHttpRequest::Open(const nsACString& method, const nsACString& url,
    1655                 :                        bool async, const nsAString& user,
    1656                 :                        const nsAString& password, PRUint8 optional_argc)
    1657                 : {
    1658             597 :   NS_ENSURE_ARG(!method.IsEmpty());
    1659                 : 
    1660             597 :   if (!optional_argc) {
    1661                 :     // No optional arguments were passed in. Default async to true.
    1662               0 :     async = true;
    1663                 :   }
    1664                 :   Telemetry::Accumulate(Telemetry::XMLHTTPREQUEST_ASYNC_OR_SYNC,
    1665             597 :                         async ? 0 : 1);
    1666                 : 
    1667             597 :   NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED);
    1668                 : 
    1669                 :   // Disallow HTTP/1.1 TRACE method (see bug 302489)
    1670                 :   // and MS IIS equivalent TRACK (see bug 381264)
    1671            1194 :   if (method.LowerCaseEqualsLiteral("trace") ||
    1672             597 :       method.LowerCaseEqualsLiteral("track")) {
    1673               0 :     return NS_ERROR_INVALID_ARG;
    1674                 :   }
    1675                 : 
    1676                 :   // sync request is not allowed using withCredential or responseType
    1677                 :   // in window context
    1678             597 :   if (!async && HasOrHasHadOwner() &&
    1679                 :       (mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS ||
    1680                 :        mTimeoutMilliseconds ||
    1681                 :        mResponseType != XML_HTTP_RESPONSE_TYPE_DEFAULT)) {
    1682               0 :     if (mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS) {
    1683               0 :       LogMessage("WithCredentialsSyncXHRWarning", GetOwner());
    1684                 :     }
    1685               0 :     if (mTimeoutMilliseconds) {
    1686               0 :       LogMessage("TimeoutSyncXHRWarning", GetOwner());
    1687                 :     }
    1688               0 :     if (mResponseType != XML_HTTP_RESPONSE_TYPE_DEFAULT) {
    1689               0 :       LogMessage("ResponseTypeSyncXHRWarning", GetOwner());
    1690                 :     }
    1691               0 :     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
    1692                 :   }
    1693                 : 
    1694                 :   nsresult rv;
    1695            1194 :   nsCOMPtr<nsIURI> uri;
    1696                 : 
    1697             597 :   if (mState & (XML_HTTP_REQUEST_OPENED |
    1698                 :                 XML_HTTP_REQUEST_HEADERS_RECEIVED |
    1699                 :                 XML_HTTP_REQUEST_LOADING |
    1700                 :                 XML_HTTP_REQUEST_SENT |
    1701                 :                 XML_HTTP_REQUEST_STOPPED)) {
    1702                 :     // IE aborts as well
    1703               0 :     Abort();
    1704                 : 
    1705                 :     // XXX We should probably send a warning to the JS console
    1706                 :     //     that load was aborted and event listeners were cleared
    1707                 :     //     since this looks like a situation that could happen
    1708                 :     //     by accident and you could spend a lot of time wondering
    1709                 :     //     why things didn't work.
    1710                 :   }
    1711                 : 
    1712                 :   // Unset any pre-existing aborted and timed-out states.
    1713             597 :   mState &= ~XML_HTTP_REQUEST_ABORTED & ~XML_HTTP_REQUEST_TIMED_OUT;
    1714                 : 
    1715             597 :   if (async) {
    1716             539 :     mState |= XML_HTTP_REQUEST_ASYNC;
    1717                 :   } else {
    1718              58 :     mState &= ~XML_HTTP_REQUEST_ASYNC;
    1719                 :   }
    1720                 : 
    1721             597 :   mState &= ~XML_HTTP_REQUEST_MPART_HEADERS;
    1722                 : 
    1723             597 :   nsIScriptContext* sc = GetContextForEventHandlers(&rv);
    1724             597 :   NS_ENSURE_SUCCESS(rv, rv);
    1725                 :   nsCOMPtr<nsIDocument> doc =
    1726            1194 :     nsContentUtils::GetDocumentFromScriptContext(sc);
    1727                 :   
    1728            1194 :   nsCOMPtr<nsIURI> baseURI;
    1729             597 :   if (mBaseURI) {
    1730               0 :     baseURI = mBaseURI;
    1731                 :   }
    1732             597 :   else if (doc) {
    1733               0 :     baseURI = doc->GetBaseURI();
    1734                 :   }
    1735                 : 
    1736             597 :   rv = NS_NewURI(getter_AddRefs(uri), url, nsnull, baseURI);
    1737             597 :   if (NS_FAILED(rv)) return rv;
    1738                 : 
    1739             597 :   rv = CheckInnerWindowCorrectness();
    1740             597 :   NS_ENSURE_SUCCESS(rv, rv);
    1741             597 :   PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
    1742                 :   rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_XMLHTTPREQUEST,
    1743                 :                                  uri,
    1744                 :                                  mPrincipal,
    1745                 :                                  doc,
    1746             597 :                                  EmptyCString(), //mime guess
    1747                 :                                  nsnull,         //extra
    1748                 :                                  &shouldLoad,
    1749                 :                                  nsContentUtils::GetContentPolicy(),
    1750            1194 :                                  nsContentUtils::GetSecurityManager());
    1751             597 :   if (NS_FAILED(rv)) return rv;
    1752             597 :   if (NS_CP_REJECTED(shouldLoad)) {
    1753                 :     // Disallowed by content policy
    1754               0 :     return NS_ERROR_CONTENT_BLOCKED;
    1755                 :   }
    1756                 : 
    1757             597 :   if (!user.IsEmpty()) {
    1758               0 :     nsCAutoString userpass;
    1759               0 :     CopyUTF16toUTF8(user, userpass);
    1760               0 :     if (!password.IsEmpty()) {
    1761               0 :       userpass.Append(':');
    1762               0 :       AppendUTF16toUTF8(password, userpass);
    1763                 :     }
    1764               0 :     uri->SetUserPass(userpass);
    1765                 :   }
    1766                 : 
    1767                 :   // When we are called from JS we can find the load group for the page,
    1768                 :   // and add ourselves to it. This way any pending requests
    1769                 :   // will be automatically aborted if the user leaves the page.
    1770            1194 :   nsCOMPtr<nsILoadGroup> loadGroup = GetLoadGroup();
    1771                 : 
    1772                 :   // get Content Security Policy from principal to pass into channel
    1773            1194 :   nsCOMPtr<nsIChannelPolicy> channelPolicy;
    1774            1194 :   nsCOMPtr<nsIContentSecurityPolicy> csp;
    1775             597 :   rv = mPrincipal->GetCsp(getter_AddRefs(csp));
    1776             597 :   NS_ENSURE_SUCCESS(rv, rv);
    1777             597 :   if (csp) {
    1778               0 :     channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
    1779               0 :     channelPolicy->SetContentSecurityPolicy(csp);
    1780               0 :     channelPolicy->SetLoadType(nsIContentPolicy::TYPE_XMLHTTPREQUEST);
    1781                 :   }
    1782             597 :   rv = NS_NewChannel(getter_AddRefs(mChannel),
    1783                 :                      uri,
    1784                 :                      nsnull,                    // ioService
    1785                 :                      loadGroup,
    1786                 :                      nsnull,                    // callbacks
    1787                 :                      nsIRequest::LOAD_BACKGROUND,
    1788             597 :                      channelPolicy);
    1789             597 :   if (NS_FAILED(rv)) return rv;
    1790                 : 
    1791                 :   mState &= ~(XML_HTTP_REQUEST_USE_XSITE_AC |
    1792             597 :               XML_HTTP_REQUEST_NEED_AC_PREFLIGHT);
    1793                 : 
    1794            1194 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
    1795             597 :   if (httpChannel) {
    1796             595 :     rv = httpChannel->SetRequestMethod(method);
    1797             595 :     NS_ENSURE_SUCCESS(rv, rv);
    1798                 :   }
    1799                 : 
    1800             597 :   ChangeState(XML_HTTP_REQUEST_OPENED);
    1801                 : 
    1802             597 :   return rv;
    1803                 : }
    1804                 : 
    1805                 : /*
    1806                 :  * "Copy" from a stream.
    1807                 :  */
    1808                 : NS_METHOD
    1809             563 : nsXMLHttpRequest::StreamReaderFunc(nsIInputStream* in,
    1810                 :                                    void* closure,
    1811                 :                                    const char* fromRawSegment,
    1812                 :                                    PRUint32 toOffset,
    1813                 :                                    PRUint32 count,
    1814                 :                                    PRUint32 *writeCount)
    1815                 : {
    1816             563 :   nsXMLHttpRequest* xmlHttpRequest = static_cast<nsXMLHttpRequest*>(closure);
    1817             563 :   if (!xmlHttpRequest || !writeCount) {
    1818               0 :     NS_WARNING("XMLHttpRequest cannot read from stream: no closure or writeCount");
    1819               0 :     return NS_ERROR_FAILURE;
    1820                 :   }
    1821                 : 
    1822             563 :   nsresult rv = NS_OK;
    1823                 : 
    1824             563 :   if (xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB ||
    1825                 :       xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB) {
    1826               0 :     if (!xmlHttpRequest->mDOMFile) {
    1827               0 :       if (!xmlHttpRequest->mBuilder) {
    1828               0 :         xmlHttpRequest->mBuilder = new nsDOMBlobBuilder();
    1829                 :       }
    1830               0 :       rv = xmlHttpRequest->mBuilder->AppendVoidPtr(fromRawSegment, count);
    1831                 :     }
    1832                 :     // Clear the cache so that the blob size is updated.
    1833               0 :     if (xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB) {
    1834               0 :       xmlHttpRequest->mResponseBlob = nsnull;
    1835                 :     }
    1836               0 :     if (NS_SUCCEEDED(rv)) {
    1837               0 :       *writeCount = count;
    1838                 :     }
    1839               0 :     return rv;
    1840                 :   }
    1841                 : 
    1842            1126 :   if ((xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_DEFAULT &&
    1843             563 :        xmlHttpRequest->mResponseXML) ||
    1844                 :       xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER ||
    1845                 :       xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER) {
    1846                 :     // Copy for our own use
    1847             556 :     PRUint32 previousLength = xmlHttpRequest->mResponseBody.Length();
    1848             556 :     xmlHttpRequest->mResponseBody.Append(fromRawSegment,count);
    1849             556 :     if (count > 0 && xmlHttpRequest->mResponseBody.Length() == previousLength) {
    1850               0 :       return NS_ERROR_OUT_OF_MEMORY;
    1851                 :     }
    1852               7 :   } else if (xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_DEFAULT ||
    1853                 :              xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_TEXT ||
    1854                 :              xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_JSON ||
    1855                 :              xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT) {
    1856               7 :     NS_ASSERTION(!xmlHttpRequest->mResponseXML,
    1857                 :                  "We shouldn't be parsing a doc here");
    1858               7 :     xmlHttpRequest->AppendToResponseText(fromRawSegment, count);
    1859                 :   }
    1860                 : 
    1861             563 :   if (xmlHttpRequest->mState & XML_HTTP_REQUEST_PARSEBODY) {
    1862                 :     // Give the same data to the parser.
    1863                 : 
    1864                 :     // We need to wrap the data in a new lightweight stream and pass that
    1865                 :     // to the parser, because calling ReadSegments() recursively on the same
    1866                 :     // stream is not supported.
    1867            1112 :     nsCOMPtr<nsIInputStream> copyStream;
    1868             556 :     rv = NS_NewByteInputStream(getter_AddRefs(copyStream), fromRawSegment, count);
    1869                 : 
    1870             556 :     if (NS_SUCCEEDED(rv) && xmlHttpRequest->mXMLParserStreamListener) {
    1871             556 :       NS_ASSERTION(copyStream, "NS_NewByteInputStream lied");
    1872                 :       nsresult parsingResult = xmlHttpRequest->mXMLParserStreamListener
    1873             556 :                                   ->OnDataAvailable(xmlHttpRequest->mReadRequest,
    1874                 :                                                     xmlHttpRequest->mContext,
    1875             556 :                                                     copyStream, toOffset, count);
    1876                 : 
    1877                 :       // No use to continue parsing if we failed here, but we
    1878                 :       // should still finish reading the stream
    1879             556 :       if (NS_FAILED(parsingResult)) {
    1880               0 :         xmlHttpRequest->mState &= ~XML_HTTP_REQUEST_PARSEBODY;
    1881                 :       }
    1882                 :     }
    1883                 :   }
    1884                 : 
    1885             563 :   if (NS_SUCCEEDED(rv)) {
    1886             563 :     *writeCount = count;
    1887                 :   } else {
    1888               0 :     *writeCount = 0;
    1889                 :   }
    1890                 : 
    1891             563 :   return rv;
    1892                 : }
    1893                 : 
    1894               0 : bool nsXMLHttpRequest::CreateDOMFile(nsIRequest *request)
    1895                 : {
    1896               0 :   nsCOMPtr<nsIFile> file;
    1897               0 :   nsCOMPtr<nsICachingChannel> cc(do_QueryInterface(request));
    1898               0 :   if (cc) {
    1899               0 :     cc->GetCacheFile(getter_AddRefs(file));
    1900                 :   } else {
    1901               0 :     nsCOMPtr<nsIFileChannel> fc = do_QueryInterface(request);
    1902               0 :     if (fc) {
    1903               0 :       fc->GetFile(getter_AddRefs(file));
    1904                 :     }
    1905                 :   }
    1906               0 :   bool fromFile = false;
    1907               0 :   if (file) {
    1908               0 :     nsCAutoString contentType;
    1909               0 :     mChannel->GetContentType(contentType);
    1910               0 :     nsCOMPtr<nsISupports> cacheToken;
    1911               0 :     if (cc) {
    1912               0 :       cc->GetCacheToken(getter_AddRefs(cacheToken));
    1913                 :       // We need to call IsFromCache to determine whether the response is
    1914                 :       // fully cached (i.e. whether we can skip reading the response).
    1915               0 :       cc->IsFromCache(&fromFile);
    1916                 :     } else {
    1917                 :       // If the response is coming from the local resource, we can skip
    1918                 :       // reading the response unconditionally.
    1919               0 :       fromFile = true;
    1920                 :     }
    1921                 : 
    1922                 :     mDOMFile =
    1923               0 :       new nsDOMFileFile(file, NS_ConvertASCIItoUTF16(contentType), cacheToken);
    1924               0 :     mBuilder = nsnull;
    1925               0 :     NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty");
    1926                 :   }
    1927               0 :   return fromFile;
    1928                 : }
    1929                 : 
    1930                 : NS_IMETHODIMP
    1931             563 : nsXMLHttpRequest::OnDataAvailable(nsIRequest *request,
    1932                 :                                   nsISupports *ctxt,
    1933                 :                                   nsIInputStream *inStr,
    1934                 :                                   PRUint32 sourceOffset,
    1935                 :                                   PRUint32 count)
    1936                 : {
    1937             563 :   NS_ENSURE_ARG_POINTER(inStr);
    1938                 : 
    1939             563 :   NS_ABORT_IF_FALSE(mContext.get() == ctxt,"start context different from OnDataAvailable context");
    1940                 : 
    1941             563 :   mProgressSinceLastProgressEvent = true;
    1942                 : 
    1943             563 :   bool cancelable = false;
    1944             563 :   if ((mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB ||
    1945               0 :        mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB) && !mDOMFile) {
    1946               0 :     cancelable = CreateDOMFile(request);
    1947                 :     // The nsIStreamListener contract mandates us
    1948                 :     // to read from the stream before returning.
    1949                 :   }
    1950                 : 
    1951                 :   PRUint32 totalRead;
    1952                 :   nsresult rv = inStr->ReadSegments(nsXMLHttpRequest::StreamReaderFunc,
    1953             563 :                                     (void*)this, count, &totalRead);
    1954             563 :   NS_ENSURE_SUCCESS(rv, rv);
    1955                 : 
    1956             563 :   if (cancelable) {
    1957                 :     // We don't have to read from the local file for the blob response
    1958               0 :     mDOMFile->GetSize(&mLoadTransferred);
    1959               0 :     ChangeState(XML_HTTP_REQUEST_LOADING);
    1960               0 :     return request->Cancel(NS_OK);
    1961                 :   }
    1962                 : 
    1963             563 :   mLoadTransferred += totalRead;
    1964                 : 
    1965             563 :   ChangeState(XML_HTTP_REQUEST_LOADING);
    1966                 :   
    1967             563 :   MaybeDispatchProgressEvents(false);
    1968                 : 
    1969             563 :   return NS_OK;
    1970                 : }
    1971                 : 
    1972                 : bool
    1973            1192 : IsSameOrBaseChannel(nsIRequest* aPossibleBase, nsIChannel* aChannel)
    1974                 : {
    1975            2384 :   nsCOMPtr<nsIMultiPartChannel> mpChannel = do_QueryInterface(aPossibleBase);
    1976            1192 :   if (mpChannel) {
    1977               0 :     nsCOMPtr<nsIChannel> baseChannel;
    1978               0 :     nsresult rv = mpChannel->GetBaseChannel(getter_AddRefs(baseChannel));
    1979               0 :     NS_ENSURE_SUCCESS(rv, false);
    1980                 :     
    1981               0 :     return baseChannel == aChannel;
    1982                 :   }
    1983                 : 
    1984            1192 :   return aPossibleBase == aChannel;
    1985                 : }
    1986                 : 
    1987                 : /* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
    1988                 : NS_IMETHODIMP
    1989             596 : nsXMLHttpRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
    1990                 : {
    1991            1192 :   SAMPLE_LABEL("nsXMLHttpRequest", "OnStartRequest");
    1992             596 :   nsresult rv = NS_OK;
    1993             596 :   if (!mFirstStartRequestSeen && mRequestObserver) {
    1994               0 :     mFirstStartRequestSeen = true;
    1995               0 :     mRequestObserver->OnStartRequest(request, ctxt);
    1996                 :   }
    1997                 : 
    1998             596 :   if (!IsSameOrBaseChannel(request, mChannel)) {
    1999               0 :     return NS_OK;
    2000                 :   }
    2001                 : 
    2002                 :   // Don't do anything if we have been aborted
    2003             596 :   if (mState & XML_HTTP_REQUEST_UNSENT)
    2004              12 :     return NS_OK;
    2005                 : 
    2006                 :   /* Apparently, Abort() should set XML_HTTP_REQUEST_UNSENT.  See bug 361773.
    2007                 :      XHR2 spec says this is correct. */
    2008             584 :   if (mState & XML_HTTP_REQUEST_ABORTED) {
    2009               0 :     NS_ERROR("Ugh, still getting data on an aborted XMLHttpRequest!");
    2010                 : 
    2011               0 :     return NS_ERROR_UNEXPECTED;
    2012                 :   }
    2013                 : 
    2014                 :   // Don't do anything if we have timed out.
    2015             584 :   if (mState & XML_HTTP_REQUEST_TIMED_OUT) {
    2016               0 :     return NS_OK;
    2017                 :   }
    2018                 : 
    2019            1168 :   nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
    2020             584 :   NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED);
    2021                 : 
    2022            1168 :   nsCOMPtr<nsIPrincipal> documentPrincipal;
    2023             584 :   if (IsSystemXHR()) {
    2024                 :     // Don't give this document the system principal.  We need to keep track of
    2025                 :     // mPrincipal being system because we use it for various security checks
    2026                 :     // that should be passing, but the document data shouldn't get a system
    2027                 :     // principal.
    2028                 :     nsresult rv;
    2029             584 :     documentPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
    2030             584 :     NS_ENSURE_SUCCESS(rv, rv);
    2031                 :   } else {
    2032               0 :     documentPrincipal = mPrincipal;
    2033                 :   }
    2034                 : 
    2035             584 :   channel->SetOwner(documentPrincipal);
    2036                 : 
    2037                 :   nsresult status;
    2038             584 :   request->GetStatus(&status);
    2039             584 :   mErrorLoad = mErrorLoad || NS_FAILED(status);
    2040                 : 
    2041             584 :   if (mUpload && !mUploadComplete && !mErrorLoad &&
    2042                 :       (mState & XML_HTTP_REQUEST_ASYNC)) {
    2043               0 :     if (mProgressTimerIsActive) {
    2044               0 :       mProgressTimerIsActive = false;
    2045               0 :       mProgressNotifier->Cancel();
    2046                 :     }
    2047               0 :     MaybeDispatchProgressEvents(true);
    2048               0 :     mUploadComplete = true;
    2049               0 :     DispatchProgressEvent(mUpload, NS_LITERAL_STRING(LOAD_STR),
    2050               0 :                           true, mUploadTotal, mUploadTotal);
    2051                 :   }
    2052                 : 
    2053             584 :   mReadRequest = request;
    2054             584 :   mContext = ctxt;
    2055             584 :   mState |= XML_HTTP_REQUEST_PARSEBODY;
    2056             584 :   mState &= ~XML_HTTP_REQUEST_MPART_HEADERS;
    2057             584 :   ChangeState(XML_HTTP_REQUEST_HEADERS_RECEIVED);
    2058                 : 
    2059             584 :   if (mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB ||
    2060                 :       mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB) {
    2061               0 :     nsCOMPtr<nsICachingChannel> cc(do_QueryInterface(mChannel));
    2062               0 :     if (cc) {
    2063               0 :       cc->SetCacheAsFile(true);
    2064                 :     }
    2065                 :   }
    2066                 : 
    2067             584 :   ResetResponse();
    2068                 : 
    2069             584 :   if (!mOverrideMimeType.IsEmpty()) {
    2070             522 :     channel->SetContentType(mOverrideMimeType);
    2071                 :   }
    2072                 : 
    2073             584 :   DetectCharset();
    2074                 : 
    2075                 :   // Set up responseXML
    2076                 :   bool parseBody = mResponseType == XML_HTTP_RESPONSE_TYPE_DEFAULT ||
    2077             584 :                      mResponseType == XML_HTTP_RESPONSE_TYPE_DOCUMENT;
    2078            1168 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
    2079             584 :   if (parseBody && httpChannel) {
    2080            1166 :     nsCAutoString method;
    2081             583 :     httpChannel->GetRequestMethod(method);
    2082             583 :     parseBody = !method.EqualsLiteral("HEAD");
    2083                 :   }
    2084                 : 
    2085             584 :   mIsHtml = false;
    2086             584 :   mWarnAboutMultipartHtml = false;
    2087             584 :   mWarnAboutSyncHtml = false;
    2088             584 :   if (parseBody && NS_SUCCEEDED(status)) {
    2089                 :     // We can gain a huge performance win by not even trying to
    2090                 :     // parse non-XML data. This also protects us from the situation
    2091                 :     // where we have an XML document and sink, but HTML (or other)
    2092                 :     // parser, which can produce unreliable results.
    2093            1010 :     nsCAutoString type;
    2094             505 :     channel->GetContentType(type);
    2095                 : 
    2096             505 :     if ((mResponseType == XML_HTTP_RESPONSE_TYPE_DOCUMENT) &&
    2097               0 :         type.EqualsLiteral("text/html")) {
    2098                 :       // HTML parsing is only supported for responseType == "document" to
    2099                 :       // avoid running the parser and, worse, populating responseXML for
    2100                 :       // legacy users of XHR who use responseType == "" for retrieving the
    2101                 :       // responseText of text/html resources. This legacy case is so common
    2102                 :       // that it's not useful to emit a warning about it.
    2103               0 :       if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
    2104                 :         // We don't make cool new features available in the bad synchronous
    2105                 :         // mode. The synchronous mode is for legacy only.
    2106               0 :         mWarnAboutSyncHtml = true;
    2107               0 :         mState &= ~XML_HTTP_REQUEST_PARSEBODY;
    2108               0 :       } else if (mState & XML_HTTP_REQUEST_MULTIPART) {
    2109                 :         // HTML parsing is supported only for non-multipart responses. The
    2110                 :         // multipart implementation assumes that it's OK to start the next part
    2111                 :         // immediately after the last part. That doesn't work with the HTML
    2112                 :         // parser, because when OnStopRequest for one part has fired, the
    2113                 :         // parser thread still hasn't posted back the runnables that make the
    2114                 :         // parsing appear finished.
    2115                 :         //
    2116                 :         // On the other hand, multipart support seems to be a legacy feature,
    2117                 :         // so it isn't clear that use cases justify adding support for deferring
    2118                 :         // the multipart stream events between parts to accommodate the
    2119                 :         // asynchronous nature of the HTML parser.
    2120               0 :         mWarnAboutMultipartHtml = true;
    2121               0 :         mState &= ~XML_HTTP_REQUEST_PARSEBODY;
    2122                 :       } else {
    2123               0 :         mIsHtml = true;
    2124                 :       }
    2125             505 :     } else if (type.Find("xml") == kNotFound) {
    2126              37 :       mState &= ~XML_HTTP_REQUEST_PARSEBODY;
    2127             505 :     }
    2128                 :   } else {
    2129                 :     // The request failed, so we shouldn't be parsing anyway
    2130              79 :     mState &= ~XML_HTTP_REQUEST_PARSEBODY;
    2131                 :   }
    2132                 : 
    2133             584 :   if (mState & XML_HTTP_REQUEST_PARSEBODY) {
    2134             936 :     nsCOMPtr<nsIURI> baseURI, docURI;
    2135             468 :     nsIScriptContext* sc = GetContextForEventHandlers(&rv);
    2136             468 :     NS_ENSURE_SUCCESS(rv, rv);
    2137                 :     nsCOMPtr<nsIDocument> doc =
    2138             936 :       nsContentUtils::GetDocumentFromScriptContext(sc);
    2139                 : 
    2140             468 :     if (doc) {
    2141               0 :       docURI = doc->GetDocumentURI();
    2142               0 :       baseURI = doc->GetBaseURI();
    2143                 :     }
    2144                 : 
    2145                 :     // Create an empty document from it.  Here we have to cheat a little bit...
    2146                 :     // Setting the base URI to |baseURI| won't work if the document has a null
    2147                 :     // principal, so use mPrincipal when creating the document, then reset the
    2148                 :     // principal.
    2149             468 :     const nsAString& emptyStr = EmptyString();
    2150             936 :     nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(GetOwner());
    2151                 :     rv = nsContentUtils::CreateDocument(emptyStr, emptyStr, nsnull, docURI,
    2152                 :                                         baseURI, mPrincipal, global,
    2153                 :                                         mIsHtml ? DocumentFlavorHTML :
    2154                 :                                                   DocumentFlavorLegacyGuess,
    2155             468 :                                         getter_AddRefs(mResponseXML));
    2156             468 :     NS_ENSURE_SUCCESS(rv, rv);
    2157             936 :     nsCOMPtr<nsIDocument> responseDoc = do_QueryInterface(mResponseXML);
    2158             468 :     responseDoc->SetPrincipal(documentPrincipal);
    2159                 : 
    2160             468 :     if (IsSystemXHR()) {
    2161             468 :       responseDoc->ForceEnableXULXBL();
    2162                 :     }
    2163                 : 
    2164             468 :     if (mState & XML_HTTP_REQUEST_USE_XSITE_AC) {
    2165               0 :       nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mResponseXML);
    2166               0 :       if (htmlDoc) {
    2167               0 :         htmlDoc->DisableCookieAccess();
    2168                 :       }
    2169                 :     }
    2170                 : 
    2171             936 :     nsCOMPtr<nsIStreamListener> listener;
    2172             936 :     nsCOMPtr<nsILoadGroup> loadGroup;
    2173             468 :     channel->GetLoadGroup(getter_AddRefs(loadGroup));
    2174                 : 
    2175             468 :     rv = responseDoc->StartDocumentLoad(kLoadAsData, channel, loadGroup,
    2176             468 :                                         nsnull, getter_AddRefs(listener),
    2177             468 :                                         !(mState & XML_HTTP_REQUEST_USE_XSITE_AC));
    2178             468 :     NS_ENSURE_SUCCESS(rv, rv);
    2179                 : 
    2180             468 :     mXMLParserStreamListener = listener;
    2181             468 :     rv = mXMLParserStreamListener->OnStartRequest(request, ctxt);
    2182             468 :     NS_ENSURE_SUCCESS(rv, rv);
    2183                 :   }
    2184                 : 
    2185                 :   // We won't get any progress events anyway if we didn't have progress
    2186                 :   // events when starting the request - so maybe no need to start timer here.
    2187            2222 :   if (NS_SUCCEEDED(rv) &&
    2188                 :       (mState & XML_HTTP_REQUEST_ASYNC) &&
    2189            1638 :       HasListenersFor(NS_LITERAL_STRING(PROGRESS_STR))) {
    2190               0 :     StartProgressEventTimer();
    2191                 :   }
    2192                 : 
    2193             584 :   return NS_OK;
    2194                 : }
    2195                 : 
    2196                 : /* void onStopRequest (in nsIRequest request, in nsISupports ctxt, in nsresult status, in wstring statusArg); */
    2197                 : NS_IMETHODIMP
    2198             596 : nsXMLHttpRequest::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult status)
    2199                 : {
    2200            1192 :   SAMPLE_LABEL("content", "nsXMLHttpRequest::OnStopRequest");
    2201             596 :   if (!IsSameOrBaseChannel(request, mChannel)) {
    2202               0 :     return NS_OK;
    2203                 :   }
    2204                 : 
    2205             596 :   mWaitingForOnStopRequest = false;
    2206                 : 
    2207             596 :   nsresult rv = NS_OK;
    2208                 : 
    2209                 :   // If we're loading a multipart stream of XML documents, we'll get
    2210                 :   // an OnStopRequest() for the last part in the stream, and then
    2211                 :   // another one for the end of the initiating
    2212                 :   // "multipart/x-mixed-replace" stream too. So we must check that we
    2213                 :   // still have an xml parser stream listener before accessing it
    2214                 :   // here.
    2215            1192 :   nsCOMPtr<nsIMultiPartChannel> mpChannel = do_QueryInterface(request);
    2216             596 :   if (mpChannel) {
    2217                 :     bool last;
    2218               0 :     rv = mpChannel->GetIsLastPart(&last);
    2219               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2220               0 :     if (last) {
    2221               0 :       mState |= XML_HTTP_REQUEST_GOT_FINAL_STOP;
    2222                 :     }
    2223                 :   }
    2224                 :   else {
    2225             596 :     mState |= XML_HTTP_REQUEST_GOT_FINAL_STOP;
    2226                 :   }
    2227                 : 
    2228             596 :   if (mRequestObserver && mState & XML_HTTP_REQUEST_GOT_FINAL_STOP) {
    2229               0 :     NS_ASSERTION(mFirstStartRequestSeen, "Inconsistent state!");
    2230               0 :     mFirstStartRequestSeen = false;
    2231               0 :     mRequestObserver->OnStopRequest(request, ctxt, status);
    2232                 :   }
    2233                 : 
    2234                 :   // make sure to notify the listener if we were aborted
    2235                 :   // XXX in fact, why don't we do the cleanup below in this case??
    2236                 :   // XML_HTTP_REQUEST_UNSENT is for abort calls.  See OnStartRequest above.
    2237             596 :   if ((mState & XML_HTTP_REQUEST_UNSENT) ||
    2238                 :       (mState & XML_HTTP_REQUEST_TIMED_OUT)) {
    2239              12 :     if (mXMLParserStreamListener)
    2240               0 :       (void) mXMLParserStreamListener->OnStopRequest(request, ctxt, status);
    2241              12 :     return NS_OK;
    2242                 :   }
    2243                 : 
    2244                 :   // Is this good enough here?
    2245             584 :   if (mState & XML_HTTP_REQUEST_PARSEBODY && mXMLParserStreamListener) {
    2246             468 :     mXMLParserStreamListener->OnStopRequest(request, ctxt, status);
    2247                 :   }
    2248                 : 
    2249             584 :   mXMLParserStreamListener = nsnull;
    2250             584 :   mReadRequest = nsnull;
    2251             584 :   mContext = nsnull;
    2252                 : 
    2253                 :   // If we're received data since the last progress event, make sure to fire
    2254                 :   // an event for it, except in the HTML case, defer the last progress event
    2255                 :   // until the parser is done.
    2256             584 :   if (!mIsHtml) {
    2257             584 :     MaybeDispatchProgressEvents(true);
    2258                 :   }
    2259                 : 
    2260             584 :   if (NS_SUCCEEDED(status) &&
    2261                 :       (mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB ||
    2262                 :        mResponseType == XML_HTTP_RESPONSE_TYPE_MOZ_BLOB)) {
    2263               0 :     if (!mDOMFile) {
    2264               0 :       CreateDOMFile(request);
    2265                 :     }
    2266               0 :     if (mDOMFile) {
    2267               0 :       mResponseBlob = mDOMFile;
    2268               0 :       mDOMFile = nsnull;
    2269                 :     } else {
    2270                 :       // Smaller files may be written in cache map instead of separate files.
    2271                 :       // Also, no-store response cannot be written in persistent cache.
    2272               0 :       nsCAutoString contentType;
    2273               0 :       mChannel->GetContentType(contentType);
    2274               0 :       mBuilder->GetBlobInternal(NS_ConvertASCIItoUTF16(contentType),
    2275               0 :                                 false, getter_AddRefs(mResponseBlob));
    2276               0 :       mBuilder = nsnull;
    2277                 :     }
    2278               0 :     NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty");
    2279               0 :     NS_ASSERTION(mResponseText.IsEmpty(), "mResponseText should be empty");
    2280                 :   }
    2281                 : 
    2282            1168 :   nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
    2283             584 :   NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED);
    2284                 : 
    2285             584 :   channel->SetNotificationCallbacks(nsnull);
    2286             584 :   mNotificationCallbacks = nsnull;
    2287             584 :   mChannelEventSink = nsnull;
    2288             584 :   mProgressEventSink = nsnull;
    2289                 : 
    2290             584 :   mState &= ~XML_HTTP_REQUEST_SYNCLOOPING;
    2291                 : 
    2292             584 :   if (NS_FAILED(status)) {
    2293                 :     // This can happen if the server is unreachable. Other possible
    2294                 :     // reasons are that the user leaves the page or hits the ESC key.
    2295                 : 
    2296              71 :     mErrorLoad = true;
    2297              71 :     mResponseXML = nsnull;
    2298                 :   }
    2299                 : 
    2300                 :   // If we're uninitialized at this point, we encountered an error
    2301                 :   // earlier and listeners have already been notified. Also we do
    2302                 :   // not want to do this if we already completed.
    2303             584 :   if (mState & (XML_HTTP_REQUEST_UNSENT |
    2304                 :                 XML_HTTP_REQUEST_DONE)) {
    2305               0 :     return NS_OK;
    2306                 :   }
    2307                 : 
    2308             584 :   if (!mResponseXML) {
    2309             116 :     ChangeStateToDone();
    2310             116 :     return NS_OK;
    2311                 :   }
    2312             468 :   if (mIsHtml) {
    2313               0 :     NS_ASSERTION(!(mState & XML_HTTP_REQUEST_SYNCLOOPING),
    2314                 :       "We weren't supposed to support HTML parsing with XHR!");
    2315               0 :     nsCOMPtr<nsIDOMEventTarget> eventTarget = do_QueryInterface(mResponseXML);
    2316               0 :     nsEventListenerManager* manager = eventTarget->GetListenerManager(true);
    2317               0 :     manager->AddEventListenerByType(new nsXHRParseEndListener(this),
    2318               0 :                                     NS_LITERAL_STRING("DOMContentLoaded"),
    2319                 :                                     NS_EVENT_FLAG_BUBBLE |
    2320               0 :                                     NS_EVENT_FLAG_SYSTEM_EVENT);
    2321               0 :     return NS_OK;
    2322                 :   }
    2323                 :   // We might have been sent non-XML data. If that was the case,
    2324                 :   // we should null out the document member. The idea in this
    2325                 :   // check here is that if there is no document element it is not
    2326                 :   // an XML document. We might need a fancier check...
    2327             936 :   nsCOMPtr<nsIDOMElement> root;
    2328             468 :   mResponseXML->GetDocumentElement(getter_AddRefs(root));
    2329             468 :   if (!root) {
    2330               0 :     mResponseXML = nsnull;
    2331                 :   }
    2332             468 :   ChangeStateToDone();
    2333             468 :   return NS_OK;
    2334                 : }
    2335                 : 
    2336                 : void
    2337             584 : nsXMLHttpRequest::ChangeStateToDone()
    2338                 : {
    2339             584 :   if (mIsHtml) {
    2340                 :     // In the HTML case, this has to be deferred, because the parser doesn't
    2341                 :     // do it's job synchronously.
    2342               0 :     MaybeDispatchProgressEvents(true);
    2343                 :   }
    2344                 : 
    2345             584 :   ChangeState(XML_HTTP_REQUEST_DONE, true);
    2346             584 :   if (mTimeoutTimer) {
    2347               0 :     mTimeoutTimer->Cancel();
    2348                 :   }
    2349                 : 
    2350            1168 :   NS_NAMED_LITERAL_STRING(errorStr, ERROR_STR);
    2351            1168 :   NS_NAMED_LITERAL_STRING(loadStr, LOAD_STR);
    2352                 :   DispatchProgressEvent(this,
    2353                 :                         mErrorLoad ? errorStr : loadStr,
    2354             584 :                         !mErrorLoad,
    2355                 :                         mLoadTransferred,
    2356            1168 :                         mErrorLoad ? 0 : mLoadTransferred);
    2357             584 :   if (mErrorLoad && mUpload && !mUploadComplete) {
    2358                 :     DispatchProgressEvent(mUpload, errorStr, true,
    2359               0 :                           mUploadTransferred, mUploadTotal);
    2360                 :   }
    2361                 : 
    2362             584 :   if (mErrorLoad) {
    2363                 :     // By nulling out channel here we make it so that Send() can test
    2364                 :     // for that and throw. Also calling the various status
    2365                 :     // methods/members will not throw.
    2366                 :     // This matches what IE does.
    2367              71 :     mChannel = nsnull;
    2368                 :   }
    2369             513 :   else if (!(mState & XML_HTTP_REQUEST_GOT_FINAL_STOP)) {
    2370                 :     // We're a multipart request, so we're not done. Reset to opened.
    2371               0 :     ChangeState(XML_HTTP_REQUEST_OPENED);
    2372                 :   }
    2373             584 : }
    2374                 : 
    2375                 : NS_IMETHODIMP
    2376               0 : nsXMLHttpRequest::SendAsBinary(const nsAString &aBody)
    2377                 : {
    2378               0 :   char *data = static_cast<char*>(NS_Alloc(aBody.Length() + 1));
    2379               0 :   if (!data)
    2380               0 :     return NS_ERROR_OUT_OF_MEMORY;
    2381                 : 
    2382               0 :   nsAString::const_iterator iter, end;
    2383               0 :   aBody.BeginReading(iter);
    2384               0 :   aBody.EndReading(end);
    2385               0 :   char *p = data;
    2386               0 :   while (iter != end) {
    2387               0 :     if (*iter & 0xFF00) {
    2388               0 :       NS_Free(data);
    2389               0 :       return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
    2390                 :     }
    2391               0 :     *p++ = static_cast<char>(*iter++);
    2392                 :   }
    2393               0 :   *p = '\0';
    2394                 : 
    2395               0 :   nsCOMPtr<nsIInputStream> stream;
    2396               0 :   nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream), data,
    2397               0 :                                       aBody.Length(), NS_ASSIGNMENT_ADOPT);
    2398               0 :   if (NS_FAILED(rv))
    2399               0 :     NS_Free(data);
    2400               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2401                 : 
    2402               0 :   nsCOMPtr<nsIWritableVariant> variant = new nsVariant();
    2403               0 :   if (!variant) return NS_ERROR_OUT_OF_MEMORY;
    2404                 : 
    2405               0 :   rv = variant->SetAsISupports(stream);
    2406               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2407                 : 
    2408               0 :   return Send(variant);
    2409                 : }
    2410                 : 
    2411                 : static nsresult
    2412              44 : GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult,
    2413                 :                nsACString& aContentType, nsACString& aCharset)
    2414                 : {
    2415              44 :   *aResult = nsnull;
    2416              44 :   aContentType.AssignLiteral("text/plain");
    2417              44 :   aCharset.AssignLiteral("UTF-8");
    2418                 : 
    2419                 :   PRUint16 dataType;
    2420              44 :   nsresult rv = aBody->GetDataType(&dataType);
    2421              44 :   NS_ENSURE_SUCCESS(rv, rv);
    2422                 : 
    2423              44 :   if (dataType == nsIDataType::VTYPE_INTERFACE ||
    2424                 :       dataType == nsIDataType::VTYPE_INTERFACE_IS) {
    2425               8 :     nsCOMPtr<nsISupports> supports;
    2426                 :     nsID *iid;
    2427               4 :     rv = aBody->GetAsInterface(&iid, getter_AddRefs(supports));
    2428               4 :     NS_ENSURE_SUCCESS(rv, rv);
    2429                 : 
    2430               4 :     nsMemory::Free(iid);
    2431                 : 
    2432                 :     // document?
    2433               8 :     nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(supports);
    2434               4 :     if (doc) {
    2435               0 :       aContentType.AssignLiteral("application/xml");
    2436               0 :       nsAutoString inputEncoding;
    2437               0 :       doc->GetInputEncoding(inputEncoding);
    2438               0 :       if (!DOMStringIsNull(inputEncoding)) {
    2439               0 :         CopyUTF16toUTF8(inputEncoding, aCharset);
    2440                 :       }
    2441                 : 
    2442                 :       // Serialize to a stream so that the encoding used will
    2443                 :       // match the document's.
    2444                 :       nsCOMPtr<nsIDOMSerializer> serializer =
    2445               0 :         do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID, &rv);
    2446               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2447                 : 
    2448               0 :       nsCOMPtr<nsIStorageStream> storStream;
    2449                 :       rv = NS_NewStorageStream(4096, PR_UINT32_MAX,
    2450               0 :                                getter_AddRefs(storStream));
    2451               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2452                 : 
    2453               0 :       nsCOMPtr<nsIOutputStream> output;
    2454               0 :       rv = storStream->GetOutputStream(0, getter_AddRefs(output));
    2455               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2456                 : 
    2457                 :       // Make sure to use the encoding we'll send
    2458               0 :       rv = serializer->SerializeToStream(doc, output, aCharset);
    2459               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2460                 : 
    2461               0 :       output->Close();
    2462                 : 
    2463               0 :       return storStream->NewInputStream(0, aResult);
    2464                 :     }
    2465                 : 
    2466                 :     // nsISupportsString?
    2467               8 :     nsCOMPtr<nsISupportsString> wstr = do_QueryInterface(supports);
    2468               4 :     if (wstr) {
    2469               0 :       nsAutoString string;
    2470               0 :       wstr->GetData(string);
    2471                 : 
    2472                 :       return NS_NewCStringInputStream(aResult,
    2473               0 :                                       NS_ConvertUTF16toUTF8(string));
    2474                 :     }
    2475                 : 
    2476                 :     // nsIInputStream?
    2477               8 :     nsCOMPtr<nsIInputStream> stream = do_QueryInterface(supports);
    2478               4 :     if (stream) {
    2479               4 :       stream.forget(aResult);
    2480               4 :       aCharset.Truncate();
    2481                 : 
    2482               4 :       return NS_OK;
    2483                 :     }
    2484                 : 
    2485                 :     // nsIXHRSendable?
    2486               0 :     nsCOMPtr<nsIXHRSendable> sendable = do_QueryInterface(supports);
    2487               0 :     if (sendable) {
    2488               0 :       return sendable->GetSendInfo(aResult, aContentType, aCharset);
    2489                 :     }
    2490                 : 
    2491                 :     // ArrayBuffer?
    2492                 :     jsval realVal;
    2493                 :     JSObject* obj;
    2494               0 :     nsresult rv = aBody->GetAsJSVal(&realVal);
    2495               0 :     if (NS_SUCCEEDED(rv) && !JSVAL_IS_PRIMITIVE(realVal) &&
    2496                 :         (obj = JSVAL_TO_OBJECT(realVal)) &&
    2497               0 :         (js_IsArrayBuffer(obj))) {
    2498                 : 
    2499               0 :       aContentType.SetIsVoid(true);
    2500               0 :       PRInt32 abLength = JS_GetArrayBufferByteLength(obj);
    2501               0 :       char* data = (char*)JS_GetArrayBufferData(obj);
    2502                 : 
    2503               0 :       nsCOMPtr<nsIInputStream> stream;
    2504               0 :       nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream), data,
    2505               0 :                                           abLength, NS_ASSIGNMENT_COPY);
    2506               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2507               0 :       stream.forget(aResult);
    2508               0 :       aCharset.Truncate();
    2509                 : 
    2510               0 :       return NS_OK;
    2511               0 :     }
    2512                 :   }
    2513              40 :   else if (dataType == nsIDataType::VTYPE_VOID ||
    2514                 :            dataType == nsIDataType::VTYPE_EMPTY) {
    2515                 :     // Makes us act as if !aBody, don't upload anything
    2516              40 :     return NS_OK;
    2517                 :   }
    2518                 : 
    2519               0 :   PRUnichar* data = nsnull;
    2520               0 :   PRUint32 len = 0;
    2521               0 :   rv = aBody->GetAsWStringWithSize(&len, &data);
    2522               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2523                 : 
    2524               0 :   nsString string;
    2525               0 :   string.Adopt(data, len);
    2526                 : 
    2527               0 :   return NS_NewCStringInputStream(aResult, NS_ConvertUTF16toUTF8(string));
    2528                 : }
    2529                 : 
    2530                 : /* void send (in nsIVariant aBody); */
    2531                 : NS_IMETHODIMP
    2532             596 : nsXMLHttpRequest::Send(nsIVariant *aBody)
    2533                 : {
    2534             596 :   NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED);
    2535                 : 
    2536             596 :   nsresult rv = CheckInnerWindowCorrectness();
    2537             596 :   NS_ENSURE_SUCCESS(rv, rv);
    2538                 : 
    2539                 :   // Return error if we're already processing a request
    2540             596 :   if (XML_HTTP_REQUEST_SENT & mState) {
    2541               0 :     return NS_ERROR_FAILURE;
    2542                 :   }
    2543                 : 
    2544                 :   // Make sure we've been opened
    2545             596 :   if (!mChannel || !(XML_HTTP_REQUEST_OPENED & mState)) {
    2546               0 :     return NS_ERROR_NOT_INITIALIZED;
    2547                 :   }
    2548                 : 
    2549                 : 
    2550                 :   // nsIRequest::LOAD_BACKGROUND prevents throbber from becoming active, which
    2551                 :   // in turn keeps STOP button from becoming active.  If the consumer passed in
    2552                 :   // a progress event handler we must load with nsIRequest::LOAD_NORMAL or
    2553                 :   // necko won't generate any progress notifications.
    2554            2980 :   if (HasListenersFor(NS_LITERAL_STRING(PROGRESS_STR)) ||
    2555            1788 :       HasListenersFor(NS_LITERAL_STRING(UPLOADPROGRESS_STR)) ||
    2556            1192 :       (mUpload && mUpload->HasListenersFor(NS_LITERAL_STRING(PROGRESS_STR)))) {
    2557                 :     nsLoadFlags loadFlags;
    2558               0 :     mChannel->GetLoadFlags(&loadFlags);
    2559               0 :     loadFlags &= ~nsIRequest::LOAD_BACKGROUND;
    2560               0 :     loadFlags |= nsIRequest::LOAD_NORMAL;
    2561               0 :     mChannel->SetLoadFlags(loadFlags);
    2562                 :   }
    2563                 : 
    2564                 :   // XXX We should probably send a warning to the JS console
    2565                 :   //     if there are no event listeners set and we are doing
    2566                 :   //     an asynchronous call.
    2567                 : 
    2568                 :   // Ignore argument if method is GET, there is no point in trying to
    2569                 :   // upload anything
    2570            1192 :   nsCAutoString method;
    2571            1192 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
    2572                 : 
    2573             596 :   if (httpChannel) {
    2574             595 :     httpChannel->GetRequestMethod(method); // If GET, method name will be uppercase
    2575                 : 
    2576             595 :     if (!IsSystemXHR()) {
    2577                 :       // Get the referrer for the request.
    2578                 :       //
    2579                 :       // If it weren't for history.push/replaceState, we could just use the
    2580                 :       // principal's URI here.  But since we want changes to the URI effected
    2581                 :       // by push/replaceState to be reflected in the XHR referrer, we have to
    2582                 :       // be more clever.
    2583                 :       //
    2584                 :       // If the document's original URI (before any push/replaceStates) matches
    2585                 :       // our principal, then we use the document's current URI (after
    2586                 :       // push/replaceStates).  Otherwise (if the document is, say, a data:
    2587                 :       // URI), we just use the principal's URI.
    2588                 : 
    2589               0 :       nsCOMPtr<nsIURI> principalURI;
    2590               0 :       mPrincipal->GetURI(getter_AddRefs(principalURI));
    2591                 : 
    2592               0 :       nsIScriptContext* sc = GetContextForEventHandlers(&rv);
    2593               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2594                 :       nsCOMPtr<nsIDocument> doc =
    2595               0 :         nsContentUtils::GetDocumentFromScriptContext(sc);
    2596                 : 
    2597               0 :       nsCOMPtr<nsIURI> docCurURI;
    2598               0 :       nsCOMPtr<nsIURI> docOrigURI;
    2599               0 :       if (doc) {
    2600               0 :         docCurURI = doc->GetDocumentURI();
    2601               0 :         docOrigURI = doc->GetOriginalURI();
    2602                 :       }
    2603                 : 
    2604               0 :       nsCOMPtr<nsIURI> referrerURI;
    2605                 : 
    2606               0 :       if (principalURI && docCurURI && docOrigURI) {
    2607               0 :         bool equal = false;
    2608               0 :         principalURI->Equals(docOrigURI, &equal);
    2609               0 :         if (equal) {
    2610               0 :           referrerURI = docCurURI;
    2611                 :         }
    2612                 :       }
    2613                 : 
    2614               0 :       if (!referrerURI)
    2615               0 :         referrerURI = principalURI;
    2616                 : 
    2617               0 :       httpChannel->SetReferrer(referrerURI);
    2618                 :     }
    2619                 : 
    2620                 :     // Some extensions override the http protocol handler and provide their own
    2621                 :     // implementation. The channels returned from that implementation doesn't
    2622                 :     // seem to always implement the nsIUploadChannel2 interface, presumably
    2623                 :     // because it's a new interface.
    2624                 :     // Eventually we should remove this and simply require that http channels
    2625                 :     // implement the new interface.
    2626                 :     // See bug 529041
    2627                 :     nsCOMPtr<nsIUploadChannel2> uploadChannel2 =
    2628            1190 :       do_QueryInterface(httpChannel);
    2629             595 :     if (!uploadChannel2) {
    2630                 :       nsCOMPtr<nsIConsoleService> consoleService =
    2631               0 :         do_GetService(NS_CONSOLESERVICE_CONTRACTID);
    2632               0 :       if (consoleService) {
    2633               0 :         consoleService->LogStringMessage(NS_LITERAL_STRING(
    2634                 :           "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."
    2635               0 :                                                            ).get());
    2636                 :       }
    2637                 :     }
    2638                 :   }
    2639                 : 
    2640             596 :   mUploadTransferred = 0;
    2641             596 :   mUploadTotal = 0;
    2642                 :   // By default we don't have any upload, so mark upload complete.
    2643             596 :   mUploadComplete = true;
    2644             596 :   mErrorLoad = false;
    2645             596 :   mLoadLengthComputable = false;
    2646             596 :   mLoadTotal = 0;
    2647             596 :   mUploadProgress = 0;
    2648             596 :   mUploadProgressMax = 0;
    2649             596 :   if (aBody && httpChannel && !method.EqualsLiteral("GET")) {
    2650                 : 
    2651              88 :     nsCAutoString charset;
    2652              88 :     nsCAutoString defaultContentType;
    2653              88 :     nsCOMPtr<nsIInputStream> postDataStream;
    2654                 : 
    2655              44 :     rv = GetRequestBody(aBody, getter_AddRefs(postDataStream),
    2656              44 :                         defaultContentType, charset);
    2657              44 :     NS_ENSURE_SUCCESS(rv, rv);
    2658                 : 
    2659              44 :     if (postDataStream) {
    2660                 :       // If no content type header was set by the client, we set it to
    2661                 :       // application/xml.
    2662               8 :       nsCAutoString contentType;
    2663               8 :       if (NS_FAILED(httpChannel->
    2664                 :                       GetRequestHeader(NS_LITERAL_CSTRING("Content-Type"),
    2665                 :                                        contentType)) ||
    2666               4 :           contentType.IsEmpty()) {
    2667               0 :         contentType = defaultContentType;
    2668                 :       }
    2669                 : 
    2670                 :       // We don't want to set a charset for streams.
    2671               4 :       if (!charset.IsEmpty()) {
    2672               0 :         nsCAutoString specifiedCharset;
    2673                 :         bool haveCharset;
    2674                 :         PRInt32 charsetStart, charsetEnd;
    2675                 :         rv = NS_ExtractCharsetFromContentType(contentType, specifiedCharset,
    2676                 :                                               &haveCharset, &charsetStart,
    2677               0 :                                               &charsetEnd);
    2678               0 :         if (NS_SUCCEEDED(rv)) {
    2679                 :           // special case: the extracted charset is quoted with single quotes
    2680                 :           // -- for the purpose of preserving what was set we want to handle
    2681                 :           // them as delimiters (although they aren't really)
    2682               0 :           if (specifiedCharset.Length() >= 2 &&
    2683               0 :               specifiedCharset.First() == '\'' &&
    2684               0 :               specifiedCharset.Last() == '\'') {
    2685                 :             specifiedCharset = Substring(specifiedCharset, 1,
    2686               0 :                                          specifiedCharset.Length() - 2);
    2687                 :           }
    2688                 : 
    2689                 :           // If the content-type the page set already has a charset parameter,
    2690                 :           // and it's the same charset, up to case, as |charset|, just send the
    2691                 :           // page-set content-type header.  Apparently at least
    2692                 :           // google-web-toolkit is broken and relies on the exact case of its
    2693                 :           // charset parameter, which makes things break if we use |charset|
    2694                 :           // (which is always a fully resolved charset per our charset alias
    2695                 :           // table, hence might be differently cased).
    2696               0 :           if (!specifiedCharset.Equals(charset,
    2697               0 :                                        nsCaseInsensitiveCStringComparator())) {
    2698               0 :             nsCAutoString newCharset("; charset=");
    2699               0 :             newCharset.Append(charset);
    2700                 :             contentType.Replace(charsetStart, charsetEnd - charsetStart,
    2701               0 :                                 newCharset);
    2702                 :           }
    2703                 :         }
    2704                 :       }
    2705                 : 
    2706                 :       // If necessary, wrap the stream in a buffered stream so as to guarantee
    2707                 :       // support for our upload when calling ExplicitSetUploadStream.
    2708               4 :       if (!NS_InputStreamIsBuffered(postDataStream)) {
    2709               0 :         nsCOMPtr<nsIInputStream> bufferedStream;
    2710               0 :         rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
    2711                 :                                        postDataStream, 
    2712               0 :                                        4096);
    2713               0 :         NS_ENSURE_SUCCESS(rv, rv);
    2714                 : 
    2715               0 :         postDataStream = bufferedStream;
    2716                 :       }
    2717                 : 
    2718               4 :       mUploadComplete = false;
    2719               4 :       PRUint32 uploadTotal = 0;
    2720               4 :       postDataStream->Available(&uploadTotal);
    2721               4 :       mUploadTotal = uploadTotal;
    2722                 : 
    2723                 :       // We want to use a newer version of the upload channel that won't
    2724                 :       // ignore the necessary headers for an empty Content-Type.
    2725              12 :       nsCOMPtr<nsIUploadChannel2> uploadChannel2(do_QueryInterface(httpChannel));
    2726                 :       // This assertion will fire if buggy extensions are installed
    2727               4 :       NS_ASSERTION(uploadChannel2, "http must support nsIUploadChannel2");
    2728               4 :       if (uploadChannel2) {
    2729               4 :           uploadChannel2->ExplicitSetUploadStream(postDataStream, contentType,
    2730               4 :                                                  -1, method, false);
    2731                 :       }
    2732                 :       else {
    2733                 :         // http channel doesn't support the new nsIUploadChannel2. Emulate
    2734                 :         // as best we can using nsIUploadChannel
    2735               0 :         if (contentType.IsEmpty()) {
    2736               0 :           contentType.AssignLiteral("application/octet-stream");
    2737                 :         }
    2738                 :         nsCOMPtr<nsIUploadChannel> uploadChannel =
    2739               0 :           do_QueryInterface(httpChannel);
    2740               0 :         uploadChannel->SetUploadStream(postDataStream, contentType, -1);
    2741                 :         // Reset the method to its original value
    2742               0 :         httpChannel->SetRequestMethod(method);
    2743                 :       }
    2744                 :     }
    2745                 :   }
    2746                 : 
    2747             596 :   if (httpChannel) {
    2748            1190 :     nsCAutoString contentTypeHeader;
    2749            1190 :     rv = httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("Content-Type"),
    2750             595 :                                        contentTypeHeader);
    2751             595 :     if (NS_SUCCEEDED(rv)) {
    2752               8 :       nsCAutoString contentType, charset;
    2753               4 :       rv = NS_ParseContentType(contentTypeHeader, contentType, charset);
    2754               4 :       NS_ENSURE_SUCCESS(rv, rv);
    2755                 :   
    2756              12 :       if (!contentType.LowerCaseEqualsLiteral("text/plain") &&
    2757               4 :           !contentType.LowerCaseEqualsLiteral("application/x-www-form-urlencoded") &&
    2758               4 :           !contentType.LowerCaseEqualsLiteral("multipart/form-data")) {
    2759               4 :         mCORSUnsafeHeaders.AppendElement(NS_LITERAL_CSTRING("Content-Type"));
    2760                 :       }
    2761                 :     }
    2762                 :   }
    2763                 : 
    2764             596 :   ResetResponse();
    2765                 : 
    2766             596 :   rv = CheckChannelForCrossSiteRequest(mChannel);
    2767             596 :   NS_ENSURE_SUCCESS(rv, rv);
    2768                 : 
    2769             596 :   bool withCredentials = !!(mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS);
    2770                 : 
    2771                 :   // Hook us up to listen to redirects and the like
    2772             596 :   mChannel->GetNotificationCallbacks(getter_AddRefs(mNotificationCallbacks));
    2773             596 :   mChannel->SetNotificationCallbacks(this);
    2774                 : 
    2775                 :   // Create our listener
    2776            1192 :   nsCOMPtr<nsIStreamListener> listener = this;
    2777             596 :   if (mState & XML_HTTP_REQUEST_MULTIPART) {
    2778               0 :     listener = new nsMultipartProxyListener(listener);
    2779               0 :     if (!listener) {
    2780               0 :       return NS_ERROR_OUT_OF_MEMORY;
    2781                 :     }
    2782                 :   }
    2783                 : 
    2784             596 :   if (!IsSystemXHR()) {
    2785                 :     // Always create a nsCORSListenerProxy here even if it's
    2786                 :     // a same-origin request right now, since it could be redirected.
    2787                 :     listener = new nsCORSListenerProxy(listener, mPrincipal, mChannel,
    2788               0 :                                        withCredentials, true, &rv);
    2789               0 :     NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
    2790               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2791                 :   }
    2792                 : 
    2793                 :   // Bypass the network cache in cases where it makes no sense:
    2794                 :   // 1) Multipart responses are very large and would likely be doomed by the
    2795                 :   //    cache once they grow too large, so they are not worth caching.
    2796                 :   // 2) POST responses are always unique, and we provide no API that would
    2797                 :   //    allow our consumers to specify a "cache key" to access old POST
    2798                 :   //    responses, so they are not worth caching.
    2799             596 :   if ((mState & XML_HTTP_REQUEST_MULTIPART) || method.EqualsLiteral("POST")) {
    2800                 :     AddLoadFlags(mChannel,
    2801              12 :         nsIRequest::LOAD_BYPASS_CACHE | nsIRequest::INHIBIT_CACHING);
    2802                 :   }
    2803                 :   // When we are sync loading, we need to bypass the local cache when it would
    2804                 :   // otherwise block us waiting for exclusive access to the cache.  If we don't
    2805                 :   // do this, then we could dead lock in some cases (see bug 309424).
    2806             584 :   else if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
    2807                 :     AddLoadFlags(mChannel,
    2808              49 :         nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY);
    2809                 :   }
    2810                 : 
    2811                 :   // Since we expect XML data, set the type hint accordingly
    2812                 :   // This means that we always try to parse local files as XML
    2813                 :   // ignoring return value, as this is not critical
    2814             596 :   mChannel->SetContentType(NS_LITERAL_CSTRING("application/xml"));
    2815                 : 
    2816                 :   // We're about to send the request.  Start our timeout.
    2817             596 :   mRequestSentTime = PR_Now();
    2818             596 :   StartTimeoutTimer();
    2819                 : 
    2820                 :   // Set up the preflight if needed
    2821             596 :   if (mState & XML_HTTP_REQUEST_NEED_AC_PREFLIGHT) {
    2822                 :     // Check to see if this initial OPTIONS request has already been cached
    2823                 :     // in our special Access Control Cache.
    2824                 : 
    2825                 :     rv = NS_StartCORSPreflight(mChannel, listener,
    2826                 :                                mPrincipal, withCredentials,
    2827                 :                                mCORSUnsafeHeaders,
    2828               0 :                                getter_AddRefs(mCORSPreflightChannel));
    2829               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2830                 :   }
    2831                 :   else {
    2832                 :     // Start reading from the channel
    2833             596 :     rv = mChannel->AsyncOpen(listener, nsnull);
    2834                 :   }
    2835                 : 
    2836             596 :   if (NS_FAILED(rv)) {
    2837                 :     // Drop our ref to the channel to avoid cycles
    2838               0 :     mChannel = nsnull;
    2839               0 :     mCORSPreflightChannel = nsnull;
    2840               0 :     return rv;
    2841                 :   }
    2842                 : 
    2843                 :   // Either AsyncOpen was called, or CORS will open the channel later.
    2844             596 :   mWaitingForOnStopRequest = true;
    2845                 : 
    2846                 :   // If we're synchronous, spin an event loop here and wait
    2847             596 :   if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
    2848              57 :     mState |= XML_HTTP_REQUEST_SYNCLOOPING;
    2849                 : 
    2850             114 :     nsCOMPtr<nsIDocument> suspendedDoc;
    2851             114 :     nsCOMPtr<nsIRunnable> resumeTimeoutRunnable;
    2852              57 :     if (GetOwner()) {
    2853               0 :       nsCOMPtr<nsIDOMWindow> topWindow;
    2854               0 :       if (NS_SUCCEEDED(GetOwner()->GetTop(getter_AddRefs(topWindow)))) {
    2855               0 :         nsCOMPtr<nsPIDOMWindow> suspendedWindow(do_QueryInterface(topWindow));
    2856               0 :         if (suspendedWindow &&
    2857               0 :             (suspendedWindow = suspendedWindow->GetCurrentInnerWindow())) {
    2858               0 :           suspendedDoc = do_QueryInterface(suspendedWindow->GetExtantDocument());
    2859               0 :           if (suspendedDoc) {
    2860               0 :             suspendedDoc->SuppressEventHandling();
    2861                 :           }
    2862               0 :           suspendedWindow->SuspendTimeouts(1, false);
    2863               0 :           resumeTimeoutRunnable = new nsResumeTimeoutsEvent(suspendedWindow);
    2864                 :         }
    2865                 :       }
    2866                 :     }
    2867                 : 
    2868              57 :     ChangeState(XML_HTTP_REQUEST_SENT);
    2869                 :     // Note, calling ChangeState may have cleared
    2870                 :     // XML_HTTP_REQUEST_SYNCLOOPING flag.
    2871              57 :     nsIThread *thread = NS_GetCurrentThread();
    2872              57 :     while (mState & XML_HTTP_REQUEST_SYNCLOOPING) {
    2873            1152 :       if (!NS_ProcessNextEvent(thread)) {
    2874               0 :         rv = NS_ERROR_UNEXPECTED;
    2875               0 :         break;
    2876                 :       }
    2877                 :     }
    2878                 : 
    2879              57 :     if (suspendedDoc) {
    2880               0 :       suspendedDoc->UnsuppressEventHandlingAndFireEvents(true);
    2881                 :     }
    2882                 : 
    2883              57 :     if (resumeTimeoutRunnable) {
    2884               0 :       NS_DispatchToCurrentThread(resumeTimeoutRunnable);
    2885                 :     }
    2886                 :   } else {
    2887                 :     // Now that we've successfully opened the channel, we can change state.  Note
    2888                 :     // that this needs to come after the AsyncOpen() and rv check, because this
    2889                 :     // can run script that would try to restart this request, and that could end
    2890                 :     // up doing our AsyncOpen on a null channel if the reentered AsyncOpen fails.
    2891             539 :     ChangeState(XML_HTTP_REQUEST_SENT);
    2892            1625 :     if ((!mUploadComplete &&
    2893             547 :          HasListenersFor(NS_LITERAL_STRING(UPLOADPROGRESS_STR))) ||
    2894            1078 :         (mUpload && mUpload->HasListenersFor(NS_LITERAL_STRING(PROGRESS_STR)))) {
    2895               0 :       StartProgressEventTimer();
    2896                 :     }
    2897             539 :     DispatchProgressEvent(this, NS_LITERAL_STRING(LOADSTART_STR), false,
    2898             539 :                           0, 0);
    2899             539 :     if (mUpload && !mUploadComplete) {
    2900               0 :       DispatchProgressEvent(mUpload, NS_LITERAL_STRING(LOADSTART_STR), true,
    2901               0 :                             0, mUploadTotal);
    2902                 :     }
    2903                 :   }
    2904                 : 
    2905             596 :   if (!mChannel) {
    2906               0 :     return NS_ERROR_FAILURE;
    2907                 :   }
    2908                 : 
    2909             596 :   return rv;
    2910                 : }
    2911                 : 
    2912                 : /* void setRequestHeader (in AUTF8String header, in AUTF8String value); */
    2913                 : NS_IMETHODIMP
    2914              80 : nsXMLHttpRequest::SetRequestHeader(const nsACString& header,
    2915                 :                                    const nsACString& value)
    2916                 : {
    2917                 :   nsresult rv;
    2918                 : 
    2919                 :   // Make sure we don't store an invalid header name in mCORSUnsafeHeaders
    2920              80 :   if (!IsValidHTTPToken(header)) {
    2921               0 :     return NS_ERROR_FAILURE;
    2922                 :   }
    2923                 : 
    2924                 :   // Check that we haven't already opened the channel. We can't rely on
    2925                 :   // the channel throwing from mChannel->SetRequestHeader since we might
    2926                 :   // still be waiting for mCORSPreflightChannel to actually open mChannel
    2927              80 :   if (mCORSPreflightChannel) {
    2928                 :     bool pending;
    2929               0 :     rv = mCORSPreflightChannel->IsPending(&pending);
    2930               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2931                 :     
    2932               0 :     if (pending) {
    2933               0 :       return NS_ERROR_IN_PROGRESS;
    2934                 :     }
    2935                 :   }
    2936                 : 
    2937              80 :   if (!(mState & XML_HTTP_REQUEST_OPENED))
    2938               1 :     return NS_ERROR_IN_PROGRESS;
    2939                 : 
    2940              79 :   if (!mChannel)             // open() initializes mChannel, and open()
    2941               0 :     return NS_ERROR_FAILURE; // must be called before first setRequestHeader()
    2942                 : 
    2943             158 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
    2944              79 :   if (!httpChannel) {
    2945               0 :     return NS_OK;
    2946                 :   }
    2947                 : 
    2948                 :   // Prevent modification to certain HTTP headers (see bug 302263), unless
    2949                 :   // the executing script has UniversalXPConnect.
    2950                 : 
    2951                 :   bool privileged;
    2952              79 :   rv = IsCapabilityEnabled("UniversalXPConnect", &privileged);
    2953              79 :   if (NS_FAILED(rv))
    2954               0 :     return NS_ERROR_FAILURE;
    2955                 : 
    2956              79 :   if (!privileged) {
    2957                 :     // Check for dangerous headers
    2958                 :     const char *kInvalidHeaders[] = {
    2959                 :       "accept-charset", "accept-encoding", "access-control-request-headers",
    2960                 :       "access-control-request-method", "connection", "content-length",
    2961                 :       "cookie", "cookie2", "content-transfer-encoding", "date", "expect",
    2962                 :       "host", "keep-alive", "origin", "referer", "te", "trailer",
    2963                 :       "transfer-encoding", "upgrade", "user-agent", "via"
    2964               0 :     };
    2965                 :     PRUint32 i;
    2966               0 :     for (i = 0; i < ArrayLength(kInvalidHeaders); ++i) {
    2967               0 :       if (header.LowerCaseEqualsASCII(kInvalidHeaders[i])) {
    2968               0 :         NS_WARNING("refusing to set request header");
    2969               0 :         return NS_OK;
    2970                 :       }
    2971                 :     }
    2972               0 :     if (StringBeginsWith(header, NS_LITERAL_CSTRING("proxy-"),
    2973               0 :                          nsCaseInsensitiveCStringComparator()) ||
    2974               0 :         StringBeginsWith(header, NS_LITERAL_CSTRING("sec-"),
    2975               0 :                          nsCaseInsensitiveCStringComparator())) {
    2976               0 :       NS_WARNING("refusing to set request header");
    2977               0 :       return NS_OK;
    2978                 :     }
    2979                 : 
    2980                 :     // Check for dangerous cross-site headers
    2981               0 :     bool safeHeader = IsSystemXHR();
    2982               0 :     if (!safeHeader) {
    2983                 :       // Content-Type isn't always safe, but we'll deal with it in Send()
    2984                 :       const char *kCrossOriginSafeHeaders[] = {
    2985                 :         "accept", "accept-language", "content-language", "content-type",
    2986                 :         "last-event-id"
    2987               0 :       };
    2988               0 :       for (i = 0; i < ArrayLength(kCrossOriginSafeHeaders); ++i) {
    2989               0 :         if (header.LowerCaseEqualsASCII(kCrossOriginSafeHeaders[i])) {
    2990               0 :           safeHeader = true;
    2991               0 :           break;
    2992                 :         }
    2993                 :       }
    2994                 :     }
    2995                 : 
    2996               0 :     if (!safeHeader) {
    2997               0 :       mCORSUnsafeHeaders.AppendElement(header);
    2998                 :     }
    2999                 :   }
    3000                 : 
    3001                 :   // We need to set, not add to, the header.
    3002              79 :   rv = httpChannel->SetRequestHeader(header, value, false);
    3003              79 :   if (NS_SUCCEEDED(rv)) {
    3004                 :     // We'll want to duplicate this header for any replacement channels (eg. on redirect)
    3005                 :     RequestHeader reqHeader = {
    3006                 :       nsCString(header), nsCString(value)
    3007             158 :     };
    3008              79 :     mModifiedRequestHeaders.AppendElement(reqHeader);
    3009                 :   }
    3010                 : 
    3011              79 :   return rv;
    3012                 : }
    3013                 : 
    3014                 : /* attribute unsigned long timeout; */
    3015                 : NS_IMETHODIMP
    3016               0 : nsXMLHttpRequest::GetTimeout(PRUint32 *aTimeout)
    3017                 : {
    3018               0 :   *aTimeout = mTimeoutMilliseconds;
    3019               0 :   return NS_OK;
    3020                 : }
    3021                 : NS_IMETHODIMP
    3022               0 : nsXMLHttpRequest::SetTimeout(PRUint32 aTimeout)
    3023                 : {
    3024               0 :   if ((mState & (XML_HTTP_REQUEST_ASYNC | XML_HTTP_REQUEST_UNSENT)) ||
    3025               0 :       !HasOrHasHadOwner()) {
    3026               0 :     mTimeoutMilliseconds = aTimeout;
    3027               0 :     if (mRequestSentTime) {
    3028               0 :       StartTimeoutTimer();
    3029                 :     }
    3030               0 :     return NS_OK;
    3031                 :   }
    3032                 : 
    3033                 :   /* Timeout is not supported for synchronous requests with an owning window,
    3034                 :      per XHR2 spec. */
    3035               0 :   LogMessage("TimeoutSyncXHRWarning", GetOwner());
    3036               0 :   return NS_ERROR_DOM_INVALID_ACCESS_ERR;
    3037                 : }
    3038                 : 
    3039                 : void
    3040             596 : nsXMLHttpRequest::StartTimeoutTimer()
    3041                 : {
    3042             596 :   NS_ABORT_IF_FALSE(mRequestSentTime,
    3043                 :                     "StartTimeoutTimer mustn't be called before the request was sent!");
    3044             596 :   if (mState & XML_HTTP_REQUEST_DONE) {
    3045                 :     // do nothing!
    3046               0 :     return;
    3047                 :   }
    3048                 : 
    3049             596 :   if (mTimeoutTimer) {
    3050               0 :     mTimeoutTimer->Cancel();
    3051                 :   }
    3052                 : 
    3053             596 :   if (!mTimeoutMilliseconds) {
    3054             596 :     return;
    3055                 :   }
    3056                 : 
    3057               0 :   if (!mTimeoutTimer) {
    3058               0 :     mTimeoutTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
    3059                 :   }
    3060                 :   PRUint32 elapsed =
    3061               0 :     (PRUint32)((PR_Now() - mRequestSentTime) / PR_USEC_PER_MSEC);
    3062               0 :   mTimeoutTimer->InitWithCallback(
    3063                 :     this,
    3064                 :     mTimeoutMilliseconds > elapsed ? mTimeoutMilliseconds - elapsed : 0,
    3065                 :     nsITimer::TYPE_ONE_SHOT
    3066               0 :   );
    3067                 : }
    3068                 : 
    3069                 : /* readonly attribute long readyState; */
    3070                 : NS_IMETHODIMP
    3071             124 : nsXMLHttpRequest::GetReadyState(PRUint16 *aState)
    3072                 : {
    3073             124 :   NS_ENSURE_ARG_POINTER(aState);
    3074                 :   // Translate some of our internal states for external consumers
    3075             124 :   if (mState & XML_HTTP_REQUEST_UNSENT) {
    3076               0 :     *aState = UNSENT;
    3077             124 :   } else  if (mState & (XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT)) {
    3078               2 :     *aState = OPENED;
    3079             122 :   } else if (mState & XML_HTTP_REQUEST_HEADERS_RECEIVED) {
    3080               2 :     *aState = HEADERS_RECEIVED;
    3081             120 :   } else if (mState & (XML_HTTP_REQUEST_LOADING | XML_HTTP_REQUEST_STOPPED)) {
    3082               1 :     *aState = LOADING;
    3083             119 :   } else if (mState & XML_HTTP_REQUEST_DONE) {
    3084             119 :     *aState = DONE;
    3085                 :   } else {
    3086               0 :     NS_ERROR("Should not happen");
    3087                 :   }
    3088                 : 
    3089             124 :   return NS_OK;
    3090                 : }
    3091                 : 
    3092                 : /* void   overrideMimeType(in AUTF8String mimetype); */
    3093                 : NS_IMETHODIMP
    3094             534 : nsXMLHttpRequest::OverrideMimeType(const nsACString& aMimeType)
    3095                 : {
    3096                 :   // XXX Should we do some validation here?
    3097             534 :   mOverrideMimeType.Assign(aMimeType);
    3098             534 :   return NS_OK;
    3099                 : }
    3100                 : 
    3101                 : 
    3102                 : /* attribute boolean multipart; */
    3103                 : NS_IMETHODIMP
    3104               0 : nsXMLHttpRequest::GetMultipart(bool *_retval)
    3105                 : {
    3106               0 :   *_retval = !!(mState & XML_HTTP_REQUEST_MULTIPART);
    3107                 : 
    3108               0 :   return NS_OK;
    3109                 : }
    3110                 : 
    3111                 : /* attribute boolean multipart; */
    3112                 : NS_IMETHODIMP
    3113               0 : nsXMLHttpRequest::SetMultipart(bool aMultipart)
    3114                 : {
    3115               0 :   if (!(mState & XML_HTTP_REQUEST_UNSENT)) {
    3116                 :     // Can't change this while we're in the middle of something.
    3117               0 :     return NS_ERROR_IN_PROGRESS;
    3118                 :   }
    3119                 : 
    3120               0 :   if (aMultipart) {
    3121               0 :     mState |= XML_HTTP_REQUEST_MULTIPART;
    3122                 :   } else {
    3123               0 :     mState &= ~XML_HTTP_REQUEST_MULTIPART;
    3124                 :   }
    3125                 : 
    3126               0 :   return NS_OK;
    3127                 : }
    3128                 : 
    3129                 : /* attribute boolean mozBackgroundRequest; */
    3130                 : NS_IMETHODIMP
    3131               0 : nsXMLHttpRequest::GetMozBackgroundRequest(bool *_retval)
    3132                 : {
    3133               0 :   *_retval = !!(mState & XML_HTTP_REQUEST_BACKGROUND);
    3134                 : 
    3135               0 :   return NS_OK;
    3136                 : }
    3137                 : 
    3138                 : /* attribute boolean mozBackgroundRequest; */
    3139                 : NS_IMETHODIMP
    3140              87 : nsXMLHttpRequest::SetMozBackgroundRequest(bool aMozBackgroundRequest)
    3141                 : {
    3142                 :   bool privileged;
    3143                 : 
    3144              87 :   nsresult rv = IsCapabilityEnabled("UniversalXPConnect", &privileged);
    3145              87 :   NS_ENSURE_SUCCESS(rv, rv);
    3146                 : 
    3147              87 :   if (!privileged)
    3148               0 :     return NS_ERROR_DOM_SECURITY_ERR;
    3149                 : 
    3150              87 :   if (!(mState & XML_HTTP_REQUEST_UNSENT)) {
    3151                 :     // Can't change this while we're in the middle of something.
    3152               0 :     return NS_ERROR_IN_PROGRESS;
    3153                 :   }
    3154                 : 
    3155              87 :   if (aMozBackgroundRequest) {
    3156              87 :     mState |= XML_HTTP_REQUEST_BACKGROUND;
    3157                 :   } else {
    3158               0 :     mState &= ~XML_HTTP_REQUEST_BACKGROUND;
    3159                 :   }
    3160                 : 
    3161              87 :   return NS_OK;
    3162                 : }
    3163                 : 
    3164                 : /* attribute boolean withCredentials; */
    3165                 : NS_IMETHODIMP
    3166               0 : nsXMLHttpRequest::GetWithCredentials(bool *_retval)
    3167                 : {
    3168               0 :   *_retval = !!(mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS);
    3169                 : 
    3170               0 :   return NS_OK;
    3171                 : }
    3172                 : 
    3173                 : /* attribute boolean withCredentials; */
    3174                 : NS_IMETHODIMP
    3175               1 : nsXMLHttpRequest::SetWithCredentials(bool aWithCredentials)
    3176                 : {
    3177                 :   // Return error if we're already processing a request
    3178               1 :   if (XML_HTTP_REQUEST_SENT & mState) {
    3179               0 :     return NS_ERROR_FAILURE;
    3180                 :   }
    3181                 : 
    3182                 :   // sync request is not allowed setting withCredentials in window context
    3183               1 :   if (HasOrHasHadOwner() &&
    3184               0 :       !(mState & (XML_HTTP_REQUEST_UNSENT | XML_HTTP_REQUEST_ASYNC))) {
    3185               0 :     LogMessage("WithCredentialsSyncXHRWarning", GetOwner());
    3186               0 :     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
    3187                 :   }
    3188                 : 
    3189               1 :   if (aWithCredentials) {
    3190               0 :     mState |= XML_HTTP_REQUEST_AC_WITH_CREDENTIALS;
    3191                 :   }
    3192                 :   else {
    3193               1 :     mState &= ~XML_HTTP_REQUEST_AC_WITH_CREDENTIALS;
    3194                 :   }
    3195               1 :   return NS_OK;
    3196                 : }
    3197                 : 
    3198                 : nsresult
    3199            2948 : nsXMLHttpRequest::ChangeState(PRUint32 aState, bool aBroadcast)
    3200                 : {
    3201                 :   // If we are setting one of the mutually exclusive states,
    3202                 :   // unset those state bits first.
    3203            2948 :   if (aState & XML_HTTP_REQUEST_LOADSTATES) {
    3204            2948 :     mState &= ~XML_HTTP_REQUEST_LOADSTATES;
    3205                 :   }
    3206            2948 :   mState |= aState;
    3207            2948 :   nsresult rv = NS_OK;
    3208                 : 
    3209            3502 :   if (mProgressNotifier &&
    3210            3502 :       !(aState & (XML_HTTP_REQUEST_HEADERS_RECEIVED | XML_HTTP_REQUEST_LOADING))) {
    3211             416 :     mProgressTimerIsActive = false;
    3212             416 :     mProgressNotifier->Cancel();
    3213                 :   }
    3214                 : 
    3215            2948 :   if ((aState & XML_HTTP_REQUEST_LOADSTATES) && // Broadcast load states only
    3216                 :       aBroadcast &&
    3217                 :       (mState & XML_HTTP_REQUEST_ASYNC ||
    3218                 :        aState & XML_HTTP_REQUEST_OPENED ||
    3219                 :        aState & XML_HTTP_REQUEST_DONE)) {
    3220            5626 :     nsCOMPtr<nsIDOMEvent> event;
    3221            2813 :     rv = CreateReadystatechangeEvent(getter_AddRefs(event));
    3222            2813 :     NS_ENSURE_SUCCESS(rv, rv);
    3223                 : 
    3224            5626 :     DispatchDOMEvent(nsnull, event, nsnull, nsnull);
    3225                 :   }
    3226                 : 
    3227            2948 :   return rv;
    3228                 : }
    3229                 : 
    3230                 : /*
    3231                 :  * Simple helper class that just forwards the redirect callback back
    3232                 :  * to the nsXMLHttpRequest.
    3233                 :  */
    3234                 : class AsyncVerifyRedirectCallbackForwarder : public nsIAsyncVerifyRedirectCallback
    3235               0 : {
    3236                 : public:
    3237               0 :   AsyncVerifyRedirectCallbackForwarder(nsXMLHttpRequest *xhr)
    3238               0 :     : mXHR(xhr)
    3239                 :   {
    3240               0 :   }
    3241                 : 
    3242               0 :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    3243            1396 :   NS_DECL_CYCLE_COLLECTION_CLASS(AsyncVerifyRedirectCallbackForwarder)
    3244                 : 
    3245                 :   // nsIAsyncVerifyRedirectCallback implementation
    3246               0 :   NS_IMETHOD OnRedirectVerifyCallback(nsresult result)
    3247                 :   {
    3248               0 :     mXHR->OnRedirectVerifyCallback(result);
    3249                 : 
    3250               0 :     return NS_OK;
    3251                 :   }
    3252                 : 
    3253                 : private:
    3254                 :   nsRefPtr<nsXMLHttpRequest> mXHR;
    3255                 : };
    3256                 : 
    3257            1396 : NS_IMPL_CYCLE_COLLECTION_CLASS(AsyncVerifyRedirectCallbackForwarder)
    3258                 : 
    3259               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AsyncVerifyRedirectCallbackForwarder)
    3260               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mXHR, nsIXMLHttpRequest)
    3261               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    3262                 : 
    3263               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AsyncVerifyRedirectCallbackForwarder)
    3264               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mXHR)
    3265               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    3266                 : 
    3267               0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AsyncVerifyRedirectCallbackForwarder)
    3268               0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
    3269               0 :   NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
    3270               0 : NS_INTERFACE_MAP_END
    3271                 : 
    3272               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(AsyncVerifyRedirectCallbackForwarder)
    3273               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(AsyncVerifyRedirectCallbackForwarder)
    3274                 : 
    3275                 : 
    3276                 : /////////////////////////////////////////////////////
    3277                 : // nsIChannelEventSink methods:
    3278                 : //
    3279                 : NS_IMETHODIMP
    3280              35 : nsXMLHttpRequest::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
    3281                 :                                          nsIChannel *aNewChannel,
    3282                 :                                          PRUint32    aFlags,
    3283                 :                                          nsIAsyncVerifyRedirectCallback *callback)
    3284                 : {
    3285              35 :   NS_PRECONDITION(aNewChannel, "Redirect without a channel?");
    3286                 : 
    3287                 :   nsresult rv;
    3288                 : 
    3289              35 :   if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags)) {
    3290              35 :     rv = CheckChannelForCrossSiteRequest(aNewChannel);
    3291              35 :     if (NS_FAILED(rv)) {
    3292                 :       NS_WARNING("nsXMLHttpRequest::OnChannelRedirect: "
    3293               0 :                  "CheckChannelForCrossSiteRequest returned failure");
    3294               0 :       return rv;
    3295                 :     }
    3296                 : 
    3297                 :     // Disable redirects for preflighted cross-site requests entirely for now
    3298                 :     // Note, do this after the call to CheckChannelForCrossSiteRequest
    3299                 :     // to make sure that XML_HTTP_REQUEST_USE_XSITE_AC is up-to-date
    3300              35 :     if ((mState & XML_HTTP_REQUEST_NEED_AC_PREFLIGHT)) {
    3301               0 :        return NS_ERROR_DOM_BAD_URI;
    3302                 :     }
    3303                 :   }
    3304                 : 
    3305                 :   // Prepare to receive callback
    3306              35 :   mRedirectCallback = callback;
    3307              35 :   mNewRedirectChannel = aNewChannel;
    3308                 : 
    3309              35 :   if (mChannelEventSink) {
    3310                 :     nsRefPtr<AsyncVerifyRedirectCallbackForwarder> fwd =
    3311               0 :       new AsyncVerifyRedirectCallbackForwarder(this);
    3312                 : 
    3313               0 :     rv = mChannelEventSink->AsyncOnChannelRedirect(aOldChannel,
    3314                 :                                                    aNewChannel,
    3315               0 :                                                    aFlags, fwd);
    3316               0 :     if (NS_FAILED(rv)) {
    3317               0 :         mRedirectCallback = nsnull;
    3318               0 :         mNewRedirectChannel = nsnull;
    3319                 :     }
    3320               0 :     return rv;
    3321                 :   }
    3322              35 :   OnRedirectVerifyCallback(NS_OK);
    3323              35 :   return NS_OK;
    3324                 : }
    3325                 : 
    3326                 : void
    3327              35 : nsXMLHttpRequest::OnRedirectVerifyCallback(nsresult result)
    3328                 : {
    3329              35 :   NS_ASSERTION(mRedirectCallback, "mRedirectCallback not set in callback");
    3330              35 :   NS_ASSERTION(mNewRedirectChannel, "mNewRedirectChannel not set in callback");
    3331                 : 
    3332              35 :   if (NS_SUCCEEDED(result)) {
    3333              35 :     mChannel = mNewRedirectChannel;
    3334                 : 
    3335              70 :     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
    3336              35 :     if (httpChannel) {
    3337                 :       // Ensure all original headers are duplicated for the new channel (bug #553888)
    3338              71 :       for (PRUint32 i = mModifiedRequestHeaders.Length(); i > 0; ) {
    3339               1 :         --i;
    3340               2 :         httpChannel->SetRequestHeader(mModifiedRequestHeaders[i].header,
    3341               1 :                                       mModifiedRequestHeaders[i].value,
    3342               3 :                                       false);
    3343                 :       }
    3344                 :     }
    3345                 :   } else {
    3346               0 :     mErrorLoad = true;
    3347                 :   }
    3348                 : 
    3349              35 :   mNewRedirectChannel = nsnull;
    3350                 : 
    3351              35 :   mRedirectCallback->OnRedirectVerifyCallback(result);
    3352              35 :   mRedirectCallback = nsnull;
    3353              35 : }
    3354                 : 
    3355                 : /////////////////////////////////////////////////////
    3356                 : // nsIProgressEventSink methods:
    3357                 : //
    3358                 : 
    3359                 : void
    3360            1159 : nsXMLHttpRequest::MaybeDispatchProgressEvents(bool aFinalProgress)
    3361                 : {
    3362            1159 :   if (aFinalProgress && mProgressTimerIsActive) {
    3363             416 :     mProgressTimerIsActive = false;
    3364             416 :     mProgressNotifier->Cancel();
    3365                 :   }
    3366                 : 
    3367            2728 :   if (mProgressTimerIsActive ||
    3368            1029 :       !mProgressSinceLastProgressEvent ||
    3369                 :       mErrorLoad ||
    3370             540 :       !(mState & XML_HTTP_REQUEST_ASYNC)) {
    3371             637 :     return;
    3372                 :   }
    3373                 : 
    3374             522 :   if (!aFinalProgress) {
    3375             428 :     StartProgressEventTimer();
    3376                 :   }
    3377                 : 
    3378                 :   // We're uploading if our state is XML_HTTP_REQUEST_OPENED or
    3379                 :   // XML_HTTP_REQUEST_SENT
    3380             522 :   if ((XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT) & mState) {
    3381               0 :     if (aFinalProgress) {
    3382               0 :       mUploadTotal = mUploadTransferred;
    3383               0 :       mUploadProgressMax = mUploadProgress;
    3384               0 :       mUploadLengthComputable = true;
    3385                 :     }
    3386               0 :     DispatchProgressEvent(this, NS_LITERAL_STRING(UPLOADPROGRESS_STR),
    3387                 :                           true, mUploadLengthComputable, mUploadTransferred,
    3388                 :                           mUploadTotal, mUploadProgress,
    3389               0 :                           mUploadProgressMax);
    3390               0 :     if (mUpload && !mUploadComplete) {
    3391               0 :       DispatchProgressEvent(mUpload, NS_LITERAL_STRING(PROGRESS_STR),
    3392                 :                             true, mUploadLengthComputable, mUploadTransferred,
    3393                 :                             mUploadTotal, mUploadProgress,
    3394               0 :                             mUploadProgressMax);
    3395                 :     }
    3396                 :   } else {
    3397             522 :     if (aFinalProgress) {
    3398              94 :       mLoadTotal = mLoadTransferred;
    3399              94 :       mLoadLengthComputable = true;
    3400                 :     }
    3401             522 :     mInLoadProgressEvent = true;
    3402             522 :     DispatchProgressEvent(this, NS_LITERAL_STRING(PROGRESS_STR),
    3403                 :                           true, mLoadLengthComputable, mLoadTransferred,
    3404             522 :                           mLoadTotal, mLoadTransferred, mLoadTotal);
    3405             522 :     mInLoadProgressEvent = false;
    3406             522 :     if (mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT ||
    3407                 :         mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER) {
    3408               0 :       mResponseBody.Truncate();
    3409               0 :       mResponseText.Truncate();
    3410               0 :       mResultArrayBuffer = nsnull;
    3411                 :     }
    3412                 :   }
    3413                 : 
    3414             522 :   mProgressSinceLastProgressEvent = false;
    3415                 : }
    3416                 : 
    3417                 : NS_IMETHODIMP
    3418               1 : nsXMLHttpRequest::OnProgress(nsIRequest *aRequest, nsISupports *aContext, PRUint64 aProgress, PRUint64 aProgressMax)
    3419                 : {
    3420                 :   // We're in middle of processing multipart headers and we don't want to report
    3421                 :   // any progress because upload's 'load' is dispatched when we start to load
    3422                 :   // the first response.
    3423               1 :   if (XML_HTTP_REQUEST_MPART_HEADERS & mState) {
    3424               0 :     return NS_OK;
    3425                 :   }
    3426                 : 
    3427                 :   // We're uploading if our state is XML_HTTP_REQUEST_OPENED or
    3428                 :   // XML_HTTP_REQUEST_SENT
    3429               1 :   bool upload = !!((XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT) & mState);
    3430                 :   // When uploading, OnProgress reports also headers in aProgress and aProgressMax.
    3431                 :   // So, try to remove the headers, if possible.
    3432               1 :   bool lengthComputable = (aProgressMax != LL_MAXUINT);
    3433               1 :   if (upload) {
    3434               0 :     PRUint64 loaded = aProgress;
    3435               0 :     PRUint64 total = aProgressMax;
    3436               0 :     if (lengthComputable) {
    3437               0 :       PRUint64 headerSize = aProgressMax - mUploadTotal;
    3438               0 :       loaded -= headerSize;
    3439               0 :       total -= headerSize;
    3440                 :     }
    3441               0 :     mUploadLengthComputable = lengthComputable;
    3442               0 :     mUploadTransferred = loaded;
    3443               0 :     mUploadProgress = aProgress;
    3444               0 :     mUploadProgressMax = aProgressMax;
    3445               0 :     mProgressSinceLastProgressEvent = true;
    3446                 : 
    3447               0 :     MaybeDispatchProgressEvents(false);
    3448                 :   } else {
    3449               1 :     mLoadLengthComputable = lengthComputable;
    3450               1 :     mLoadTotal = lengthComputable ? aProgressMax : 0;
    3451                 :     
    3452                 :     // Don't dispatch progress events here. OnDataAvailable will take care
    3453                 :     // of that.
    3454                 :   }
    3455                 : 
    3456               1 :   if (mProgressEventSink) {
    3457               0 :     mProgressEventSink->OnProgress(aRequest, aContext, aProgress,
    3458               0 :                                    aProgressMax);
    3459                 :   }
    3460                 : 
    3461               1 :   return NS_OK;
    3462                 : }
    3463                 : 
    3464                 : NS_IMETHODIMP
    3465               2 : nsXMLHttpRequest::OnStatus(nsIRequest *aRequest, nsISupports *aContext, nsresult aStatus, const PRUnichar *aStatusArg)
    3466                 : {
    3467               2 :   if (mProgressEventSink) {
    3468               0 :     mProgressEventSink->OnStatus(aRequest, aContext, aStatus, aStatusArg);
    3469                 :   }
    3470                 : 
    3471               2 :   return NS_OK;
    3472                 : }
    3473                 : 
    3474                 : bool
    3475            2253 : nsXMLHttpRequest::AllowUploadProgress()
    3476                 : {
    3477            2253 :   return !(mState & XML_HTTP_REQUEST_USE_XSITE_AC) ||
    3478            2253 :     (mState & XML_HTTP_REQUEST_NEED_AC_PREFLIGHT);
    3479                 : }
    3480                 : 
    3481                 : /////////////////////////////////////////////////////
    3482                 : // nsIInterfaceRequestor methods:
    3483                 : //
    3484                 : NS_IMETHODIMP
    3485            1324 : nsXMLHttpRequest::GetInterface(const nsIID & aIID, void **aResult)
    3486                 : {
    3487                 :   nsresult rv;
    3488                 : 
    3489                 :   // Make sure to return ourselves for the channel event sink interface and
    3490                 :   // progress event sink interface, no matter what.  We can forward these to
    3491                 :   // mNotificationCallbacks if it wants to get notifications for them.  But we
    3492                 :   // need to see these notifications for proper functioning.
    3493            1324 :   if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
    3494              35 :     mChannelEventSink = do_GetInterface(mNotificationCallbacks);
    3495              35 :     *aResult = static_cast<nsIChannelEventSink*>(this);
    3496              35 :     NS_ADDREF_THIS();
    3497              35 :     return NS_OK;
    3498            1289 :   } else if (aIID.Equals(NS_GET_IID(nsIProgressEventSink))) {
    3499             615 :     mProgressEventSink = do_GetInterface(mNotificationCallbacks);
    3500             615 :     *aResult = static_cast<nsIProgressEventSink*>(this);
    3501             615 :     NS_ADDREF_THIS();
    3502             615 :     return NS_OK;
    3503                 :   }
    3504                 : 
    3505                 :   // Now give mNotificationCallbacks (if non-null) a chance to return the
    3506                 :   // desired interface.
    3507             674 :   if (mNotificationCallbacks) {
    3508             448 :     rv = mNotificationCallbacks->GetInterface(aIID, aResult);
    3509             448 :     if (NS_SUCCEEDED(rv)) {
    3510               0 :       NS_ASSERTION(*aResult, "Lying nsIInterfaceRequestor implementation!");
    3511               0 :       return rv;
    3512                 :     }
    3513                 :   }
    3514                 : 
    3515             674 :   if (mState & XML_HTTP_REQUEST_BACKGROUND) {
    3516             182 :     nsCOMPtr<nsIInterfaceRequestor> badCertHandler(do_CreateInstance(NS_BADCERTHANDLER_CONTRACTID, &rv));
    3517                 : 
    3518                 :     // Ignore failure to get component, we may not have all its dependencies
    3519                 :     // available
    3520              91 :     if (NS_SUCCEEDED(rv)) {
    3521              91 :       rv = badCertHandler->GetInterface(aIID, aResult);
    3522              91 :       if (NS_SUCCEEDED(rv))
    3523               0 :         return rv;
    3524                 :     }
    3525                 :   }
    3526            1166 :   else if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
    3527             583 :            aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
    3528                 :     nsCOMPtr<nsIPromptFactory> wwatch =
    3529               0 :       do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
    3530               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3531                 : 
    3532                 :     // Get the an auth prompter for our window so that the parenting
    3533                 :     // of the dialogs works as it should when using tabs.
    3534                 : 
    3535               0 :     nsCOMPtr<nsIDOMWindow> window;
    3536               0 :     if (GetOwner()) {
    3537               0 :       window = GetOwner()->GetOuterWindow();
    3538                 :     }
    3539                 : 
    3540               0 :     return wwatch->GetPrompt(window, aIID,
    3541               0 :                              reinterpret_cast<void**>(aResult));
    3542                 : 
    3543                 :   }
    3544                 : 
    3545             674 :   return QueryInterface(aIID, aResult);
    3546                 : }
    3547                 : 
    3548                 : NS_IMETHODIMP
    3549               0 : nsXMLHttpRequest::GetUpload(nsIXMLHttpRequestUpload** aUpload)
    3550                 : {
    3551               0 :   *aUpload = nsnull;
    3552                 : 
    3553                 :   nsresult rv;
    3554                 :   nsIScriptContext* scriptContext =
    3555               0 :     GetContextForEventHandlers(&rv);
    3556               0 :   NS_ENSURE_SUCCESS(rv, rv);
    3557               0 :   if (!mUpload) {
    3558               0 :     mUpload = new nsXMLHttpRequestUpload(this);
    3559               0 :     NS_ENSURE_TRUE(mUpload, NS_ERROR_OUT_OF_MEMORY);
    3560                 :   }
    3561               0 :   NS_ADDREF(*aUpload = mUpload);
    3562               0 :   return NS_OK;
    3563                 : }
    3564                 : 
    3565                 : void
    3566               0 : nsXMLHttpRequest::HandleTimeoutCallback()
    3567                 : {
    3568               0 :   if (mState & XML_HTTP_REQUEST_DONE) {
    3569               0 :     NS_NOTREACHED("nsXMLHttpRequest::HandleTimeoutCallback with completed request");
    3570                 :     // do nothing!
    3571               0 :     return;
    3572                 :   }
    3573                 : 
    3574               0 :   CloseRequestWithError(NS_LITERAL_STRING(TIMEOUT_STR),
    3575               0 :                         XML_HTTP_REQUEST_TIMED_OUT);
    3576                 : }
    3577                 : 
    3578                 : NS_IMETHODIMP
    3579              12 : nsXMLHttpRequest::Notify(nsITimer* aTimer)
    3580                 : {
    3581              12 :   if (mProgressNotifier == aTimer) {
    3582              12 :     HandleProgressTimerCallback();
    3583              12 :     return NS_OK;
    3584                 :   }
    3585                 : 
    3586               0 :   if (mTimeoutTimer == aTimer) {
    3587               0 :     HandleTimeoutCallback();
    3588               0 :     return NS_OK;
    3589                 :   }
    3590                 : 
    3591                 :   // Just in case some JS user wants to QI to nsITimerCallback and play with us...
    3592               0 :   NS_WARNING("Unexpected timer!");
    3593               0 :   return NS_ERROR_INVALID_POINTER;
    3594                 : }
    3595                 : 
    3596                 : void
    3597              12 : nsXMLHttpRequest::HandleProgressTimerCallback()
    3598                 : {
    3599              12 :   mProgressTimerIsActive = false;
    3600              12 :   if (!(XML_HTTP_REQUEST_MPART_HEADERS & mState)) {
    3601              12 :     MaybeDispatchProgressEvents(false);
    3602                 :   }
    3603              12 : }
    3604                 : 
    3605                 : void
    3606             428 : nsXMLHttpRequest::StartProgressEventTimer()
    3607                 : {
    3608             428 :   if (!mProgressNotifier) {
    3609             416 :     mProgressNotifier = do_CreateInstance(NS_TIMER_CONTRACTID);
    3610                 :   }
    3611             428 :   if (mProgressNotifier) {
    3612             428 :     mProgressEventWasDelayed = false;
    3613             428 :     mProgressTimerIsActive = true;
    3614             428 :     mProgressNotifier->Cancel();
    3615             428 :     mProgressNotifier->InitWithCallback(this, NS_PROGRESS_EVENT_INTERVAL,
    3616             428 :                                         nsITimer::TYPE_ONE_SHOT);
    3617                 :   }
    3618             428 : }
    3619                 : 
    3620               0 : NS_IMPL_ISUPPORTS1(nsXMLHttpRequest::nsHeaderVisitor, nsIHttpHeaderVisitor)
    3621                 : 
    3622               0 : NS_IMETHODIMP nsXMLHttpRequest::
    3623                 : nsHeaderVisitor::VisitHeader(const nsACString &header, const nsACString &value)
    3624                 : {
    3625                 :     // See bug #380418. Hide "Set-Cookie" headers from non-chrome scripts.
    3626               0 :     bool chrome = false; // default to false in case IsCapabilityEnabled fails
    3627               0 :     IsCapabilityEnabled("UniversalXPConnect", &chrome);
    3628               0 :     if (!chrome &&
    3629               0 :          (header.LowerCaseEqualsASCII("set-cookie") ||
    3630               0 :           header.LowerCaseEqualsASCII("set-cookie2"))) {
    3631               0 :         NS_WARNING("blocked access to response header");
    3632                 :     } else {
    3633               0 :         mHeaders.Append(header);
    3634               0 :         mHeaders.Append(": ");
    3635               0 :         mHeaders.Append(value);
    3636               0 :         mHeaders.Append('\n');
    3637                 :     }
    3638               0 :     return NS_OK;
    3639                 : }
    3640                 : 
    3641                 : // DOM event class to handle progress notifications
    3642             522 : nsXMLHttpProgressEvent::nsXMLHttpProgressEvent(nsIDOMProgressEvent* aInner,
    3643                 :                                                PRUint64 aCurrentProgress,
    3644                 :                                                PRUint64 aMaxProgress,
    3645                 :                                                nsPIDOMWindow* aWindow)
    3646             522 :   : mWindow(aWindow)
    3647                 : {
    3648             522 :   mInner = static_cast<nsDOMProgressEvent*>(aInner);
    3649             522 :   mCurProgress = aCurrentProgress;
    3650             522 :   mMaxProgress = aMaxProgress;
    3651             522 : }
    3652                 : 
    3653            1044 : nsXMLHttpProgressEvent::~nsXMLHttpProgressEvent()
    3654            2088 : {}
    3655                 : 
    3656            1396 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLHttpProgressEvent)
    3657                 : 
    3658                 : DOMCI_DATA(XMLHttpProgressEvent, nsXMLHttpProgressEvent)
    3659                 : 
    3660                 : // QueryInterface implementation for nsXMLHttpProgressEvent
    3661            4698 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXMLHttpProgressEvent)
    3662            2610 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMProgressEvent)
    3663            2610 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEvent, nsIDOMProgressEvent)
    3664            2088 :   NS_INTERFACE_MAP_ENTRY(nsIDOMNSEvent)
    3665            1566 :   NS_INTERFACE_MAP_ENTRY(nsIPrivateDOMEvent)
    3666             522 :   NS_INTERFACE_MAP_ENTRY(nsIDOMProgressEvent)
    3667               0 :   NS_INTERFACE_MAP_ENTRY(nsIDOMLSProgressEvent)
    3668               0 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XMLHttpProgressEvent)
    3669               0 : NS_INTERFACE_MAP_END
    3670                 : 
    3671            3654 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXMLHttpProgressEvent)
    3672            3654 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXMLHttpProgressEvent)
    3673                 : 
    3674               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXMLHttpProgressEvent)
    3675               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mInner);
    3676               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mWindow);
    3677               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    3678                 : 
    3679               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXMLHttpProgressEvent)
    3680               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mInner,
    3681                 :                                                        nsIDOMProgressEvent)
    3682               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mWindow);
    3683               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    3684                 : 
    3685               0 : NS_IMETHODIMP nsXMLHttpProgressEvent::GetInput(nsIDOMLSInput * *aInput)
    3686                 : {
    3687               0 :   *aInput = nsnull;
    3688               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    3689                 : }
    3690                 : 
    3691                 : void
    3692               0 : nsXMLHttpProgressEvent::WarnAboutLSProgressEvent(nsIDocument::DeprecatedOperations aOperation)
    3693                 : {
    3694               0 :   if (!mWindow) {
    3695               0 :     return;
    3696                 :   }
    3697                 :   nsCOMPtr<nsIDocument> document =
    3698               0 :     do_QueryInterface(mWindow->GetExtantDocument());
    3699               0 :   if (!document) {
    3700                 :     return;
    3701                 :   }
    3702               0 :   document->WarnOnceAbout(aOperation);
    3703                 : }
    3704                 : 
    3705               0 : NS_IMETHODIMP nsXMLHttpProgressEvent::GetPosition(PRUint32 *aPosition)
    3706                 : {
    3707               0 :   WarnAboutLSProgressEvent(nsIDocument::ePosition);
    3708                 :   // XXX can we change the iface?
    3709               0 :   LL_L2UI(*aPosition, mCurProgress);
    3710               0 :   return NS_OK;
    3711                 : }
    3712                 : 
    3713               0 : NS_IMETHODIMP nsXMLHttpProgressEvent::GetTotalSize(PRUint32 *aTotalSize)
    3714                 : {
    3715               0 :   WarnAboutLSProgressEvent(nsIDocument::eTotalSize);
    3716                 :   // XXX can we change the iface?
    3717               0 :   LL_L2UI(*aTotalSize, mMaxProgress);
    3718               0 :   return NS_OK;
    3719            4188 : }

Generated by: LCOV version 1.7