LCOV - code coverage report
Current view: directory - content/base/src - nsXMLHttpRequest.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1740 862 49.5 %
Date: 2012-06-02 Functions: 155 73 47.1 %

       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              62 : static void AddLoadFlags(nsIRequest *request, nsLoadFlags newFlags)
     185                 : {
     186                 :   nsLoadFlags flags;
     187              62 :   request->GetLoadFlags(&flags);
     188              62 :   flags |= newFlags;
     189              62 :   request->SetLoadFlags(flags);
     190              62 : }
     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            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXHREventTarget)
     302                 : 
     303              25 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXHREventTarget,
     304                 :                                                   nsDOMEventTargetHelper)
     305              25 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnLoadListener)
     306              25 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnErrorListener)
     307              25 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnAbortListener)
     308              25 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnLoadStartListener)
     309              25 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnProgressListener)
     310              25 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnLoadendListener)
     311              25 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnTimeoutListener)
     312              25 : 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           38012 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXHREventTarget)
     326           38012 :   NS_INTERFACE_MAP_ENTRY(nsIXMLHttpRequestEventTarget)
     327           38012 : NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
     328                 : 
     329           83921 : NS_IMPL_ADDREF_INHERITED(nsXHREventTarget, nsDOMEventTargetHelper)
     330           83921 : 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             596 : 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             596 :     mResultArrayBuffer(nsnull)
     471                 : {
     472             596 :   nsLayoutStatics::AddRef();
     473             596 : }
     474                 : 
     475            1788 : nsXMLHttpRequest::~nsXMLHttpRequest()
     476                 : {
     477             596 :   mState |= XML_HTTP_REQUEST_DELETED;
     478                 : 
     479             596 :   if (mState & (XML_HTTP_REQUEST_STOPPED |
     480                 :                 XML_HTTP_REQUEST_SENT |
     481                 :                 XML_HTTP_REQUEST_LOADING)) {
     482               0 :     Abort();
     483                 :   }
     484                 : 
     485             596 :   NS_ABORT_IF_FALSE(!(mState & XML_HTTP_REQUEST_SYNCLOOPING), "we rather crash than hang");
     486             596 :   mState &= ~XML_HTTP_REQUEST_SYNCLOOPING;
     487                 : 
     488             596 :   nsLayoutStatics::Release();
     489            2384 : }
     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             596 : nsXMLHttpRequest::Init()
     504                 : {
     505                 :   // Set the original mPrincipal, if available.
     506                 :   // Get JSContext from stack.
     507                 :   nsCOMPtr<nsIJSContextStack> stack =
     508            1192 :     do_GetService("@mozilla.org/js/xpc/ContextStack;1");
     509                 : 
     510             596 :   if (!stack) {
     511               0 :     return NS_OK;
     512                 :   }
     513                 : 
     514                 :   JSContext *cx;
     515                 : 
     516             596 :   if (NS_FAILED(stack->Peek(&cx)) || !cx) {
     517               1 :     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               1 : nsXMLHttpRequest::Init(nsIPrincipal* aPrincipal,
     543                 :                        nsIScriptContext* aScriptContext,
     544                 :                        nsPIDOMWindow* aOwnerWindow,
     545                 :                        nsIURI* aBaseURI)
     546                 : {
     547               1 :   NS_ENSURE_ARG_POINTER(aPrincipal);
     548                 : 
     549               1 :   mPrincipal = aPrincipal;
     550               1 :   BindToOwner(aOwnerWindow ? aOwnerWindow->GetCurrentInnerWindow() : nsnull);
     551               1 :   mBaseURI = aBaseURI;
     552                 : 
     553               1 :   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            1194 : nsXMLHttpRequest::ResetResponse()
     580                 : {
     581            1194 :   mResponseXML = nsnull;
     582            1194 :   mResponseBody.Truncate();
     583            1194 :   mResponseText.Truncate();
     584            1194 :   mResponseBlob = nsnull;
     585            1194 :   mDOMFile = nsnull;
     586            1194 :   mBuilder = nsnull;
     587            1194 :   mResultArrayBuffer = nsnull;
     588            1194 :   mResultJSON = JSVAL_VOID;
     589            1194 :   mLoadTransferred = 0;
     590            1194 :   mResponseBodyDecodedPos = 0;
     591            1194 : }
     592                 : 
     593                 : void
     594               0 : nsXMLHttpRequest::SetRequestObserver(nsIRequestObserver* aObserver)
     595                 : {
     596               0 :   mRequestObserver = aObserver;
     597               0 : }
     598                 : 
     599            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLHttpRequest)
     600                 : 
     601             324 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsXMLHttpRequest)
     602             324 :   bool isBlack = tmp->IsBlack();
     603             324 :   if (isBlack || tmp->mWaitingForOnStopRequest) {
     604             189 :     if (tmp->mListenerManager) {
     605             187 :       tmp->mListenerManager->UnmarkGrayJSListeners();
     606             187 :       NS_UNMARK_LISTENER_WRAPPER(Load)
     607             187 :       NS_UNMARK_LISTENER_WRAPPER(Error)
     608             187 :       NS_UNMARK_LISTENER_WRAPPER(Abort)
     609             187 :       NS_UNMARK_LISTENER_WRAPPER(LoadStart)
     610             187 :       NS_UNMARK_LISTENER_WRAPPER(Progress)
     611             187 :       NS_UNMARK_LISTENER_WRAPPER(Loadend)
     612             187 :       NS_UNMARK_LISTENER_WRAPPER(UploadProgress)
     613             187 :       NS_UNMARK_LISTENER_WRAPPER(Readystatechange)
     614                 :     }
     615             189 :     if (!isBlack) {
     616              32 :       xpc_UnmarkGrayObject(tmp->PreservingWrapper() ? 
     617               0 :                            tmp->GetWrapperPreserveColor() :
     618              32 :                            tmp->GetExpandoObjectPreserveColor());
     619                 :     }
     620             189 :     return true;
     621                 :   }
     622             135 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
     623                 : 
     624              23 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsXMLHttpRequest)
     625              23 :   return tmp->IsBlack();
     626                 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
     627                 : 
     628              38 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsXMLHttpRequest)
     629              38 :   return tmp->IsBlack();
     630                 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
     631                 : 
     632              25 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLHttpRequest,
     633                 :                                                   nsXHREventTarget)
     634              25 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
     635              25 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannel)
     636              25 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mReadRequest)
     637              25 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mResponseXML)
     638              25 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCORSPreflightChannel)
     639                 : 
     640              25 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnUploadProgressListener)
     641              25 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnReadystatechangeListener)
     642                 : 
     643              25 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mXMLParserStreamListener)
     644                 : 
     645              25 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannelEventSink)
     646              25 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mProgressEventSink)
     647                 : 
     648              25 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mUpload,
     649                 :                                                        nsIXMLHttpRequestUpload)
     650              25 : 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              25 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsXMLHttpRequest,
     674                 :                                                nsXHREventTarget)
     675              25 :   if(tmp->mResultArrayBuffer) {
     676               0 :     NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(tmp->mResultArrayBuffer,
     677                 :                                                "mResultArrayBuffer")
     678                 :   }
     679              25 :   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              25 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
     684                 : 
     685                 : DOMCI_DATA(XMLHttpRequest, nsXMLHttpRequest)
     686                 : 
     687                 : // QueryInterface implementation for nsXMLHttpRequest
     688           87404 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLHttpRequest)
     689           46432 :   NS_INTERFACE_MAP_ENTRY(nsIXMLHttpRequest)
     690           42409 :   NS_INTERFACE_MAP_ENTRY(nsIJSXMLHttpRequest)
     691           42269 :   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
     692           42269 :   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
     693           40574 :   NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
     694           40539 :   NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
     695           39924 :   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
     696           38633 :   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     697           38633 :   NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
     698           38633 :   NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
     699           38629 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XMLHttpRequest)
     700           38012 : NS_INTERFACE_MAP_END_INHERITING(nsXHREventTarget)
     701                 : 
     702           83921 : NS_IMPL_ADDREF_INHERITED(nsXMLHttpRequest, nsXHREventTarget)
     703           83921 : 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             393 : nsXMLHttpRequest::GetResponseXML(nsIDOMDocument **aResponseXML)
     773                 : {
     774             393 :   NS_ENSURE_ARG_POINTER(aResponseXML);
     775             393 :   *aResponseXML = nsnull;
     776             393 :   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             393 :   if ((XML_HTTP_REQUEST_DONE & mState) && mResponseXML) {
     781             393 :     *aResponseXML = mResponseXML;
     782             393 :     NS_ADDREF(*aResponseXML);
     783                 :   }
     784             393 :   if (mWarnAboutMultipartHtml) {
     785               0 :     mWarnAboutMultipartHtml = false;
     786               0 :     LogMessage("HTMLMultipartXHRWarning", GetOwner());
     787                 :   }
     788             393 :   if (mWarnAboutSyncHtml) {
     789               0 :     mWarnAboutSyncHtml = false;
     790               0 :     LogMessage("HTMLSyncXHRWarning", GetOwner());
     791                 :   }
     792             393 :   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             585 : nsXMLHttpRequest::DetectCharset()
     801                 : {
     802             585 :   mResponseCharset.Truncate();
     803             585 :   mDecoder = nsnull;
     804                 : 
     805             585 :   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            1170 :   nsCOMPtr<nsIChannel> channel = do_QueryInterface(mReadRequest);
     813             585 :   if (!channel) {
     814               0 :     channel = mChannel;
     815                 :   }
     816                 : 
     817            1170 :   nsCAutoString charsetVal;
     818             585 :   nsresult rv = channel ? channel->GetContentCharset(charsetVal) :
     819            1170 :                 NS_ERROR_FAILURE;
     820             585 :   if (NS_SUCCEEDED(rv)) {
     821             514 :     rv = nsCharsetAlias::GetPreferred(charsetVal, mResponseCharset);
     822                 :   }
     823                 : 
     824             585 :   if (NS_FAILED(rv) || mResponseCharset.IsEmpty()) {
     825                 :     // MS documentation states UTF-8 is default for responseText
     826             581 :     mResponseCharset.AssignLiteral("UTF-8");
     827                 :   }
     828                 : 
     829             585 :   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            1170 :     do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
     838             585 :   NS_ENSURE_SUCCESS(rv, rv);
     839                 : 
     840             585 :   return ccm->GetUnicodeDecoderRaw(mResponseCharset.get(),
     841             585 :                                    getter_AddRefs(mDecoder));
     842                 : }
     843                 : 
     844                 : nsresult
     845             309 : nsXMLHttpRequest::AppendToResponseText(const char * aSrcBuffer,
     846                 :                                        PRUint32 aSrcBufferLen)
     847                 : {
     848             309 :   NS_ENSURE_STATE(mDecoder);
     849                 : 
     850                 :   PRInt32 destBufferLen;
     851             309 :   nsresult rv = mDecoder->GetMaxLength(aSrcBuffer, aSrcBufferLen,
     852             309 :                                        &destBufferLen);
     853             309 :   NS_ENSURE_SUCCESS(rv, rv);
     854                 : 
     855             309 :   if (!mResponseText.SetCapacity(mResponseText.Length() + destBufferLen)) {
     856               0 :     return NS_ERROR_OUT_OF_MEMORY;
     857                 :   }
     858                 : 
     859             309 :   PRUnichar* destBuffer = mResponseText.BeginWriting() + mResponseText.Length();
     860                 : 
     861             309 :   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             601 :   do {
     868             601 :     PRInt32 srclen = (PRInt32)aSrcBufferLen;
     869             601 :     PRInt32 destlen = (PRInt32)destBufferLen;
     870             601 :     rv = mDecoder->Convert(aSrcBuffer,
     871                 :                            &srclen,
     872                 :                            destBuffer,
     873             601 :                            &destlen);
     874             601 :     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             601 :     totalChars += destlen;
     893                 : 
     894             601 :   } while (NS_FAILED(rv) && aSrcBufferLen > 0);
     895                 : 
     896             309 :   mResponseText.SetLength(totalChars);
     897                 : 
     898             309 :   return NS_OK;
     899                 : }
     900                 : 
     901                 : /* readonly attribute AString responseText; */
     902             352 : NS_IMETHODIMP nsXMLHttpRequest::GetResponseText(nsAString& aResponseText)
     903                 : {
     904             352 :   aResponseText.Truncate();
     905                 : 
     906             352 :   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             352 :   if (mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT &&
     913               0 :       !mInLoadProgressEvent) {
     914               0 :     aResponseText.SetIsVoid(true);
     915               0 :     return NS_OK;
     916                 :   }
     917                 : 
     918             352 :   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             698 :   if (!mResponseXML ||
     926             346 :       mResponseBodyDecodedPos == mResponseBody.Length()) {
     927              50 :     aResponseText = mResponseText;
     928              50 :     return NS_OK;
     929                 :   }
     930                 : 
     931                 :   nsresult rv;
     932                 : 
     933             604 :   nsCOMPtr<nsIDocument> document = do_QueryInterface(mResponseXML);
     934             302 :   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             302 :   NS_ASSERTION(mResponseBodyDecodedPos < mResponseBody.Length(),
     949                 :                "Unexpected mResponseBodyDecodedPos");
     950             302 :   rv = AppendToResponseText(mResponseBody.get() + mResponseBodyDecodedPos,
     951             604 :                             mResponseBody.Length() - mResponseBodyDecodedPos);
     952             302 :   NS_ENSURE_SUCCESS(rv, rv);
     953                 : 
     954             302 :   mResponseBodyDecodedPos = mResponseBody.Length();
     955                 :   
     956             302 :   if (mState & XML_HTTP_REQUEST_DONE) {
     957                 :     // Free memory buffer which we no longer need
     958             302 :     mResponseBody.Truncate();
     959             302 :     mResponseBodyDecodedPos = 0;
     960                 :   }
     961                 : 
     962             302 :   aResponseText = mResponseText;
     963                 : 
     964             302 :   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             598 : nsXMLHttpRequest::GetLoadGroup() const
    1487                 : {
    1488             598 :   if (mState & XML_HTTP_REQUEST_BACKGROUND) {                 
    1489              87 :     return nsnull;
    1490                 :   }
    1491                 : 
    1492             511 :   nsresult rv = NS_ERROR_FAILURE;
    1493                 :   nsIScriptContext* sc =
    1494             511 :     const_cast<nsXMLHttpRequest*>(this)->GetContextForEventHandlers(&rv);
    1495                 :   nsCOMPtr<nsIDocument> doc =
    1496            1022 :     nsContentUtils::GetDocumentFromScriptContext(sc);
    1497             511 :   if (doc) {
    1498               0 :     return doc->GetDocumentLoadGroup();
    1499                 :   }
    1500                 : 
    1501             511 :   return nsnull;
    1502                 : }
    1503                 : 
    1504                 : nsresult
    1505            2815 : nsXMLHttpRequest::CreateReadystatechangeEvent(nsIDOMEvent** aDOMEvent)
    1506                 : {
    1507                 :   nsresult rv = nsEventDispatcher::CreateEvent(nsnull, nsnull,
    1508            2815 :                                                NS_LITERAL_STRING("Events"),
    1509            2815 :                                                aDOMEvent);
    1510            2815 :   if (NS_FAILED(rv)) {
    1511               0 :     return rv;
    1512                 :   }
    1513                 : 
    1514            5630 :   nsCOMPtr<nsIPrivateDOMEvent> privevent(do_QueryInterface(*aDOMEvent));
    1515            2815 :   if (!privevent) {
    1516               0 :     NS_IF_RELEASE(*aDOMEvent);
    1517               0 :     return NS_ERROR_FAILURE;
    1518                 :   }
    1519                 : 
    1520            2815 :   (*aDOMEvent)->InitEvent(NS_LITERAL_STRING(READYSTATE_STR),
    1521            2815 :                           false, false);
    1522                 : 
    1523                 :   // We assume anyone who managed to call CreateReadystatechangeEvent is trusted
    1524            2815 :   privevent->SetTrusted(true);
    1525                 : 
    1526            2815 :   return NS_OK;
    1527                 : }
    1528                 : 
    1529                 : void
    1530            2255 : 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            2255 :   NS_ASSERTION(aTarget, "null target");
    1538            2255 :   NS_ASSERTION(!aType.IsEmpty(), "missing event type");
    1539                 : 
    1540            4510 :   if (NS_FAILED(CheckInnerWindowCorrectness()) ||
    1541            2255 :       (!AllowUploadProgress() &&
    1542               0 :        (aTarget == mUpload || aType.EqualsLiteral(UPLOADPROGRESS_STR)))) {
    1543               0 :     return;
    1544                 :   }
    1545                 : 
    1546            2255 :   bool dispatchLoadend = aType.EqualsLiteral(LOAD_STR) ||
    1547            1741 :                            aType.EqualsLiteral(ERROR_STR) ||
    1548            1670 :                            aType.EqualsLiteral(TIMEOUT_STR) ||
    1549            5666 :                            aType.EqualsLiteral(ABORT_STR);
    1550                 :   
    1551            4510 :   nsCOMPtr<nsIDOMEvent> event;
    1552                 :   nsresult rv = nsEventDispatcher::CreateEvent(nsnull, nsnull,
    1553            2255 :                                                NS_LITERAL_STRING("ProgressEvent"),
    1554            4510 :                                                getter_AddRefs(event));
    1555            2255 :   if (NS_FAILED(rv)) {
    1556                 :     return;
    1557                 :   }
    1558                 : 
    1559            4510 :   nsCOMPtr<nsIPrivateDOMEvent> privevent(do_QueryInterface(event));
    1560            2255 :   if (!privevent) {
    1561                 :     return;
    1562                 :   }
    1563            2255 :   privevent->SetTrusted(true);
    1564                 : 
    1565            4510 :   nsCOMPtr<nsIDOMProgressEvent> progress = do_QueryInterface(event);
    1566            2255 :   if (!progress) {
    1567                 :     return;
    1568                 :   }
    1569                 : 
    1570            2255 :   progress->InitProgressEvent(aType, false, false, aLengthComputable,
    1571            2255 :                               aLoaded, (aTotal == LL_MAXUINT) ? 0 : aTotal);
    1572                 : 
    1573            2255 :   if (aUseLSEventWrapper) {
    1574                 :     nsCOMPtr<nsIDOMProgressEvent> xhrprogressEvent =
    1575            1566 :       new nsXMLHttpProgressEvent(progress, aPosition, aTotalSize, GetOwner());
    1576             522 :     event = xhrprogressEvent;
    1577                 :   }
    1578            2255 :   aTarget->DispatchDOMEvent(nsnull, event, nsnull, nsnull);
    1579                 :   
    1580            2255 :   if (dispatchLoadend) {
    1581             597 :     DispatchProgressEvent(aTarget, NS_LITERAL_STRING(LOADEND_STR),
    1582                 :                           aUseLSEventWrapper, aLengthComputable,
    1583             597 :                           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            2878 : nsXMLHttpRequest::IsSystemXHR()
    1605                 : {
    1606            2878 :   return !!nsContentUtils::IsSystemPrincipal(mPrincipal);
    1607                 : }
    1608                 : 
    1609                 : nsresult
    1610             632 : nsXMLHttpRequest::CheckChannelForCrossSiteRequest(nsIChannel* aChannel)
    1611                 : {
    1612                 :   // First check if cross-site requests are enabled...
    1613             632 :   if (IsSystemXHR()) {
    1614             632 :     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             599 : nsXMLHttpRequest::Open(const nsACString& method, const nsACString& url,
    1655                 :                        bool async, const nsAString& user,
    1656                 :                        const nsAString& password, PRUint8 optional_argc)
    1657                 : {
    1658             599 :   NS_ENSURE_ARG(!method.IsEmpty());
    1659                 : 
    1660             599 :   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             599 :                         async ? 0 : 1);
    1666                 : 
    1667             599 :   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            1196 :   if (method.LowerCaseEqualsLiteral("trace") ||
    1672             598 :       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             598 :   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            1196 :   nsCOMPtr<nsIURI> uri;
    1696                 : 
    1697             598 :   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             598 :   mState &= ~XML_HTTP_REQUEST_ABORTED & ~XML_HTTP_REQUEST_TIMED_OUT;
    1714                 : 
    1715             598 :   if (async) {
    1716             539 :     mState |= XML_HTTP_REQUEST_ASYNC;
    1717                 :   } else {
    1718              59 :     mState &= ~XML_HTTP_REQUEST_ASYNC;
    1719                 :   }
    1720                 : 
    1721             598 :   mState &= ~XML_HTTP_REQUEST_MPART_HEADERS;
    1722                 : 
    1723             598 :   nsIScriptContext* sc = GetContextForEventHandlers(&rv);
    1724             598 :   NS_ENSURE_SUCCESS(rv, rv);
    1725                 :   nsCOMPtr<nsIDocument> doc =
    1726            1196 :     nsContentUtils::GetDocumentFromScriptContext(sc);
    1727                 :   
    1728            1196 :   nsCOMPtr<nsIURI> baseURI;
    1729             598 :   if (mBaseURI) {
    1730               0 :     baseURI = mBaseURI;
    1731                 :   }
    1732             598 :   else if (doc) {
    1733               0 :     baseURI = doc->GetBaseURI();
    1734                 :   }
    1735                 : 
    1736             598 :   rv = NS_NewURI(getter_AddRefs(uri), url, nsnull, baseURI);
    1737             598 :   if (NS_FAILED(rv)) return rv;
    1738                 : 
    1739             598 :   rv = CheckInnerWindowCorrectness();
    1740             598 :   NS_ENSURE_SUCCESS(rv, rv);
    1741             598 :   PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
    1742                 :   rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_XMLHTTPREQUEST,
    1743                 :                                  uri,
    1744                 :                                  mPrincipal,
    1745                 :                                  doc,
    1746             598 :                                  EmptyCString(), //mime guess
    1747                 :                                  nsnull,         //extra
    1748                 :                                  &shouldLoad,
    1749                 :                                  nsContentUtils::GetContentPolicy(),
    1750            1196 :                                  nsContentUtils::GetSecurityManager());
    1751             598 :   if (NS_FAILED(rv)) return rv;
    1752             598 :   if (NS_CP_REJECTED(shouldLoad)) {
    1753                 :     // Disallowed by content policy
    1754               0 :     return NS_ERROR_CONTENT_BLOCKED;
    1755                 :   }
    1756                 : 
    1757             598 :   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            1196 :   nsCOMPtr<nsILoadGroup> loadGroup = GetLoadGroup();
    1771                 : 
    1772                 :   // get Content Security Policy from principal to pass into channel
    1773            1196 :   nsCOMPtr<nsIChannelPolicy> channelPolicy;
    1774            1196 :   nsCOMPtr<nsIContentSecurityPolicy> csp;
    1775             598 :   rv = mPrincipal->GetCsp(getter_AddRefs(csp));
    1776             598 :   NS_ENSURE_SUCCESS(rv, rv);
    1777             598 :   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             598 :   rv = NS_NewChannel(getter_AddRefs(mChannel),
    1783                 :                      uri,
    1784                 :                      nsnull,                    // ioService
    1785                 :                      loadGroup,
    1786                 :                      nsnull,                    // callbacks
    1787                 :                      nsIRequest::LOAD_BACKGROUND,
    1788             598 :                      channelPolicy);
    1789             598 :   if (NS_FAILED(rv)) return rv;
    1790                 : 
    1791                 :   mState &= ~(XML_HTTP_REQUEST_USE_XSITE_AC |
    1792             598 :               XML_HTTP_REQUEST_NEED_AC_PREFLIGHT);
    1793                 : 
    1794            1196 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
    1795             598 :   if (httpChannel) {
    1796             595 :     rv = httpChannel->SetRequestMethod(method);
    1797             595 :     NS_ENSURE_SUCCESS(rv, rv);
    1798                 :   }
    1799                 : 
    1800             598 :   ChangeState(XML_HTTP_REQUEST_OPENED);
    1801                 : 
    1802             598 :   return rv;
    1803                 : }
    1804                 : 
    1805                 : /*
    1806                 :  * "Copy" from a stream.
    1807                 :  */
    1808                 : NS_METHOD
    1809             564 : nsXMLHttpRequest::StreamReaderFunc(nsIInputStream* in,
    1810                 :                                    void* closure,
    1811                 :                                    const char* fromRawSegment,
    1812                 :                                    PRUint32 toOffset,
    1813                 :                                    PRUint32 count,
    1814                 :                                    PRUint32 *writeCount)
    1815                 : {
    1816             564 :   nsXMLHttpRequest* xmlHttpRequest = static_cast<nsXMLHttpRequest*>(closure);
    1817             564 :   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             564 :   nsresult rv = NS_OK;
    1823                 : 
    1824             564 :   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            1128 :   if ((xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_DEFAULT &&
    1843             564 :        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             557 :     PRUint32 previousLength = xmlHttpRequest->mResponseBody.Length();
    1848             557 :     xmlHttpRequest->mResponseBody.Append(fromRawSegment,count);
    1849             557 :     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             564 :   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            1114 :     nsCOMPtr<nsIInputStream> copyStream;
    1868             557 :     rv = NS_NewByteInputStream(getter_AddRefs(copyStream), fromRawSegment, count);
    1869                 : 
    1870             557 :     if (NS_SUCCEEDED(rv) && xmlHttpRequest->mXMLParserStreamListener) {
    1871             557 :       NS_ASSERTION(copyStream, "NS_NewByteInputStream lied");
    1872                 :       nsresult parsingResult = xmlHttpRequest->mXMLParserStreamListener
    1873             557 :                                   ->OnDataAvailable(xmlHttpRequest->mReadRequest,
    1874                 :                                                     xmlHttpRequest->mContext,
    1875             557 :                                                     copyStream, toOffset, count);
    1876                 : 
    1877                 :       // No use to continue parsing if we failed here, but we
    1878                 :       // should still finish reading the stream
    1879             557 :       if (NS_FAILED(parsingResult)) {
    1880               0 :         xmlHttpRequest->mState &= ~XML_HTTP_REQUEST_PARSEBODY;
    1881                 :       }
    1882                 :     }
    1883                 :   }
    1884                 : 
    1885             564 :   if (NS_SUCCEEDED(rv)) {
    1886             564 :     *writeCount = count;
    1887                 :   } else {
    1888               0 :     *writeCount = 0;
    1889                 :   }
    1890                 : 
    1891             564 :   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             564 : nsXMLHttpRequest::OnDataAvailable(nsIRequest *request,
    1932                 :                                   nsISupports *ctxt,
    1933                 :                                   nsIInputStream *inStr,
    1934                 :                                   PRUint32 sourceOffset,
    1935                 :                                   PRUint32 count)
    1936                 : {
    1937             564 :   NS_ENSURE_ARG_POINTER(inStr);
    1938                 : 
    1939             564 :   NS_ABORT_IF_FALSE(mContext.get() == ctxt,"start context different from OnDataAvailable context");
    1940                 : 
    1941             564 :   mProgressSinceLastProgressEvent = true;
    1942                 : 
    1943             564 :   bool cancelable = false;
    1944             564 :   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             564 :                                     (void*)this, count, &totalRead);
    1954             564 :   NS_ENSURE_SUCCESS(rv, rv);
    1955                 : 
    1956             564 :   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             564 :   mLoadTransferred += totalRead;
    1964                 : 
    1965             564 :   ChangeState(XML_HTTP_REQUEST_LOADING);
    1966                 :   
    1967             564 :   MaybeDispatchProgressEvents(false);
    1968                 : 
    1969             564 :   return NS_OK;
    1970                 : }
    1971                 : 
    1972                 : bool
    1973            1194 : IsSameOrBaseChannel(nsIRequest* aPossibleBase, nsIChannel* aChannel)
    1974                 : {
    1975            2388 :   nsCOMPtr<nsIMultiPartChannel> mpChannel = do_QueryInterface(aPossibleBase);
    1976            1194 :   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            1194 :   return aPossibleBase == aChannel;
    1985                 : }
    1986                 : 
    1987                 : /* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
    1988                 : NS_IMETHODIMP
    1989             597 : nsXMLHttpRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
    1990                 : {
    1991            1194 :   SAMPLE_LABEL("nsXMLHttpRequest", "OnStartRequest");
    1992             597 :   nsresult rv = NS_OK;
    1993             597 :   if (!mFirstStartRequestSeen && mRequestObserver) {
    1994               0 :     mFirstStartRequestSeen = true;
    1995               0 :     mRequestObserver->OnStartRequest(request, ctxt);
    1996                 :   }
    1997                 : 
    1998             597 :   if (!IsSameOrBaseChannel(request, mChannel)) {
    1999               0 :     return NS_OK;
    2000                 :   }
    2001                 : 
    2002                 :   // Don't do anything if we have been aborted
    2003             597 :   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             585 :   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             585 :   if (mState & XML_HTTP_REQUEST_TIMED_OUT) {
    2016               0 :     return NS_OK;
    2017                 :   }
    2018                 : 
    2019            1170 :   nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
    2020             585 :   NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED);
    2021                 : 
    2022            1170 :   nsCOMPtr<nsIPrincipal> documentPrincipal;
    2023             585 :   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             585 :     documentPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
    2030             585 :     NS_ENSURE_SUCCESS(rv, rv);
    2031                 :   } else {
    2032               0 :     documentPrincipal = mPrincipal;
    2033                 :   }
    2034                 : 
    2035             585 :   channel->SetOwner(documentPrincipal);
    2036                 : 
    2037                 :   nsresult status;
    2038             585 :   request->GetStatus(&status);
    2039             585 :   mErrorLoad = mErrorLoad || NS_FAILED(status);
    2040                 : 
    2041             585 :   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             585 :   mReadRequest = request;
    2054             585 :   mContext = ctxt;
    2055             585 :   mState |= XML_HTTP_REQUEST_PARSEBODY;
    2056             585 :   mState &= ~XML_HTTP_REQUEST_MPART_HEADERS;
    2057             585 :   ChangeState(XML_HTTP_REQUEST_HEADERS_RECEIVED);
    2058                 : 
    2059             585 :   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             585 :   ResetResponse();
    2068                 : 
    2069             585 :   if (!mOverrideMimeType.IsEmpty()) {
    2070             522 :     channel->SetContentType(mOverrideMimeType);
    2071                 :   }
    2072                 : 
    2073             585 :   DetectCharset();
    2074                 : 
    2075                 :   // Set up responseXML
    2076                 :   bool parseBody = mResponseType == XML_HTTP_RESPONSE_TYPE_DEFAULT ||
    2077             585 :                      mResponseType == XML_HTTP_RESPONSE_TYPE_DOCUMENT;
    2078            1170 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
    2079             585 :   if (parseBody && httpChannel) {
    2080            1166 :     nsCAutoString method;
    2081             583 :     httpChannel->GetRequestMethod(method);
    2082             583 :     parseBody = !method.EqualsLiteral("HEAD");
    2083                 :   }
    2084                 : 
    2085             585 :   mIsHtml = false;
    2086             585 :   mWarnAboutMultipartHtml = false;
    2087             585 :   mWarnAboutSyncHtml = false;
    2088             585 :   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            1012 :     nsCAutoString type;
    2094             506 :     channel->GetContentType(type);
    2095                 : 
    2096             506 :     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             506 :     } else if (type.Find("xml") == kNotFound) {
    2126              37 :       mState &= ~XML_HTTP_REQUEST_PARSEBODY;
    2127             506 :     }
    2128                 :   } else {
    2129                 :     // The request failed, so we shouldn't be parsing anyway
    2130              79 :     mState &= ~XML_HTTP_REQUEST_PARSEBODY;
    2131                 :   }
    2132                 : 
    2133             585 :   if (mState & XML_HTTP_REQUEST_PARSEBODY) {
    2134             938 :     nsCOMPtr<nsIURI> baseURI, docURI;
    2135             469 :     nsIScriptContext* sc = GetContextForEventHandlers(&rv);
    2136             469 :     NS_ENSURE_SUCCESS(rv, rv);
    2137                 :     nsCOMPtr<nsIDocument> doc =
    2138             938 :       nsContentUtils::GetDocumentFromScriptContext(sc);
    2139                 : 
    2140             469 :     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             469 :     const nsAString& emptyStr = EmptyString();
    2150             938 :     nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(GetOwner());
    2151                 :     rv = nsContentUtils::CreateDocument(emptyStr, emptyStr, nsnull, docURI,
    2152                 :                                         baseURI, mPrincipal, global,
    2153                 :                                         mIsHtml ? DocumentFlavorHTML :
    2154                 :                                                   DocumentFlavorLegacyGuess,
    2155             469 :                                         getter_AddRefs(mResponseXML));
    2156             469 :     NS_ENSURE_SUCCESS(rv, rv);
    2157             938 :     nsCOMPtr<nsIDocument> responseDoc = do_QueryInterface(mResponseXML);
    2158             469 :     responseDoc->SetPrincipal(documentPrincipal);
    2159                 : 
    2160             469 :     if (IsSystemXHR()) {
    2161             469 :       responseDoc->ForceEnableXULXBL();
    2162                 :     }
    2163                 : 
    2164             469 :     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             938 :     nsCOMPtr<nsIStreamListener> listener;
    2172             938 :     nsCOMPtr<nsILoadGroup> loadGroup;
    2173             469 :     channel->GetLoadGroup(getter_AddRefs(loadGroup));
    2174                 : 
    2175             469 :     rv = responseDoc->StartDocumentLoad(kLoadAsData, channel, loadGroup,
    2176             469 :                                         nsnull, getter_AddRefs(listener),
    2177             469 :                                         !(mState & XML_HTTP_REQUEST_USE_XSITE_AC));
    2178             469 :     NS_ENSURE_SUCCESS(rv, rv);
    2179                 : 
    2180             469 :     mXMLParserStreamListener = listener;
    2181             469 :     rv = mXMLParserStreamListener->OnStartRequest(request, ctxt);
    2182             469 :     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            2224 :   if (NS_SUCCEEDED(rv) &&
    2188                 :       (mState & XML_HTTP_REQUEST_ASYNC) &&
    2189            1639 :       HasListenersFor(NS_LITERAL_STRING(PROGRESS_STR))) {
    2190               0 :     StartProgressEventTimer();
    2191                 :   }
    2192                 : 
    2193             585 :   return NS_OK;
    2194                 : }
    2195                 : 
    2196                 : /* void onStopRequest (in nsIRequest request, in nsISupports ctxt, in nsresult status, in wstring statusArg); */
    2197                 : NS_IMETHODIMP
    2198             597 : nsXMLHttpRequest::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult status)
    2199                 : {
    2200            1194 :   SAMPLE_LABEL("content", "nsXMLHttpRequest::OnStopRequest");
    2201             597 :   if (!IsSameOrBaseChannel(request, mChannel)) {
    2202               0 :     return NS_OK;
    2203                 :   }
    2204                 : 
    2205             597 :   mWaitingForOnStopRequest = false;
    2206                 : 
    2207             597 :   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            1194 :   nsCOMPtr<nsIMultiPartChannel> mpChannel = do_QueryInterface(request);
    2216             597 :   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             597 :     mState |= XML_HTTP_REQUEST_GOT_FINAL_STOP;
    2226                 :   }
    2227                 : 
    2228             597 :   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             597 :   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             585 :   if (mState & XML_HTTP_REQUEST_PARSEBODY && mXMLParserStreamListener) {
    2246             469 :     mXMLParserStreamListener->OnStopRequest(request, ctxt, status);
    2247                 :   }
    2248                 : 
    2249             585 :   mXMLParserStreamListener = nsnull;
    2250             585 :   mReadRequest = nsnull;
    2251             585 :   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             585 :   if (!mIsHtml) {
    2257             585 :     MaybeDispatchProgressEvents(true);
    2258                 :   }
    2259                 : 
    2260             585 :   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            1170 :   nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
    2283             585 :   NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED);
    2284                 : 
    2285             585 :   channel->SetNotificationCallbacks(nsnull);
    2286             585 :   mNotificationCallbacks = nsnull;
    2287             585 :   mChannelEventSink = nsnull;
    2288             585 :   mProgressEventSink = nsnull;
    2289                 : 
    2290             585 :   mState &= ~XML_HTTP_REQUEST_SYNCLOOPING;
    2291                 : 
    2292             585 :   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             585 :   if (mState & (XML_HTTP_REQUEST_UNSENT |
    2304                 :                 XML_HTTP_REQUEST_DONE)) {
    2305               0 :     return NS_OK;
    2306                 :   }
    2307                 : 
    2308             585 :   if (!mResponseXML) {
    2309             116 :     ChangeStateToDone();
    2310             116 :     return NS_OK;
    2311                 :   }
    2312             469 :   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             938 :   nsCOMPtr<nsIDOMElement> root;
    2328             469 :   mResponseXML->GetDocumentElement(getter_AddRefs(root));
    2329             469 :   if (!root) {
    2330               0 :     mResponseXML = nsnull;
    2331                 :   }
    2332             469 :   ChangeStateToDone();
    2333             469 :   return NS_OK;
    2334                 : }
    2335                 : 
    2336                 : void
    2337             585 : nsXMLHttpRequest::ChangeStateToDone()
    2338                 : {
    2339             585 :   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             585 :   ChangeState(XML_HTTP_REQUEST_DONE, true);
    2346             585 :   if (mTimeoutTimer) {
    2347               0 :     mTimeoutTimer->Cancel();
    2348                 :   }
    2349                 : 
    2350            1170 :   NS_NAMED_LITERAL_STRING(errorStr, ERROR_STR);
    2351            1170 :   NS_NAMED_LITERAL_STRING(loadStr, LOAD_STR);
    2352                 :   DispatchProgressEvent(this,
    2353                 :                         mErrorLoad ? errorStr : loadStr,
    2354             585 :                         !mErrorLoad,
    2355                 :                         mLoadTransferred,
    2356            1170 :                         mErrorLoad ? 0 : mLoadTransferred);
    2357             585 :   if (mErrorLoad && mUpload && !mUploadComplete) {
    2358                 :     DispatchProgressEvent(mUpload, errorStr, true,
    2359               0 :                           mUploadTransferred, mUploadTotal);
    2360                 :   }
    2361                 : 
    2362             585 :   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              71 :     mCORSPreflightChannel = nsnull;
    2369                 :   }
    2370             514 :   else if (!(mState & XML_HTTP_REQUEST_GOT_FINAL_STOP)) {
    2371                 :     // We're a multipart request, so we're not done. Reset to opened.
    2372               0 :     ChangeState(XML_HTTP_REQUEST_OPENED);
    2373                 :   }
    2374             585 : }
    2375                 : 
    2376                 : NS_IMETHODIMP
    2377               0 : nsXMLHttpRequest::SendAsBinary(const nsAString &aBody)
    2378                 : {
    2379               0 :   char *data = static_cast<char*>(NS_Alloc(aBody.Length() + 1));
    2380               0 :   if (!data)
    2381               0 :     return NS_ERROR_OUT_OF_MEMORY;
    2382                 : 
    2383               0 :   nsAString::const_iterator iter, end;
    2384               0 :   aBody.BeginReading(iter);
    2385               0 :   aBody.EndReading(end);
    2386               0 :   char *p = data;
    2387               0 :   while (iter != end) {
    2388               0 :     if (*iter & 0xFF00) {
    2389               0 :       NS_Free(data);
    2390               0 :       return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
    2391                 :     }
    2392               0 :     *p++ = static_cast<char>(*iter++);
    2393                 :   }
    2394               0 :   *p = '\0';
    2395                 : 
    2396               0 :   nsCOMPtr<nsIInputStream> stream;
    2397               0 :   nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream), data,
    2398               0 :                                       aBody.Length(), NS_ASSIGNMENT_ADOPT);
    2399               0 :   if (NS_FAILED(rv))
    2400               0 :     NS_Free(data);
    2401               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2402                 : 
    2403               0 :   nsCOMPtr<nsIWritableVariant> variant = new nsVariant();
    2404               0 :   if (!variant) return NS_ERROR_OUT_OF_MEMORY;
    2405                 : 
    2406               0 :   rv = variant->SetAsISupports(stream);
    2407               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2408                 : 
    2409               0 :   return Send(variant);
    2410                 : }
    2411                 : 
    2412                 : static nsresult
    2413              44 : GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult,
    2414                 :                nsACString& aContentType, nsACString& aCharset)
    2415                 : {
    2416              44 :   *aResult = nsnull;
    2417              44 :   aContentType.AssignLiteral("text/plain");
    2418              44 :   aCharset.AssignLiteral("UTF-8");
    2419                 : 
    2420                 :   PRUint16 dataType;
    2421              44 :   nsresult rv = aBody->GetDataType(&dataType);
    2422              44 :   NS_ENSURE_SUCCESS(rv, rv);
    2423                 : 
    2424              44 :   if (dataType == nsIDataType::VTYPE_INTERFACE ||
    2425                 :       dataType == nsIDataType::VTYPE_INTERFACE_IS) {
    2426               8 :     nsCOMPtr<nsISupports> supports;
    2427                 :     nsID *iid;
    2428               4 :     rv = aBody->GetAsInterface(&iid, getter_AddRefs(supports));
    2429               4 :     NS_ENSURE_SUCCESS(rv, rv);
    2430                 : 
    2431               4 :     nsMemory::Free(iid);
    2432                 : 
    2433                 :     // document?
    2434               8 :     nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(supports);
    2435               4 :     if (doc) {
    2436               0 :       aContentType.AssignLiteral("application/xml");
    2437               0 :       nsAutoString inputEncoding;
    2438               0 :       doc->GetInputEncoding(inputEncoding);
    2439               0 :       if (!DOMStringIsNull(inputEncoding)) {
    2440               0 :         CopyUTF16toUTF8(inputEncoding, aCharset);
    2441                 :       }
    2442                 : 
    2443                 :       // Serialize to a stream so that the encoding used will
    2444                 :       // match the document's.
    2445                 :       nsCOMPtr<nsIDOMSerializer> serializer =
    2446               0 :         do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID, &rv);
    2447               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2448                 : 
    2449               0 :       nsCOMPtr<nsIStorageStream> storStream;
    2450                 :       rv = NS_NewStorageStream(4096, PR_UINT32_MAX,
    2451               0 :                                getter_AddRefs(storStream));
    2452               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2453                 : 
    2454               0 :       nsCOMPtr<nsIOutputStream> output;
    2455               0 :       rv = storStream->GetOutputStream(0, getter_AddRefs(output));
    2456               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2457                 : 
    2458                 :       // Make sure to use the encoding we'll send
    2459               0 :       rv = serializer->SerializeToStream(doc, output, aCharset);
    2460               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2461                 : 
    2462               0 :       output->Close();
    2463                 : 
    2464               0 :       return storStream->NewInputStream(0, aResult);
    2465                 :     }
    2466                 : 
    2467                 :     // nsISupportsString?
    2468               8 :     nsCOMPtr<nsISupportsString> wstr = do_QueryInterface(supports);
    2469               4 :     if (wstr) {
    2470               0 :       nsAutoString string;
    2471               0 :       wstr->GetData(string);
    2472                 : 
    2473                 :       return NS_NewCStringInputStream(aResult,
    2474               0 :                                       NS_ConvertUTF16toUTF8(string));
    2475                 :     }
    2476                 : 
    2477                 :     // nsIInputStream?
    2478               8 :     nsCOMPtr<nsIInputStream> stream = do_QueryInterface(supports);
    2479               4 :     if (stream) {
    2480               4 :       stream.forget(aResult);
    2481               4 :       aCharset.Truncate();
    2482                 : 
    2483               4 :       return NS_OK;
    2484                 :     }
    2485                 : 
    2486                 :     // nsIXHRSendable?
    2487               0 :     nsCOMPtr<nsIXHRSendable> sendable = do_QueryInterface(supports);
    2488               0 :     if (sendable) {
    2489               0 :       return sendable->GetSendInfo(aResult, aContentType, aCharset);
    2490                 :     }
    2491                 : 
    2492                 :     // ArrayBuffer?
    2493                 :     jsval realVal;
    2494                 :     JSObject* obj;
    2495               0 :     nsresult rv = aBody->GetAsJSVal(&realVal);
    2496               0 :     if (NS_SUCCEEDED(rv) && !JSVAL_IS_PRIMITIVE(realVal) &&
    2497                 :         (obj = JSVAL_TO_OBJECT(realVal)) &&
    2498               0 :         (js_IsArrayBuffer(obj))) {
    2499                 : 
    2500               0 :       aContentType.SetIsVoid(true);
    2501               0 :       PRInt32 abLength = JS_GetArrayBufferByteLength(obj);
    2502               0 :       char* data = (char*)JS_GetArrayBufferData(obj);
    2503                 : 
    2504               0 :       nsCOMPtr<nsIInputStream> stream;
    2505               0 :       nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream), data,
    2506               0 :                                           abLength, NS_ASSIGNMENT_COPY);
    2507               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2508               0 :       stream.forget(aResult);
    2509               0 :       aCharset.Truncate();
    2510                 : 
    2511               0 :       return NS_OK;
    2512               0 :     }
    2513                 :   }
    2514              40 :   else if (dataType == nsIDataType::VTYPE_VOID ||
    2515                 :            dataType == nsIDataType::VTYPE_EMPTY) {
    2516                 :     // Makes us act as if !aBody, don't upload anything
    2517              40 :     return NS_OK;
    2518                 :   }
    2519                 : 
    2520               0 :   PRUnichar* data = nsnull;
    2521               0 :   PRUint32 len = 0;
    2522               0 :   rv = aBody->GetAsWStringWithSize(&len, &data);
    2523               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2524                 : 
    2525               0 :   nsString string;
    2526               0 :   string.Adopt(data, len);
    2527                 : 
    2528               0 :   return NS_NewCStringInputStream(aResult, NS_ConvertUTF16toUTF8(string));
    2529                 : }
    2530                 : 
    2531                 : /* void send (in nsIVariant aBody); */
    2532                 : NS_IMETHODIMP
    2533             597 : nsXMLHttpRequest::Send(nsIVariant *aBody)
    2534                 : {
    2535             597 :   NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED);
    2536                 : 
    2537             597 :   nsresult rv = CheckInnerWindowCorrectness();
    2538             597 :   NS_ENSURE_SUCCESS(rv, rv);
    2539                 : 
    2540                 :   // Return error if we're already processing a request
    2541             597 :   if (XML_HTTP_REQUEST_SENT & mState) {
    2542               0 :     return NS_ERROR_FAILURE;
    2543                 :   }
    2544                 : 
    2545                 :   // Make sure we've been opened
    2546             597 :   if (!mChannel || !(XML_HTTP_REQUEST_OPENED & mState)) {
    2547               0 :     return NS_ERROR_NOT_INITIALIZED;
    2548                 :   }
    2549                 : 
    2550                 : 
    2551                 :   // nsIRequest::LOAD_BACKGROUND prevents throbber from becoming active, which
    2552                 :   // in turn keeps STOP button from becoming active.  If the consumer passed in
    2553                 :   // a progress event handler we must load with nsIRequest::LOAD_NORMAL or
    2554                 :   // necko won't generate any progress notifications.
    2555            2985 :   if (HasListenersFor(NS_LITERAL_STRING(PROGRESS_STR)) ||
    2556            1791 :       HasListenersFor(NS_LITERAL_STRING(UPLOADPROGRESS_STR)) ||
    2557            1194 :       (mUpload && mUpload->HasListenersFor(NS_LITERAL_STRING(PROGRESS_STR)))) {
    2558                 :     nsLoadFlags loadFlags;
    2559               0 :     mChannel->GetLoadFlags(&loadFlags);
    2560               0 :     loadFlags &= ~nsIRequest::LOAD_BACKGROUND;
    2561               0 :     loadFlags |= nsIRequest::LOAD_NORMAL;
    2562               0 :     mChannel->SetLoadFlags(loadFlags);
    2563                 :   }
    2564                 : 
    2565                 :   // XXX We should probably send a warning to the JS console
    2566                 :   //     if there are no event listeners set and we are doing
    2567                 :   //     an asynchronous call.
    2568                 : 
    2569                 :   // Ignore argument if method is GET, there is no point in trying to
    2570                 :   // upload anything
    2571            1194 :   nsCAutoString method;
    2572            1194 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
    2573                 : 
    2574             597 :   if (httpChannel) {
    2575             595 :     httpChannel->GetRequestMethod(method); // If GET, method name will be uppercase
    2576                 : 
    2577             595 :     if (!IsSystemXHR()) {
    2578                 :       // Get the referrer for the request.
    2579                 :       //
    2580                 :       // If it weren't for history.push/replaceState, we could just use the
    2581                 :       // principal's URI here.  But since we want changes to the URI effected
    2582                 :       // by push/replaceState to be reflected in the XHR referrer, we have to
    2583                 :       // be more clever.
    2584                 :       //
    2585                 :       // If the document's original URI (before any push/replaceStates) matches
    2586                 :       // our principal, then we use the document's current URI (after
    2587                 :       // push/replaceStates).  Otherwise (if the document is, say, a data:
    2588                 :       // URI), we just use the principal's URI.
    2589                 : 
    2590               0 :       nsCOMPtr<nsIURI> principalURI;
    2591               0 :       mPrincipal->GetURI(getter_AddRefs(principalURI));
    2592                 : 
    2593               0 :       nsIScriptContext* sc = GetContextForEventHandlers(&rv);
    2594               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2595                 :       nsCOMPtr<nsIDocument> doc =
    2596               0 :         nsContentUtils::GetDocumentFromScriptContext(sc);
    2597                 : 
    2598               0 :       nsCOMPtr<nsIURI> docCurURI;
    2599               0 :       nsCOMPtr<nsIURI> docOrigURI;
    2600               0 :       if (doc) {
    2601               0 :         docCurURI = doc->GetDocumentURI();
    2602               0 :         docOrigURI = doc->GetOriginalURI();
    2603                 :       }
    2604                 : 
    2605               0 :       nsCOMPtr<nsIURI> referrerURI;
    2606                 : 
    2607               0 :       if (principalURI && docCurURI && docOrigURI) {
    2608               0 :         bool equal = false;
    2609               0 :         principalURI->Equals(docOrigURI, &equal);
    2610               0 :         if (equal) {
    2611               0 :           referrerURI = docCurURI;
    2612                 :         }
    2613                 :       }
    2614                 : 
    2615               0 :       if (!referrerURI)
    2616               0 :         referrerURI = principalURI;
    2617                 : 
    2618               0 :       httpChannel->SetReferrer(referrerURI);
    2619                 :     }
    2620                 : 
    2621                 :     // Some extensions override the http protocol handler and provide their own
    2622                 :     // implementation. The channels returned from that implementation doesn't
    2623                 :     // seem to always implement the nsIUploadChannel2 interface, presumably
    2624                 :     // because it's a new interface.
    2625                 :     // Eventually we should remove this and simply require that http channels
    2626                 :     // implement the new interface.
    2627                 :     // See bug 529041
    2628                 :     nsCOMPtr<nsIUploadChannel2> uploadChannel2 =
    2629            1190 :       do_QueryInterface(httpChannel);
    2630             595 :     if (!uploadChannel2) {
    2631                 :       nsCOMPtr<nsIConsoleService> consoleService =
    2632               0 :         do_GetService(NS_CONSOLESERVICE_CONTRACTID);
    2633               0 :       if (consoleService) {
    2634               0 :         consoleService->LogStringMessage(NS_LITERAL_STRING(
    2635                 :           "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."
    2636               0 :                                                            ).get());
    2637                 :       }
    2638                 :     }
    2639                 :   }
    2640                 : 
    2641             597 :   mUploadTransferred = 0;
    2642             597 :   mUploadTotal = 0;
    2643                 :   // By default we don't have any upload, so mark upload complete.
    2644             597 :   mUploadComplete = true;
    2645             597 :   mErrorLoad = false;
    2646             597 :   mLoadLengthComputable = false;
    2647             597 :   mLoadTotal = 0;
    2648             597 :   mUploadProgress = 0;
    2649             597 :   mUploadProgressMax = 0;
    2650             597 :   if (aBody && httpChannel && !method.EqualsLiteral("GET")) {
    2651                 : 
    2652              88 :     nsCAutoString charset;
    2653              88 :     nsCAutoString defaultContentType;
    2654              88 :     nsCOMPtr<nsIInputStream> postDataStream;
    2655                 : 
    2656              44 :     rv = GetRequestBody(aBody, getter_AddRefs(postDataStream),
    2657              44 :                         defaultContentType, charset);
    2658              44 :     NS_ENSURE_SUCCESS(rv, rv);
    2659                 : 
    2660              44 :     if (postDataStream) {
    2661                 :       // If no content type header was set by the client, we set it to
    2662                 :       // application/xml.
    2663               8 :       nsCAutoString contentType;
    2664               8 :       if (NS_FAILED(httpChannel->
    2665                 :                       GetRequestHeader(NS_LITERAL_CSTRING("Content-Type"),
    2666                 :                                        contentType)) ||
    2667               4 :           contentType.IsEmpty()) {
    2668               0 :         contentType = defaultContentType;
    2669                 :       }
    2670                 : 
    2671                 :       // We don't want to set a charset for streams.
    2672               4 :       if (!charset.IsEmpty()) {
    2673               0 :         nsCAutoString specifiedCharset;
    2674                 :         bool haveCharset;
    2675                 :         PRInt32 charsetStart, charsetEnd;
    2676                 :         rv = NS_ExtractCharsetFromContentType(contentType, specifiedCharset,
    2677                 :                                               &haveCharset, &charsetStart,
    2678               0 :                                               &charsetEnd);
    2679               0 :         if (NS_SUCCEEDED(rv)) {
    2680                 :           // special case: the extracted charset is quoted with single quotes
    2681                 :           // -- for the purpose of preserving what was set we want to handle
    2682                 :           // them as delimiters (although they aren't really)
    2683               0 :           if (specifiedCharset.Length() >= 2 &&
    2684               0 :               specifiedCharset.First() == '\'' &&
    2685               0 :               specifiedCharset.Last() == '\'') {
    2686                 :             specifiedCharset = Substring(specifiedCharset, 1,
    2687               0 :                                          specifiedCharset.Length() - 2);
    2688                 :           }
    2689                 : 
    2690                 :           // If the content-type the page set already has a charset parameter,
    2691                 :           // and it's the same charset, up to case, as |charset|, just send the
    2692                 :           // page-set content-type header.  Apparently at least
    2693                 :           // google-web-toolkit is broken and relies on the exact case of its
    2694                 :           // charset parameter, which makes things break if we use |charset|
    2695                 :           // (which is always a fully resolved charset per our charset alias
    2696                 :           // table, hence might be differently cased).
    2697               0 :           if (!specifiedCharset.Equals(charset,
    2698               0 :                                        nsCaseInsensitiveCStringComparator())) {
    2699               0 :             nsCAutoString newCharset("; charset=");
    2700               0 :             newCharset.Append(charset);
    2701                 :             contentType.Replace(charsetStart, charsetEnd - charsetStart,
    2702               0 :                                 newCharset);
    2703                 :           }
    2704                 :         }
    2705                 :       }
    2706                 : 
    2707                 :       // If necessary, wrap the stream in a buffered stream so as to guarantee
    2708                 :       // support for our upload when calling ExplicitSetUploadStream.
    2709               4 :       if (!NS_InputStreamIsBuffered(postDataStream)) {
    2710               0 :         nsCOMPtr<nsIInputStream> bufferedStream;
    2711               0 :         rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
    2712                 :                                        postDataStream, 
    2713               0 :                                        4096);
    2714               0 :         NS_ENSURE_SUCCESS(rv, rv);
    2715                 : 
    2716               0 :         postDataStream = bufferedStream;
    2717                 :       }
    2718                 : 
    2719               4 :       mUploadComplete = false;
    2720               4 :       PRUint32 uploadTotal = 0;
    2721               4 :       postDataStream->Available(&uploadTotal);
    2722               4 :       mUploadTotal = uploadTotal;
    2723                 : 
    2724                 :       // We want to use a newer version of the upload channel that won't
    2725                 :       // ignore the necessary headers for an empty Content-Type.
    2726              12 :       nsCOMPtr<nsIUploadChannel2> uploadChannel2(do_QueryInterface(httpChannel));
    2727                 :       // This assertion will fire if buggy extensions are installed
    2728               4 :       NS_ASSERTION(uploadChannel2, "http must support nsIUploadChannel2");
    2729               4 :       if (uploadChannel2) {
    2730               4 :           uploadChannel2->ExplicitSetUploadStream(postDataStream, contentType,
    2731               4 :                                                  -1, method, false);
    2732                 :       }
    2733                 :       else {
    2734                 :         // http channel doesn't support the new nsIUploadChannel2. Emulate
    2735                 :         // as best we can using nsIUploadChannel
    2736               0 :         if (contentType.IsEmpty()) {
    2737               0 :           contentType.AssignLiteral("application/octet-stream");
    2738                 :         }
    2739                 :         nsCOMPtr<nsIUploadChannel> uploadChannel =
    2740               0 :           do_QueryInterface(httpChannel);
    2741               0 :         uploadChannel->SetUploadStream(postDataStream, contentType, -1);
    2742                 :         // Reset the method to its original value
    2743               0 :         httpChannel->SetRequestMethod(method);
    2744                 :       }
    2745                 :     }
    2746                 :   }
    2747                 : 
    2748             597 :   if (httpChannel) {
    2749            1190 :     nsCAutoString contentTypeHeader;
    2750            1190 :     rv = httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("Content-Type"),
    2751             595 :                                        contentTypeHeader);
    2752             595 :     if (NS_SUCCEEDED(rv)) {
    2753               8 :       nsCAutoString contentType, charset;
    2754               4 :       rv = NS_ParseContentType(contentTypeHeader, contentType, charset);
    2755               4 :       NS_ENSURE_SUCCESS(rv, rv);
    2756                 :   
    2757              12 :       if (!contentType.LowerCaseEqualsLiteral("text/plain") &&
    2758               4 :           !contentType.LowerCaseEqualsLiteral("application/x-www-form-urlencoded") &&
    2759               4 :           !contentType.LowerCaseEqualsLiteral("multipart/form-data")) {
    2760               4 :         mCORSUnsafeHeaders.AppendElement(NS_LITERAL_CSTRING("Content-Type"));
    2761                 :       }
    2762                 :     }
    2763                 :   }
    2764                 : 
    2765             597 :   ResetResponse();
    2766                 : 
    2767             597 :   rv = CheckChannelForCrossSiteRequest(mChannel);
    2768             597 :   NS_ENSURE_SUCCESS(rv, rv);
    2769                 : 
    2770             597 :   bool withCredentials = !!(mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS);
    2771                 : 
    2772                 :   // Hook us up to listen to redirects and the like
    2773             597 :   mChannel->GetNotificationCallbacks(getter_AddRefs(mNotificationCallbacks));
    2774             597 :   mChannel->SetNotificationCallbacks(this);
    2775                 : 
    2776                 :   // Create our listener
    2777            1194 :   nsCOMPtr<nsIStreamListener> listener = this;
    2778             597 :   if (mState & XML_HTTP_REQUEST_MULTIPART) {
    2779               0 :     listener = new nsMultipartProxyListener(listener);
    2780               0 :     if (!listener) {
    2781               0 :       return NS_ERROR_OUT_OF_MEMORY;
    2782                 :     }
    2783                 :   }
    2784                 : 
    2785             597 :   if (!IsSystemXHR()) {
    2786                 :     // Always create a nsCORSListenerProxy here even if it's
    2787                 :     // a same-origin request right now, since it could be redirected.
    2788                 :     listener = new nsCORSListenerProxy(listener, mPrincipal, mChannel,
    2789               0 :                                        withCredentials, true, &rv);
    2790               0 :     NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
    2791               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2792                 :   }
    2793                 : 
    2794                 :   // Bypass the network cache in cases where it makes no sense:
    2795                 :   // 1) Multipart responses are very large and would likely be doomed by the
    2796                 :   //    cache once they grow too large, so they are not worth caching.
    2797                 :   // 2) POST responses are always unique, and we provide no API that would
    2798                 :   //    allow our consumers to specify a "cache key" to access old POST
    2799                 :   //    responses, so they are not worth caching.
    2800             597 :   if ((mState & XML_HTTP_REQUEST_MULTIPART) || method.EqualsLiteral("POST")) {
    2801                 :     AddLoadFlags(mChannel,
    2802              12 :         nsIRequest::LOAD_BYPASS_CACHE | nsIRequest::INHIBIT_CACHING);
    2803                 :   }
    2804                 :   // When we are sync loading, we need to bypass the local cache when it would
    2805                 :   // otherwise block us waiting for exclusive access to the cache.  If we don't
    2806                 :   // do this, then we could dead lock in some cases (see bug 309424).
    2807             585 :   else if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
    2808                 :     AddLoadFlags(mChannel,
    2809              50 :         nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY);
    2810                 :   }
    2811                 : 
    2812                 :   // Since we expect XML data, set the type hint accordingly
    2813                 :   // This means that we always try to parse local files as XML
    2814                 :   // ignoring return value, as this is not critical
    2815             597 :   mChannel->SetContentType(NS_LITERAL_CSTRING("application/xml"));
    2816                 : 
    2817                 :   // We're about to send the request.  Start our timeout.
    2818             597 :   mRequestSentTime = PR_Now();
    2819             597 :   StartTimeoutTimer();
    2820                 : 
    2821                 :   // Set up the preflight if needed
    2822             597 :   if (mState & XML_HTTP_REQUEST_NEED_AC_PREFLIGHT) {
    2823                 :     // Check to see if this initial OPTIONS request has already been cached
    2824                 :     // in our special Access Control Cache.
    2825                 : 
    2826                 :     rv = NS_StartCORSPreflight(mChannel, listener,
    2827                 :                                mPrincipal, withCredentials,
    2828                 :                                mCORSUnsafeHeaders,
    2829               0 :                                getter_AddRefs(mCORSPreflightChannel));
    2830               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2831                 :   }
    2832                 :   else {
    2833                 :     // Start reading from the channel
    2834             597 :     rv = mChannel->AsyncOpen(listener, nsnull);
    2835                 :   }
    2836                 : 
    2837             597 :   if (NS_FAILED(rv)) {
    2838                 :     // Drop our ref to the channel to avoid cycles
    2839               0 :     mChannel = nsnull;
    2840               0 :     mCORSPreflightChannel = nsnull;
    2841               0 :     return rv;
    2842                 :   }
    2843                 : 
    2844                 :   // Either AsyncOpen was called, or CORS will open the channel later.
    2845             597 :   mWaitingForOnStopRequest = true;
    2846                 : 
    2847                 :   // If we're synchronous, spin an event loop here and wait
    2848             597 :   if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
    2849              58 :     mState |= XML_HTTP_REQUEST_SYNCLOOPING;
    2850                 : 
    2851             116 :     nsCOMPtr<nsIDocument> suspendedDoc;
    2852             116 :     nsCOMPtr<nsIRunnable> resumeTimeoutRunnable;
    2853              58 :     if (GetOwner()) {
    2854               0 :       nsCOMPtr<nsIDOMWindow> topWindow;
    2855               0 :       if (NS_SUCCEEDED(GetOwner()->GetTop(getter_AddRefs(topWindow)))) {
    2856               0 :         nsCOMPtr<nsPIDOMWindow> suspendedWindow(do_QueryInterface(topWindow));
    2857               0 :         if (suspendedWindow &&
    2858               0 :             (suspendedWindow = suspendedWindow->GetCurrentInnerWindow())) {
    2859               0 :           suspendedDoc = do_QueryInterface(suspendedWindow->GetExtantDocument());
    2860               0 :           if (suspendedDoc) {
    2861               0 :             suspendedDoc->SuppressEventHandling();
    2862                 :           }
    2863               0 :           suspendedWindow->SuspendTimeouts(1, false);
    2864               0 :           resumeTimeoutRunnable = new nsResumeTimeoutsEvent(suspendedWindow);
    2865                 :         }
    2866                 :       }
    2867                 :     }
    2868                 : 
    2869              58 :     ChangeState(XML_HTTP_REQUEST_SENT);
    2870                 :     // Note, calling ChangeState may have cleared
    2871                 :     // XML_HTTP_REQUEST_SYNCLOOPING flag.
    2872              58 :     nsIThread *thread = NS_GetCurrentThread();
    2873              58 :     while (mState & XML_HTTP_REQUEST_SYNCLOOPING) {
    2874            1230 :       if (!NS_ProcessNextEvent(thread)) {
    2875               0 :         rv = NS_ERROR_UNEXPECTED;
    2876               0 :         break;
    2877                 :       }
    2878                 :     }
    2879                 : 
    2880              58 :     if (suspendedDoc) {
    2881               0 :       suspendedDoc->UnsuppressEventHandlingAndFireEvents(true);
    2882                 :     }
    2883                 : 
    2884              58 :     if (resumeTimeoutRunnable) {
    2885               0 :       NS_DispatchToCurrentThread(resumeTimeoutRunnable);
    2886                 :     }
    2887                 :   } else {
    2888                 :     // Now that we've successfully opened the channel, we can change state.  Note
    2889                 :     // that this needs to come after the AsyncOpen() and rv check, because this
    2890                 :     // can run script that would try to restart this request, and that could end
    2891                 :     // up doing our AsyncOpen on a null channel if the reentered AsyncOpen fails.
    2892             539 :     ChangeState(XML_HTTP_REQUEST_SENT);
    2893            1625 :     if ((!mUploadComplete &&
    2894             547 :          HasListenersFor(NS_LITERAL_STRING(UPLOADPROGRESS_STR))) ||
    2895            1078 :         (mUpload && mUpload->HasListenersFor(NS_LITERAL_STRING(PROGRESS_STR)))) {
    2896               0 :       StartProgressEventTimer();
    2897                 :     }
    2898             539 :     DispatchProgressEvent(this, NS_LITERAL_STRING(LOADSTART_STR), false,
    2899             539 :                           0, 0);
    2900             539 :     if (mUpload && !mUploadComplete) {
    2901               0 :       DispatchProgressEvent(mUpload, NS_LITERAL_STRING(LOADSTART_STR), true,
    2902               0 :                             0, mUploadTotal);
    2903                 :     }
    2904                 :   }
    2905                 : 
    2906             597 :   if (!mChannel) {
    2907               0 :     return NS_ERROR_FAILURE;
    2908                 :   }
    2909                 : 
    2910             597 :   return rv;
    2911                 : }
    2912                 : 
    2913                 : /* void setRequestHeader (in AUTF8String header, in AUTF8String value); */
    2914                 : NS_IMETHODIMP
    2915              80 : nsXMLHttpRequest::SetRequestHeader(const nsACString& header,
    2916                 :                                    const nsACString& value)
    2917                 : {
    2918                 :   nsresult rv;
    2919                 : 
    2920                 :   // Make sure we don't store an invalid header name in mCORSUnsafeHeaders
    2921              80 :   if (!IsValidHTTPToken(header)) {
    2922               0 :     return NS_ERROR_FAILURE;
    2923                 :   }
    2924                 : 
    2925                 :   // Check that we haven't already opened the channel. We can't rely on
    2926                 :   // the channel throwing from mChannel->SetRequestHeader since we might
    2927                 :   // still be waiting for mCORSPreflightChannel to actually open mChannel
    2928              80 :   if (mCORSPreflightChannel) {
    2929                 :     bool pending;
    2930               0 :     rv = mCORSPreflightChannel->IsPending(&pending);
    2931               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2932                 :     
    2933               0 :     if (pending) {
    2934               0 :       return NS_ERROR_IN_PROGRESS;
    2935                 :     }
    2936                 :   }
    2937                 : 
    2938              80 :   if (!(mState & XML_HTTP_REQUEST_OPENED))
    2939               1 :     return NS_ERROR_IN_PROGRESS;
    2940                 : 
    2941              79 :   if (!mChannel)             // open() initializes mChannel, and open()
    2942               0 :     return NS_ERROR_FAILURE; // must be called before first setRequestHeader()
    2943                 : 
    2944             158 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
    2945              79 :   if (!httpChannel) {
    2946               0 :     return NS_OK;
    2947                 :   }
    2948                 : 
    2949                 :   // Prevent modification to certain HTTP headers (see bug 302263), unless
    2950                 :   // the executing script has UniversalXPConnect.
    2951                 : 
    2952                 :   bool privileged;
    2953              79 :   rv = IsCapabilityEnabled("UniversalXPConnect", &privileged);
    2954              79 :   if (NS_FAILED(rv))
    2955               0 :     return NS_ERROR_FAILURE;
    2956                 : 
    2957              79 :   if (!privileged) {
    2958                 :     // Check for dangerous headers
    2959                 :     const char *kInvalidHeaders[] = {
    2960                 :       "accept-charset", "accept-encoding", "access-control-request-headers",
    2961                 :       "access-control-request-method", "connection", "content-length",
    2962                 :       "cookie", "cookie2", "content-transfer-encoding", "date", "expect",
    2963                 :       "host", "keep-alive", "origin", "referer", "te", "trailer",
    2964                 :       "transfer-encoding", "upgrade", "user-agent", "via"
    2965               0 :     };
    2966                 :     PRUint32 i;
    2967               0 :     for (i = 0; i < ArrayLength(kInvalidHeaders); ++i) {
    2968               0 :       if (header.LowerCaseEqualsASCII(kInvalidHeaders[i])) {
    2969               0 :         NS_WARNING("refusing to set request header");
    2970               0 :         return NS_OK;
    2971                 :       }
    2972                 :     }
    2973               0 :     if (StringBeginsWith(header, NS_LITERAL_CSTRING("proxy-"),
    2974               0 :                          nsCaseInsensitiveCStringComparator()) ||
    2975               0 :         StringBeginsWith(header, NS_LITERAL_CSTRING("sec-"),
    2976               0 :                          nsCaseInsensitiveCStringComparator())) {
    2977               0 :       NS_WARNING("refusing to set request header");
    2978               0 :       return NS_OK;
    2979                 :     }
    2980                 : 
    2981                 :     // Check for dangerous cross-site headers
    2982               0 :     bool safeHeader = IsSystemXHR();
    2983               0 :     if (!safeHeader) {
    2984                 :       // Content-Type isn't always safe, but we'll deal with it in Send()
    2985                 :       const char *kCrossOriginSafeHeaders[] = {
    2986                 :         "accept", "accept-language", "content-language", "content-type",
    2987                 :         "last-event-id"
    2988               0 :       };
    2989               0 :       for (i = 0; i < ArrayLength(kCrossOriginSafeHeaders); ++i) {
    2990               0 :         if (header.LowerCaseEqualsASCII(kCrossOriginSafeHeaders[i])) {
    2991               0 :           safeHeader = true;
    2992               0 :           break;
    2993                 :         }
    2994                 :       }
    2995                 :     }
    2996                 : 
    2997               0 :     if (!safeHeader) {
    2998               0 :       mCORSUnsafeHeaders.AppendElement(header);
    2999                 :     }
    3000                 :   }
    3001                 : 
    3002                 :   // We need to set, not add to, the header.
    3003              79 :   rv = httpChannel->SetRequestHeader(header, value, false);
    3004              79 :   if (NS_SUCCEEDED(rv)) {
    3005                 :     // We'll want to duplicate this header for any replacement channels (eg. on redirect)
    3006                 :     RequestHeader reqHeader = {
    3007                 :       nsCString(header), nsCString(value)
    3008             158 :     };
    3009              79 :     mModifiedRequestHeaders.AppendElement(reqHeader);
    3010                 :   }
    3011                 : 
    3012              79 :   return rv;
    3013                 : }
    3014                 : 
    3015                 : /* attribute unsigned long timeout; */
    3016                 : NS_IMETHODIMP
    3017               0 : nsXMLHttpRequest::GetTimeout(PRUint32 *aTimeout)
    3018                 : {
    3019               0 :   *aTimeout = mTimeoutMilliseconds;
    3020               0 :   return NS_OK;
    3021                 : }
    3022                 : NS_IMETHODIMP
    3023               0 : nsXMLHttpRequest::SetTimeout(PRUint32 aTimeout)
    3024                 : {
    3025               0 :   if ((mState & (XML_HTTP_REQUEST_ASYNC | XML_HTTP_REQUEST_UNSENT)) ||
    3026               0 :       !HasOrHasHadOwner()) {
    3027               0 :     mTimeoutMilliseconds = aTimeout;
    3028               0 :     if (mRequestSentTime) {
    3029               0 :       StartTimeoutTimer();
    3030                 :     }
    3031               0 :     return NS_OK;
    3032                 :   }
    3033                 : 
    3034                 :   /* Timeout is not supported for synchronous requests with an owning window,
    3035                 :      per XHR2 spec. */
    3036               0 :   LogMessage("TimeoutSyncXHRWarning", GetOwner());
    3037               0 :   return NS_ERROR_DOM_INVALID_ACCESS_ERR;
    3038                 : }
    3039                 : 
    3040                 : void
    3041             597 : nsXMLHttpRequest::StartTimeoutTimer()
    3042                 : {
    3043             597 :   NS_ABORT_IF_FALSE(mRequestSentTime,
    3044                 :                     "StartTimeoutTimer mustn't be called before the request was sent!");
    3045             597 :   if (mState & XML_HTTP_REQUEST_DONE) {
    3046                 :     // do nothing!
    3047               0 :     return;
    3048                 :   }
    3049                 : 
    3050             597 :   if (mTimeoutTimer) {
    3051               0 :     mTimeoutTimer->Cancel();
    3052                 :   }
    3053                 : 
    3054             597 :   if (!mTimeoutMilliseconds) {
    3055             597 :     return;
    3056                 :   }
    3057                 : 
    3058               0 :   if (!mTimeoutTimer) {
    3059               0 :     mTimeoutTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
    3060                 :   }
    3061                 :   PRUint32 elapsed =
    3062               0 :     (PRUint32)((PR_Now() - mRequestSentTime) / PR_USEC_PER_MSEC);
    3063               0 :   mTimeoutTimer->InitWithCallback(
    3064                 :     this,
    3065                 :     mTimeoutMilliseconds > elapsed ? mTimeoutMilliseconds - elapsed : 0,
    3066                 :     nsITimer::TYPE_ONE_SHOT
    3067               0 :   );
    3068                 : }
    3069                 : 
    3070                 : /* readonly attribute long readyState; */
    3071                 : NS_IMETHODIMP
    3072             124 : nsXMLHttpRequest::GetReadyState(PRUint16 *aState)
    3073                 : {
    3074             124 :   NS_ENSURE_ARG_POINTER(aState);
    3075                 :   // Translate some of our internal states for external consumers
    3076             124 :   if (mState & XML_HTTP_REQUEST_UNSENT) {
    3077               0 :     *aState = UNSENT;
    3078             124 :   } else  if (mState & (XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT)) {
    3079               2 :     *aState = OPENED;
    3080             122 :   } else if (mState & XML_HTTP_REQUEST_HEADERS_RECEIVED) {
    3081               2 :     *aState = HEADERS_RECEIVED;
    3082             120 :   } else if (mState & (XML_HTTP_REQUEST_LOADING | XML_HTTP_REQUEST_STOPPED)) {
    3083               1 :     *aState = LOADING;
    3084             119 :   } else if (mState & XML_HTTP_REQUEST_DONE) {
    3085             119 :     *aState = DONE;
    3086                 :   } else {
    3087               0 :     NS_ERROR("Should not happen");
    3088                 :   }
    3089                 : 
    3090             124 :   return NS_OK;
    3091                 : }
    3092                 : 
    3093                 : /* void   overrideMimeType(in AUTF8String mimetype); */
    3094                 : NS_IMETHODIMP
    3095             534 : nsXMLHttpRequest::OverrideMimeType(const nsACString& aMimeType)
    3096                 : {
    3097                 :   // XXX Should we do some validation here?
    3098             534 :   mOverrideMimeType.Assign(aMimeType);
    3099             534 :   return NS_OK;
    3100                 : }
    3101                 : 
    3102                 : 
    3103                 : /* attribute boolean multipart; */
    3104                 : NS_IMETHODIMP
    3105               0 : nsXMLHttpRequest::GetMultipart(bool *_retval)
    3106                 : {
    3107               0 :   *_retval = !!(mState & XML_HTTP_REQUEST_MULTIPART);
    3108                 : 
    3109               0 :   return NS_OK;
    3110                 : }
    3111                 : 
    3112                 : /* attribute boolean multipart; */
    3113                 : NS_IMETHODIMP
    3114               0 : nsXMLHttpRequest::SetMultipart(bool aMultipart)
    3115                 : {
    3116               0 :   if (!(mState & XML_HTTP_REQUEST_UNSENT)) {
    3117                 :     // Can't change this while we're in the middle of something.
    3118               0 :     return NS_ERROR_IN_PROGRESS;
    3119                 :   }
    3120                 : 
    3121               0 :   if (aMultipart) {
    3122               0 :     mState |= XML_HTTP_REQUEST_MULTIPART;
    3123                 :   } else {
    3124               0 :     mState &= ~XML_HTTP_REQUEST_MULTIPART;
    3125                 :   }
    3126                 : 
    3127               0 :   return NS_OK;
    3128                 : }
    3129                 : 
    3130                 : /* attribute boolean mozBackgroundRequest; */
    3131                 : NS_IMETHODIMP
    3132               0 : nsXMLHttpRequest::GetMozBackgroundRequest(bool *_retval)
    3133                 : {
    3134               0 :   *_retval = !!(mState & XML_HTTP_REQUEST_BACKGROUND);
    3135                 : 
    3136               0 :   return NS_OK;
    3137                 : }
    3138                 : 
    3139                 : /* attribute boolean mozBackgroundRequest; */
    3140                 : NS_IMETHODIMP
    3141              87 : nsXMLHttpRequest::SetMozBackgroundRequest(bool aMozBackgroundRequest)
    3142                 : {
    3143                 :   bool privileged;
    3144                 : 
    3145              87 :   nsresult rv = IsCapabilityEnabled("UniversalXPConnect", &privileged);
    3146              87 :   NS_ENSURE_SUCCESS(rv, rv);
    3147                 : 
    3148              87 :   if (!privileged)
    3149               0 :     return NS_ERROR_DOM_SECURITY_ERR;
    3150                 : 
    3151              87 :   if (!(mState & XML_HTTP_REQUEST_UNSENT)) {
    3152                 :     // Can't change this while we're in the middle of something.
    3153               0 :     return NS_ERROR_IN_PROGRESS;
    3154                 :   }
    3155                 : 
    3156              87 :   if (aMozBackgroundRequest) {
    3157              87 :     mState |= XML_HTTP_REQUEST_BACKGROUND;
    3158                 :   } else {
    3159               0 :     mState &= ~XML_HTTP_REQUEST_BACKGROUND;
    3160                 :   }
    3161                 : 
    3162              87 :   return NS_OK;
    3163                 : }
    3164                 : 
    3165                 : /* attribute boolean withCredentials; */
    3166                 : NS_IMETHODIMP
    3167               0 : nsXMLHttpRequest::GetWithCredentials(bool *_retval)
    3168                 : {
    3169               0 :   *_retval = !!(mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS);
    3170                 : 
    3171               0 :   return NS_OK;
    3172                 : }
    3173                 : 
    3174                 : /* attribute boolean withCredentials; */
    3175                 : NS_IMETHODIMP
    3176               1 : nsXMLHttpRequest::SetWithCredentials(bool aWithCredentials)
    3177                 : {
    3178                 :   // Return error if we're already processing a request
    3179               1 :   if (XML_HTTP_REQUEST_SENT & mState) {
    3180               0 :     return NS_ERROR_FAILURE;
    3181                 :   }
    3182                 : 
    3183                 :   // sync request is not allowed setting withCredentials in window context
    3184               1 :   if (HasOrHasHadOwner() &&
    3185               0 :       !(mState & (XML_HTTP_REQUEST_UNSENT | XML_HTTP_REQUEST_ASYNC))) {
    3186               0 :     LogMessage("WithCredentialsSyncXHRWarning", GetOwner());
    3187               0 :     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
    3188                 :   }
    3189                 : 
    3190               1 :   if (aWithCredentials) {
    3191               0 :     mState |= XML_HTTP_REQUEST_AC_WITH_CREDENTIALS;
    3192                 :   }
    3193                 :   else {
    3194               1 :     mState &= ~XML_HTTP_REQUEST_AC_WITH_CREDENTIALS;
    3195                 :   }
    3196               1 :   return NS_OK;
    3197                 : }
    3198                 : 
    3199                 : nsresult
    3200            2953 : nsXMLHttpRequest::ChangeState(PRUint32 aState, bool aBroadcast)
    3201                 : {
    3202                 :   // If we are setting one of the mutually exclusive states,
    3203                 :   // unset those state bits first.
    3204            2953 :   if (aState & XML_HTTP_REQUEST_LOADSTATES) {
    3205            2953 :     mState &= ~XML_HTTP_REQUEST_LOADSTATES;
    3206                 :   }
    3207            2953 :   mState |= aState;
    3208            2953 :   nsresult rv = NS_OK;
    3209                 : 
    3210            3507 :   if (mProgressNotifier &&
    3211            3507 :       !(aState & (XML_HTTP_REQUEST_HEADERS_RECEIVED | XML_HTTP_REQUEST_LOADING))) {
    3212             416 :     mProgressTimerIsActive = false;
    3213             416 :     mProgressNotifier->Cancel();
    3214                 :   }
    3215                 : 
    3216            2953 :   if ((aState & XML_HTTP_REQUEST_LOADSTATES) && // Broadcast load states only
    3217                 :       aBroadcast &&
    3218                 :       (mState & XML_HTTP_REQUEST_ASYNC ||
    3219                 :        aState & XML_HTTP_REQUEST_OPENED ||
    3220                 :        aState & XML_HTTP_REQUEST_DONE)) {
    3221            5630 :     nsCOMPtr<nsIDOMEvent> event;
    3222            2815 :     rv = CreateReadystatechangeEvent(getter_AddRefs(event));
    3223            2815 :     NS_ENSURE_SUCCESS(rv, rv);
    3224                 : 
    3225            5630 :     DispatchDOMEvent(nsnull, event, nsnull, nsnull);
    3226                 :   }
    3227                 : 
    3228            2953 :   return rv;
    3229                 : }
    3230                 : 
    3231                 : /*
    3232                 :  * Simple helper class that just forwards the redirect callback back
    3233                 :  * to the nsXMLHttpRequest.
    3234                 :  */
    3235                 : class AsyncVerifyRedirectCallbackForwarder : public nsIAsyncVerifyRedirectCallback
    3236               0 : {
    3237                 : public:
    3238               0 :   AsyncVerifyRedirectCallbackForwarder(nsXMLHttpRequest *xhr)
    3239               0 :     : mXHR(xhr)
    3240                 :   {
    3241               0 :   }
    3242                 : 
    3243               0 :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    3244            1464 :   NS_DECL_CYCLE_COLLECTION_CLASS(AsyncVerifyRedirectCallbackForwarder)
    3245                 : 
    3246                 :   // nsIAsyncVerifyRedirectCallback implementation
    3247               0 :   NS_IMETHOD OnRedirectVerifyCallback(nsresult result)
    3248                 :   {
    3249               0 :     mXHR->OnRedirectVerifyCallback(result);
    3250                 : 
    3251               0 :     return NS_OK;
    3252                 :   }
    3253                 : 
    3254                 : private:
    3255                 :   nsRefPtr<nsXMLHttpRequest> mXHR;
    3256                 : };
    3257                 : 
    3258            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(AsyncVerifyRedirectCallbackForwarder)
    3259                 : 
    3260               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AsyncVerifyRedirectCallbackForwarder)
    3261               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mXHR, nsIXMLHttpRequest)
    3262               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    3263                 : 
    3264               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AsyncVerifyRedirectCallbackForwarder)
    3265               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mXHR)
    3266               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    3267                 : 
    3268               0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AsyncVerifyRedirectCallbackForwarder)
    3269               0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
    3270               0 :   NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
    3271               0 : NS_INTERFACE_MAP_END
    3272                 : 
    3273               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(AsyncVerifyRedirectCallbackForwarder)
    3274               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(AsyncVerifyRedirectCallbackForwarder)
    3275                 : 
    3276                 : 
    3277                 : /////////////////////////////////////////////////////
    3278                 : // nsIChannelEventSink methods:
    3279                 : //
    3280                 : NS_IMETHODIMP
    3281              35 : nsXMLHttpRequest::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
    3282                 :                                          nsIChannel *aNewChannel,
    3283                 :                                          PRUint32    aFlags,
    3284                 :                                          nsIAsyncVerifyRedirectCallback *callback)
    3285                 : {
    3286              35 :   NS_PRECONDITION(aNewChannel, "Redirect without a channel?");
    3287                 : 
    3288                 :   nsresult rv;
    3289                 : 
    3290              35 :   if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags)) {
    3291              35 :     rv = CheckChannelForCrossSiteRequest(aNewChannel);
    3292              35 :     if (NS_FAILED(rv)) {
    3293                 :       NS_WARNING("nsXMLHttpRequest::OnChannelRedirect: "
    3294               0 :                  "CheckChannelForCrossSiteRequest returned failure");
    3295               0 :       return rv;
    3296                 :     }
    3297                 : 
    3298                 :     // Disable redirects for preflighted cross-site requests entirely for now
    3299                 :     // Note, do this after the call to CheckChannelForCrossSiteRequest
    3300                 :     // to make sure that XML_HTTP_REQUEST_USE_XSITE_AC is up-to-date
    3301              35 :     if ((mState & XML_HTTP_REQUEST_NEED_AC_PREFLIGHT)) {
    3302               0 :        return NS_ERROR_DOM_BAD_URI;
    3303                 :     }
    3304                 :   }
    3305                 : 
    3306                 :   // Prepare to receive callback
    3307              35 :   mRedirectCallback = callback;
    3308              35 :   mNewRedirectChannel = aNewChannel;
    3309                 : 
    3310              35 :   if (mChannelEventSink) {
    3311                 :     nsRefPtr<AsyncVerifyRedirectCallbackForwarder> fwd =
    3312               0 :       new AsyncVerifyRedirectCallbackForwarder(this);
    3313                 : 
    3314               0 :     rv = mChannelEventSink->AsyncOnChannelRedirect(aOldChannel,
    3315                 :                                                    aNewChannel,
    3316               0 :                                                    aFlags, fwd);
    3317               0 :     if (NS_FAILED(rv)) {
    3318               0 :         mRedirectCallback = nsnull;
    3319               0 :         mNewRedirectChannel = nsnull;
    3320                 :     }
    3321               0 :     return rv;
    3322                 :   }
    3323              35 :   OnRedirectVerifyCallback(NS_OK);
    3324              35 :   return NS_OK;
    3325                 : }
    3326                 : 
    3327                 : void
    3328              35 : nsXMLHttpRequest::OnRedirectVerifyCallback(nsresult result)
    3329                 : {
    3330              35 :   NS_ASSERTION(mRedirectCallback, "mRedirectCallback not set in callback");
    3331              35 :   NS_ASSERTION(mNewRedirectChannel, "mNewRedirectChannel not set in callback");
    3332                 : 
    3333              35 :   if (NS_SUCCEEDED(result)) {
    3334              35 :     mChannel = mNewRedirectChannel;
    3335                 : 
    3336              70 :     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
    3337              35 :     if (httpChannel) {
    3338                 :       // Ensure all original headers are duplicated for the new channel (bug #553888)
    3339              71 :       for (PRUint32 i = mModifiedRequestHeaders.Length(); i > 0; ) {
    3340               1 :         --i;
    3341               2 :         httpChannel->SetRequestHeader(mModifiedRequestHeaders[i].header,
    3342               1 :                                       mModifiedRequestHeaders[i].value,
    3343               3 :                                       false);
    3344                 :       }
    3345                 :     }
    3346                 :   } else {
    3347               0 :     mErrorLoad = true;
    3348                 :   }
    3349                 : 
    3350              35 :   mNewRedirectChannel = nsnull;
    3351                 : 
    3352              35 :   mRedirectCallback->OnRedirectVerifyCallback(result);
    3353              35 :   mRedirectCallback = nsnull;
    3354              35 : }
    3355                 : 
    3356                 : /////////////////////////////////////////////////////
    3357                 : // nsIProgressEventSink methods:
    3358                 : //
    3359                 : 
    3360                 : void
    3361            1153 : nsXMLHttpRequest::MaybeDispatchProgressEvents(bool aFinalProgress)
    3362                 : {
    3363            1153 :   if (aFinalProgress && mProgressTimerIsActive) {
    3364             416 :     mProgressTimerIsActive = false;
    3365             416 :     mProgressNotifier->Cancel();
    3366                 :   }
    3367                 : 
    3368            2710 :   if (mProgressTimerIsActive ||
    3369            1015 :       !mProgressSinceLastProgressEvent ||
    3370                 :       mErrorLoad ||
    3371             542 :       !(mState & XML_HTTP_REQUEST_ASYNC)) {
    3372             631 :     return;
    3373                 :   }
    3374                 : 
    3375             522 :   if (!aFinalProgress) {
    3376             420 :     StartProgressEventTimer();
    3377                 :   }
    3378                 : 
    3379                 :   // We're uploading if our state is XML_HTTP_REQUEST_OPENED or
    3380                 :   // XML_HTTP_REQUEST_SENT
    3381             522 :   if ((XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT) & mState) {
    3382               0 :     if (aFinalProgress) {
    3383               0 :       mUploadTotal = mUploadTransferred;
    3384               0 :       mUploadProgressMax = mUploadProgress;
    3385               0 :       mUploadLengthComputable = true;
    3386                 :     }
    3387               0 :     DispatchProgressEvent(this, NS_LITERAL_STRING(UPLOADPROGRESS_STR),
    3388                 :                           true, mUploadLengthComputable, mUploadTransferred,
    3389                 :                           mUploadTotal, mUploadProgress,
    3390               0 :                           mUploadProgressMax);
    3391               0 :     if (mUpload && !mUploadComplete) {
    3392               0 :       DispatchProgressEvent(mUpload, NS_LITERAL_STRING(PROGRESS_STR),
    3393                 :                             true, mUploadLengthComputable, mUploadTransferred,
    3394                 :                             mUploadTotal, mUploadProgress,
    3395               0 :                             mUploadProgressMax);
    3396                 :     }
    3397                 :   } else {
    3398             522 :     if (aFinalProgress) {
    3399             102 :       mLoadTotal = mLoadTransferred;
    3400             102 :       mLoadLengthComputable = true;
    3401                 :     }
    3402             522 :     mInLoadProgressEvent = true;
    3403             522 :     DispatchProgressEvent(this, NS_LITERAL_STRING(PROGRESS_STR),
    3404                 :                           true, mLoadLengthComputable, mLoadTransferred,
    3405             522 :                           mLoadTotal, mLoadTransferred, mLoadTotal);
    3406             522 :     mInLoadProgressEvent = false;
    3407             522 :     if (mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT ||
    3408                 :         mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER) {
    3409               0 :       mResponseBody.Truncate();
    3410               0 :       mResponseText.Truncate();
    3411               0 :       mResultArrayBuffer = nsnull;
    3412                 :     }
    3413                 :   }
    3414                 : 
    3415             522 :   mProgressSinceLastProgressEvent = false;
    3416                 : }
    3417                 : 
    3418                 : NS_IMETHODIMP
    3419               1 : nsXMLHttpRequest::OnProgress(nsIRequest *aRequest, nsISupports *aContext, PRUint64 aProgress, PRUint64 aProgressMax)
    3420                 : {
    3421                 :   // We're in middle of processing multipart headers and we don't want to report
    3422                 :   // any progress because upload's 'load' is dispatched when we start to load
    3423                 :   // the first response.
    3424               1 :   if (XML_HTTP_REQUEST_MPART_HEADERS & mState) {
    3425               0 :     return NS_OK;
    3426                 :   }
    3427                 : 
    3428                 :   // We're uploading if our state is XML_HTTP_REQUEST_OPENED or
    3429                 :   // XML_HTTP_REQUEST_SENT
    3430               1 :   bool upload = !!((XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT) & mState);
    3431                 :   // When uploading, OnProgress reports also headers in aProgress and aProgressMax.
    3432                 :   // So, try to remove the headers, if possible.
    3433               1 :   bool lengthComputable = (aProgressMax != LL_MAXUINT);
    3434               1 :   if (upload) {
    3435               0 :     PRUint64 loaded = aProgress;
    3436               0 :     PRUint64 total = aProgressMax;
    3437               0 :     if (lengthComputable) {
    3438               0 :       PRUint64 headerSize = aProgressMax - mUploadTotal;
    3439               0 :       loaded -= headerSize;
    3440               0 :       total -= headerSize;
    3441                 :     }
    3442               0 :     mUploadLengthComputable = lengthComputable;
    3443               0 :     mUploadTransferred = loaded;
    3444               0 :     mUploadProgress = aProgress;
    3445               0 :     mUploadProgressMax = aProgressMax;
    3446               0 :     mProgressSinceLastProgressEvent = true;
    3447                 : 
    3448               0 :     MaybeDispatchProgressEvents(false);
    3449                 :   } else {
    3450               1 :     mLoadLengthComputable = lengthComputable;
    3451               1 :     mLoadTotal = lengthComputable ? aProgressMax : 0;
    3452                 :     
    3453                 :     // Don't dispatch progress events here. OnDataAvailable will take care
    3454                 :     // of that.
    3455                 :   }
    3456                 : 
    3457               1 :   if (mProgressEventSink) {
    3458               0 :     mProgressEventSink->OnProgress(aRequest, aContext, aProgress,
    3459               0 :                                    aProgressMax);
    3460                 :   }
    3461                 : 
    3462               1 :   return NS_OK;
    3463                 : }
    3464                 : 
    3465                 : NS_IMETHODIMP
    3466               4 : nsXMLHttpRequest::OnStatus(nsIRequest *aRequest, nsISupports *aContext, nsresult aStatus, const PRUnichar *aStatusArg)
    3467                 : {
    3468               4 :   if (mProgressEventSink) {
    3469               0 :     mProgressEventSink->OnStatus(aRequest, aContext, aStatus, aStatusArg);
    3470                 :   }
    3471                 : 
    3472               4 :   return NS_OK;
    3473                 : }
    3474                 : 
    3475                 : bool
    3476            2255 : nsXMLHttpRequest::AllowUploadProgress()
    3477                 : {
    3478            2255 :   return !(mState & XML_HTTP_REQUEST_USE_XSITE_AC) ||
    3479            2255 :     (mState & XML_HTTP_REQUEST_NEED_AC_PREFLIGHT);
    3480                 : }
    3481                 : 
    3482                 : /////////////////////////////////////////////////////
    3483                 : // nsIInterfaceRequestor methods:
    3484                 : //
    3485                 : NS_IMETHODIMP
    3486            1324 : nsXMLHttpRequest::GetInterface(const nsIID & aIID, void **aResult)
    3487                 : {
    3488                 :   nsresult rv;
    3489                 : 
    3490                 :   // Make sure to return ourselves for the channel event sink interface and
    3491                 :   // progress event sink interface, no matter what.  We can forward these to
    3492                 :   // mNotificationCallbacks if it wants to get notifications for them.  But we
    3493                 :   // need to see these notifications for proper functioning.
    3494            1324 :   if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
    3495              35 :     mChannelEventSink = do_GetInterface(mNotificationCallbacks);
    3496              35 :     *aResult = static_cast<nsIChannelEventSink*>(this);
    3497              35 :     NS_ADDREF_THIS();
    3498              35 :     return NS_OK;
    3499            1289 :   } else if (aIID.Equals(NS_GET_IID(nsIProgressEventSink))) {
    3500             615 :     mProgressEventSink = do_GetInterface(mNotificationCallbacks);
    3501             615 :     *aResult = static_cast<nsIProgressEventSink*>(this);
    3502             615 :     NS_ADDREF_THIS();
    3503             615 :     return NS_OK;
    3504                 :   }
    3505                 : 
    3506                 :   // Now give mNotificationCallbacks (if non-null) a chance to return the
    3507                 :   // desired interface.
    3508             674 :   if (mNotificationCallbacks) {
    3509             448 :     rv = mNotificationCallbacks->GetInterface(aIID, aResult);
    3510             448 :     if (NS_SUCCEEDED(rv)) {
    3511               0 :       NS_ASSERTION(*aResult, "Lying nsIInterfaceRequestor implementation!");
    3512               0 :       return rv;
    3513                 :     }
    3514                 :   }
    3515                 : 
    3516             674 :   if (mState & XML_HTTP_REQUEST_BACKGROUND) {
    3517             182 :     nsCOMPtr<nsIInterfaceRequestor> badCertHandler(do_CreateInstance(NS_BADCERTHANDLER_CONTRACTID, &rv));
    3518                 : 
    3519                 :     // Ignore failure to get component, we may not have all its dependencies
    3520                 :     // available
    3521              91 :     if (NS_SUCCEEDED(rv)) {
    3522              91 :       rv = badCertHandler->GetInterface(aIID, aResult);
    3523              91 :       if (NS_SUCCEEDED(rv))
    3524               0 :         return rv;
    3525                 :     }
    3526                 :   }
    3527            1166 :   else if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
    3528             583 :            aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
    3529                 :     nsCOMPtr<nsIPromptFactory> wwatch =
    3530               0 :       do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
    3531               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3532                 : 
    3533                 :     // Get the an auth prompter for our window so that the parenting
    3534                 :     // of the dialogs works as it should when using tabs.
    3535                 : 
    3536               0 :     nsCOMPtr<nsIDOMWindow> window;
    3537               0 :     if (GetOwner()) {
    3538               0 :       window = GetOwner()->GetOuterWindow();
    3539                 :     }
    3540                 : 
    3541               0 :     return wwatch->GetPrompt(window, aIID,
    3542               0 :                              reinterpret_cast<void**>(aResult));
    3543                 : 
    3544                 :   }
    3545                 : 
    3546             674 :   return QueryInterface(aIID, aResult);
    3547                 : }
    3548                 : 
    3549                 : NS_IMETHODIMP
    3550               0 : nsXMLHttpRequest::GetUpload(nsIXMLHttpRequestUpload** aUpload)
    3551                 : {
    3552               0 :   *aUpload = nsnull;
    3553                 : 
    3554                 :   nsresult rv;
    3555                 :   nsIScriptContext* scriptContext =
    3556               0 :     GetContextForEventHandlers(&rv);
    3557               0 :   NS_ENSURE_SUCCESS(rv, rv);
    3558               0 :   if (!mUpload) {
    3559               0 :     mUpload = new nsXMLHttpRequestUpload(this);
    3560               0 :     NS_ENSURE_TRUE(mUpload, NS_ERROR_OUT_OF_MEMORY);
    3561                 :   }
    3562               0 :   NS_ADDREF(*aUpload = mUpload);
    3563               0 :   return NS_OK;
    3564                 : }
    3565                 : 
    3566                 : void
    3567               0 : nsXMLHttpRequest::HandleTimeoutCallback()
    3568                 : {
    3569               0 :   if (mState & XML_HTTP_REQUEST_DONE) {
    3570               0 :     NS_NOTREACHED("nsXMLHttpRequest::HandleTimeoutCallback with completed request");
    3571                 :     // do nothing!
    3572               0 :     return;
    3573                 :   }
    3574                 : 
    3575               0 :   CloseRequestWithError(NS_LITERAL_STRING(TIMEOUT_STR),
    3576               0 :                         XML_HTTP_REQUEST_TIMED_OUT);
    3577                 : }
    3578                 : 
    3579                 : NS_IMETHODIMP
    3580               4 : nsXMLHttpRequest::Notify(nsITimer* aTimer)
    3581                 : {
    3582               4 :   if (mProgressNotifier == aTimer) {
    3583               4 :     HandleProgressTimerCallback();
    3584               4 :     return NS_OK;
    3585                 :   }
    3586                 : 
    3587               0 :   if (mTimeoutTimer == aTimer) {
    3588               0 :     HandleTimeoutCallback();
    3589               0 :     return NS_OK;
    3590                 :   }
    3591                 : 
    3592                 :   // Just in case some JS user wants to QI to nsITimerCallback and play with us...
    3593               0 :   NS_WARNING("Unexpected timer!");
    3594               0 :   return NS_ERROR_INVALID_POINTER;
    3595                 : }
    3596                 : 
    3597                 : void
    3598               4 : nsXMLHttpRequest::HandleProgressTimerCallback()
    3599                 : {
    3600               4 :   mProgressTimerIsActive = false;
    3601               4 :   if (!(XML_HTTP_REQUEST_MPART_HEADERS & mState)) {
    3602               4 :     MaybeDispatchProgressEvents(false);
    3603                 :   }
    3604               4 : }
    3605                 : 
    3606                 : void
    3607             420 : nsXMLHttpRequest::StartProgressEventTimer()
    3608                 : {
    3609             420 :   if (!mProgressNotifier) {
    3610             416 :     mProgressNotifier = do_CreateInstance(NS_TIMER_CONTRACTID);
    3611                 :   }
    3612             420 :   if (mProgressNotifier) {
    3613             420 :     mProgressEventWasDelayed = false;
    3614             420 :     mProgressTimerIsActive = true;
    3615             420 :     mProgressNotifier->Cancel();
    3616             420 :     mProgressNotifier->InitWithCallback(this, NS_PROGRESS_EVENT_INTERVAL,
    3617             420 :                                         nsITimer::TYPE_ONE_SHOT);
    3618                 :   }
    3619             420 : }
    3620                 : 
    3621               0 : NS_IMPL_ISUPPORTS1(nsXMLHttpRequest::nsHeaderVisitor, nsIHttpHeaderVisitor)
    3622                 : 
    3623               0 : NS_IMETHODIMP nsXMLHttpRequest::
    3624                 : nsHeaderVisitor::VisitHeader(const nsACString &header, const nsACString &value)
    3625                 : {
    3626                 :     // See bug #380418. Hide "Set-Cookie" headers from non-chrome scripts.
    3627               0 :     bool chrome = false; // default to false in case IsCapabilityEnabled fails
    3628               0 :     IsCapabilityEnabled("UniversalXPConnect", &chrome);
    3629               0 :     if (!chrome &&
    3630               0 :          (header.LowerCaseEqualsASCII("set-cookie") ||
    3631               0 :           header.LowerCaseEqualsASCII("set-cookie2"))) {
    3632               0 :         NS_WARNING("blocked access to response header");
    3633                 :     } else {
    3634               0 :         mHeaders.Append(header);
    3635               0 :         mHeaders.Append(": ");
    3636               0 :         mHeaders.Append(value);
    3637               0 :         mHeaders.Append('\n');
    3638                 :     }
    3639               0 :     return NS_OK;
    3640                 : }
    3641                 : 
    3642                 : // DOM event class to handle progress notifications
    3643             522 : nsXMLHttpProgressEvent::nsXMLHttpProgressEvent(nsIDOMProgressEvent* aInner,
    3644                 :                                                PRUint64 aCurrentProgress,
    3645                 :                                                PRUint64 aMaxProgress,
    3646                 :                                                nsPIDOMWindow* aWindow)
    3647             522 :   : mWindow(aWindow)
    3648                 : {
    3649             522 :   mInner = static_cast<nsDOMProgressEvent*>(aInner);
    3650             522 :   mCurProgress = aCurrentProgress;
    3651             522 :   mMaxProgress = aMaxProgress;
    3652             522 : }
    3653                 : 
    3654            1044 : nsXMLHttpProgressEvent::~nsXMLHttpProgressEvent()
    3655            2088 : {}
    3656                 : 
    3657            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLHttpProgressEvent)
    3658                 : 
    3659                 : DOMCI_DATA(XMLHttpProgressEvent, nsXMLHttpProgressEvent)
    3660                 : 
    3661                 : // QueryInterface implementation for nsXMLHttpProgressEvent
    3662            4698 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXMLHttpProgressEvent)
    3663            2610 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMProgressEvent)
    3664            2610 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEvent, nsIDOMProgressEvent)
    3665            2088 :   NS_INTERFACE_MAP_ENTRY(nsIDOMNSEvent)
    3666            1566 :   NS_INTERFACE_MAP_ENTRY(nsIPrivateDOMEvent)
    3667             522 :   NS_INTERFACE_MAP_ENTRY(nsIDOMProgressEvent)
    3668               0 :   NS_INTERFACE_MAP_ENTRY(nsIDOMLSProgressEvent)
    3669               0 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XMLHttpProgressEvent)
    3670               0 : NS_INTERFACE_MAP_END
    3671                 : 
    3672            3654 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXMLHttpProgressEvent)
    3673            3654 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXMLHttpProgressEvent)
    3674                 : 
    3675               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXMLHttpProgressEvent)
    3676               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mInner);
    3677               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mWindow);
    3678               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    3679                 : 
    3680               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXMLHttpProgressEvent)
    3681               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mInner,
    3682                 :                                                        nsIDOMProgressEvent)
    3683               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mWindow);
    3684               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    3685                 : 
    3686               0 : NS_IMETHODIMP nsXMLHttpProgressEvent::GetInput(nsIDOMLSInput * *aInput)
    3687                 : {
    3688               0 :   *aInput = nsnull;
    3689               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    3690                 : }
    3691                 : 
    3692                 : void
    3693               0 : nsXMLHttpProgressEvent::WarnAboutLSProgressEvent(nsIDocument::DeprecatedOperations aOperation)
    3694                 : {
    3695               0 :   if (!mWindow) {
    3696               0 :     return;
    3697                 :   }
    3698                 :   nsCOMPtr<nsIDocument> document =
    3699               0 :     do_QueryInterface(mWindow->GetExtantDocument());
    3700               0 :   if (!document) {
    3701                 :     return;
    3702                 :   }
    3703               0 :   document->WarnOnceAbout(aOperation);
    3704                 : }
    3705                 : 
    3706               0 : NS_IMETHODIMP nsXMLHttpProgressEvent::GetPosition(PRUint32 *aPosition)
    3707                 : {
    3708               0 :   WarnAboutLSProgressEvent(nsIDocument::ePosition);
    3709                 :   // XXX can we change the iface?
    3710               0 :   LL_L2UI(*aPosition, mCurProgress);
    3711               0 :   return NS_OK;
    3712                 : }
    3713                 : 
    3714               0 : NS_IMETHODIMP nsXMLHttpProgressEvent::GetTotalSize(PRUint32 *aTotalSize)
    3715                 : {
    3716               0 :   WarnAboutLSProgressEvent(nsIDocument::eTotalSize);
    3717                 :   // XXX can we change the iface?
    3718               0 :   LL_L2UI(*aTotalSize, mMaxProgress);
    3719               0 :   return NS_OK;
    3720            4392 : }

Generated by: LCOV version 1.7