LCOV - code coverage report
Current view: directory - content/base/src - nsEventSource.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 823 4 0.5 %
Date: 2012-06-02 Functions: 71 3 4.2 %

       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                 :  * Wellington Fernando de Macedo and Clayton Williams.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2008
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *    Wellington Fernando de Macedo <wfernandom2004@gmail.com>
      24                 :  *    Clayton Williams <claytonw@mit.edu>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #include "mozilla/Util.h"
      41                 : 
      42                 : #include "nsEventSource.h"
      43                 : #include "nsNetUtil.h"
      44                 : #include "nsMimeTypes.h"
      45                 : #include "nsDOMMessageEvent.h"
      46                 : #include "nsIJSContextStack.h"
      47                 : #include "nsIPromptFactory.h"
      48                 : #include "nsIWindowWatcher.h"
      49                 : #include "nsPresContext.h"
      50                 : #include "nsContentPolicyUtils.h"
      51                 : #include "nsIStringBundle.h"
      52                 : #include "nsIConsoleService.h"
      53                 : #include "nsIObserverService.h"
      54                 : #include "nsIScriptObjectPrincipal.h"
      55                 : #include "jsdbgapi.h"
      56                 : #include "nsJSUtils.h"
      57                 : #include "nsIAsyncVerifyRedirectCallback.h"
      58                 : #include "nsIScriptError.h"
      59                 : #include "nsICharsetConverterManager.h"
      60                 : #include "nsIChannelPolicy.h"
      61                 : #include "nsIContentSecurityPolicy.h"
      62                 : #include "nsContentUtils.h"
      63                 : #include "mozilla/Preferences.h"
      64                 : #include "xpcpublic.h"
      65                 : #include "nsCrossSiteListenerProxy.h"
      66                 : #include "nsWrapperCacheInlines.h"
      67                 : #include "nsDOMEventTargetHelper.h"
      68                 : 
      69                 : using namespace mozilla;
      70                 : 
      71                 : #define REPLACEMENT_CHAR     (PRUnichar)0xFFFD
      72                 : #define BOM_CHAR             (PRUnichar)0xFEFF
      73                 : #define SPACE_CHAR           (PRUnichar)0x0020
      74                 : #define CR_CHAR              (PRUnichar)0x000D
      75                 : #define LF_CHAR              (PRUnichar)0x000A
      76                 : #define COLON_CHAR           (PRUnichar)0x003A
      77                 : 
      78                 : #define DEFAULT_BUFFER_SIZE 4096
      79                 : 
      80                 : // Reconnection time related values in milliseconds. The default one is equal
      81                 : // to the default value of the pref dom.server-events.default-reconnection-time
      82                 : #define MIN_RECONNECTION_TIME_VALUE       500
      83                 : #define DEFAULT_RECONNECTION_TIME_VALUE   5000
      84                 : #define MAX_RECONNECTION_TIME_VALUE       PR_IntervalToMilliseconds(DELAY_INTERVAL_LIMIT)
      85                 : 
      86               0 : nsEventSource::nsEventSource() :
      87                 :   mStatus(PARSE_STATE_OFF),
      88                 :   mFrozen(false),
      89                 :   mErrorLoadOnRedirect(false),
      90                 :   mGoingToDispatchAllMessages(false),
      91                 :   mWithCredentials(false),
      92                 :   mWaitingForOnStopRequest(false),
      93                 :   mLastConvertionResult(NS_OK),
      94                 :   mReadyState(nsIEventSource::CONNECTING),
      95                 :   mScriptLine(0),
      96               0 :   mInnerWindowID(0)
      97                 : {
      98               0 : }
      99                 : 
     100               0 : nsEventSource::~nsEventSource()
     101                 : {
     102               0 :   Close();
     103               0 : }
     104                 : 
     105                 : //-----------------------------------------------------------------------------
     106                 : // nsEventSource::nsISupports
     107                 : //-----------------------------------------------------------------------------
     108                 : 
     109            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsEventSource)
     110                 : 
     111               0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsEventSource)
     112               0 :   bool isBlack = tmp->IsBlack();
     113               0 :   if (isBlack || tmp->mWaitingForOnStopRequest) {
     114               0 :     if (tmp->mListenerManager) {
     115               0 :       tmp->mListenerManager->UnmarkGrayJSListeners();
     116               0 :       NS_UNMARK_LISTENER_WRAPPER(Open)
     117               0 :       NS_UNMARK_LISTENER_WRAPPER(Message)
     118               0 :       NS_UNMARK_LISTENER_WRAPPER(Error)
     119                 :     }
     120               0 :     if (!isBlack) {
     121               0 :       xpc_UnmarkGrayObject(tmp->PreservingWrapper() ? 
     122               0 :                            tmp->GetWrapperPreserveColor() :
     123               0 :                            tmp->GetExpandoObjectPreserveColor());
     124                 :     }
     125               0 :     return true;
     126                 :   }
     127               0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
     128                 : 
     129               0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsEventSource)
     130               0 :   return tmp->IsBlack();
     131                 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
     132                 : 
     133               0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsEventSource)
     134               0 :   return tmp->IsBlack();
     135                 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
     136                 : 
     137               0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsEventSource,
     138                 :                                                nsDOMEventTargetHelper)
     139               0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
     140                 : 
     141               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsEventSource,
     142                 :                                                   nsDOMEventTargetHelper)
     143               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSrc)
     144               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNotificationCallbacks)
     145               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLoadGroup)
     146               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannelEventSink)
     147               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mHttpChannel)
     148               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTimer)
     149               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnOpenListener)
     150               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnMessageListener)
     151               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnErrorListener)
     152               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mUnicodeDecoder)
     153               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     154                 : 
     155               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsEventSource, nsDOMEventTargetHelper)
     156               0 :   tmp->Close();
     157               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnOpenListener)
     158               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnMessageListener)
     159               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnErrorListener)
     160               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     161                 : 
     162                 : DOMCI_DATA(EventSource, nsEventSource)
     163                 : 
     164               0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsEventSource)
     165               0 :   NS_INTERFACE_MAP_ENTRY(nsIEventSource)
     166               0 :   NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
     167               0 :   NS_INTERFACE_MAP_ENTRY(nsIObserver)
     168               0 :   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
     169               0 :   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
     170               0 :   NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
     171               0 :   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
     172               0 :   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     173               0 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(EventSource)
     174               0 : NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
     175                 : 
     176               0 : NS_IMPL_ADDREF_INHERITED(nsEventSource, nsDOMEventTargetHelper)
     177               0 : NS_IMPL_RELEASE_INHERITED(nsEventSource, nsDOMEventTargetHelper)
     178                 : 
     179                 : void
     180               0 : nsEventSource::DisconnectFromOwner()
     181                 : {
     182               0 :   nsDOMEventTargetHelper::DisconnectFromOwner();
     183               0 :   NS_DISCONNECT_EVENT_HANDLER(Open)
     184               0 :   NS_DISCONNECT_EVENT_HANDLER(Message)
     185               0 :   NS_DISCONNECT_EVENT_HANDLER(Error)
     186               0 :   Close();
     187               0 : }
     188                 : 
     189                 : //-----------------------------------------------------------------------------
     190                 : // nsEventSource::nsIEventSource
     191                 : //-----------------------------------------------------------------------------
     192                 : 
     193                 : NS_IMETHODIMP
     194               0 : nsEventSource::GetUrl(nsAString& aURL)
     195                 : {
     196               0 :   aURL = mOriginalURL;
     197               0 :   return NS_OK;
     198                 : }
     199                 : 
     200                 : NS_IMETHODIMP
     201               0 : nsEventSource::GetReadyState(PRInt32 *aReadyState)
     202                 : {
     203               0 :   NS_ENSURE_ARG_POINTER(aReadyState);
     204               0 :   *aReadyState = mReadyState;
     205               0 :   return NS_OK;
     206                 : }
     207                 : 
     208                 : NS_IMETHODIMP
     209               0 : nsEventSource::GetWithCredentials(bool *aWithCredentials)
     210                 : {
     211               0 :   NS_ENSURE_ARG_POINTER(aWithCredentials);
     212               0 :   *aWithCredentials = mWithCredentials;
     213               0 :   return NS_OK;
     214                 : }
     215                 : 
     216                 : #define NS_EVENTSRC_IMPL_DOMEVENTLISTENER(_eventlistenername, _eventlistener)  \
     217                 :   NS_IMETHODIMP                                                                \
     218                 :   nsEventSource::GetOn##_eventlistenername(nsIDOMEventListener * *aListener)   \
     219                 :   {                                                                            \
     220                 :     return GetInnerEventListener(_eventlistener, aListener);                   \
     221                 :   }                                                                            \
     222                 :                                                                                \
     223                 :   NS_IMETHODIMP                                                                \
     224                 :   nsEventSource::SetOn##_eventlistenername(nsIDOMEventListener * aListener)    \
     225                 :   {                                                                            \
     226                 :     return RemoveAddEventListener(NS_LITERAL_STRING(#_eventlistenername),      \
     227                 :                                   _eventlistener, aListener);                  \
     228                 :   }
     229                 : 
     230               0 : NS_EVENTSRC_IMPL_DOMEVENTLISTENER(open, mOnOpenListener)
     231               0 : NS_EVENTSRC_IMPL_DOMEVENTLISTENER(error, mOnErrorListener)
     232               0 : NS_EVENTSRC_IMPL_DOMEVENTLISTENER(message, mOnMessageListener)
     233                 : 
     234                 : NS_IMETHODIMP
     235               0 : nsEventSource::Close()
     236                 : {
     237               0 :   if (mReadyState == nsIEventSource::CLOSED) {
     238               0 :     return NS_OK;
     239                 :   }
     240                 : 
     241               0 :   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
     242               0 :   if (os) {
     243               0 :     os->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
     244               0 :     os->RemoveObserver(this, DOM_WINDOW_FROZEN_TOPIC);
     245               0 :     os->RemoveObserver(this, DOM_WINDOW_THAWED_TOPIC);
     246                 :   }
     247                 : 
     248               0 :   if (mTimer) {
     249               0 :     mTimer->Cancel();
     250               0 :     mTimer = nsnull;
     251                 :   }
     252                 : 
     253               0 :   ResetConnection();
     254                 : 
     255               0 :   ClearFields();
     256                 : 
     257               0 :   while (mMessagesToDispatch.GetSize() != 0) {
     258               0 :     delete static_cast<Message*>(mMessagesToDispatch.PopFront());
     259                 :   }
     260                 : 
     261               0 :   mSrc = nsnull;
     262               0 :   mFrozen = false;
     263                 : 
     264               0 :   mUnicodeDecoder = nsnull;
     265                 : 
     266               0 :   mReadyState = nsIEventSource::CLOSED;
     267                 : 
     268               0 :   return NS_OK;
     269                 : }
     270                 : 
     271                 : /**
     272                 :  * This Init method should only be called by C++ consumers.
     273                 :  */
     274                 : NS_IMETHODIMP
     275               0 : nsEventSource::Init(nsIPrincipal* aPrincipal,
     276                 :                     nsIScriptContext* aScriptContext,
     277                 :                     nsPIDOMWindow* aOwnerWindow,
     278                 :                     const nsAString& aURL,
     279                 :                     bool aWithCredentials)
     280                 : {
     281               0 :   NS_ENSURE_ARG(aPrincipal);
     282                 : 
     283               0 :   if (mReadyState != nsIEventSource::CONNECTING || !PrefEnabled()) {
     284               0 :     return NS_ERROR_DOM_SECURITY_ERR;
     285                 :   }
     286                 : 
     287               0 :   mPrincipal = aPrincipal;
     288               0 :   mWithCredentials = aWithCredentials;
     289               0 :   if (aOwnerWindow) {
     290               0 :     BindToOwner(aOwnerWindow->IsOuterWindow() ?
     291               0 :       aOwnerWindow->GetCurrentInnerWindow() : aOwnerWindow);
     292                 :   } else {
     293               0 :     BindToOwner(aOwnerWindow);
     294                 :   }
     295                 : 
     296                 :   nsCOMPtr<nsIJSContextStack> stack =
     297               0 :     do_GetService("@mozilla.org/js/xpc/ContextStack;1");
     298               0 :   JSContext* cx = nsnull;
     299               0 :   if (stack && NS_SUCCEEDED(stack->Peek(&cx)) && cx) {
     300                 :     const char *filename;
     301               0 :     if (nsJSUtils::GetCallingLocation(cx, &filename, &mScriptLine)) {
     302               0 :       mScriptFile.AssignASCII(filename);
     303                 :     }
     304                 : 
     305               0 :     mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx);
     306                 :   }
     307                 : 
     308                 :   // Get the load group for the page. When requesting we'll add ourselves to it.
     309                 :   // This way any pending requests will be automatically aborted if the user
     310                 :   // leaves the page.
     311                 :   nsresult rv;
     312               0 :   nsIScriptContext* sc = GetContextForEventHandlers(&rv);
     313               0 :   if (sc) {
     314                 :     nsCOMPtr<nsIDocument> doc =
     315               0 :       nsContentUtils::GetDocumentFromScriptContext(sc);
     316               0 :     if (doc) {
     317               0 :       mLoadGroup = doc->GetDocumentLoadGroup();
     318                 :     }
     319                 :   }
     320                 : 
     321                 :   // get the src
     322               0 :   nsCOMPtr<nsIURI> baseURI;
     323               0 :   rv = GetBaseURI(getter_AddRefs(baseURI));
     324               0 :   NS_ENSURE_SUCCESS(rv, rv);
     325                 : 
     326               0 :   nsCOMPtr<nsIURI> srcURI;
     327               0 :   rv = NS_NewURI(getter_AddRefs(srcURI), aURL, nsnull, baseURI);
     328               0 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SYNTAX_ERR);
     329                 : 
     330                 :   // we observe when the window freezes and thaws
     331               0 :   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
     332               0 :   NS_ENSURE_STATE(os);
     333                 : 
     334               0 :   rv = os->AddObserver(this, DOM_WINDOW_DESTROYED_TOPIC, true);
     335               0 :   NS_ENSURE_SUCCESS(rv, rv);
     336               0 :   rv = os->AddObserver(this, DOM_WINDOW_FROZEN_TOPIC, true);
     337               0 :   NS_ENSURE_SUCCESS(rv, rv);
     338               0 :   rv = os->AddObserver(this, DOM_WINDOW_THAWED_TOPIC, true);
     339               0 :   NS_ENSURE_SUCCESS(rv, rv);
     340                 : 
     341               0 :   nsAutoString origin;
     342               0 :   rv = nsContentUtils::GetUTFOrigin(srcURI, origin);
     343               0 :   NS_ENSURE_SUCCESS(rv, rv);
     344                 : 
     345               0 :   nsCAutoString spec;
     346               0 :   rv = srcURI->GetSpec(spec);
     347               0 :   NS_ENSURE_SUCCESS(rv, rv);
     348                 : 
     349               0 :   mOriginalURL = NS_ConvertUTF8toUTF16(spec);
     350               0 :   mSrc = srcURI;
     351               0 :   mOrigin = origin;
     352                 : 
     353                 :   mReconnectionTime =
     354                 :     Preferences::GetInt("dom.server-events.default-reconnection-time",
     355               0 :                         DEFAULT_RECONNECTION_TIME_VALUE);
     356                 : 
     357                 :   nsCOMPtr<nsICharsetConverterManager> convManager =
     358               0 :     do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
     359               0 :   NS_ENSURE_SUCCESS(rv, rv);
     360                 : 
     361               0 :   rv = convManager->GetUnicodeDecoder("UTF-8", getter_AddRefs(mUnicodeDecoder));
     362               0 :   NS_ENSURE_SUCCESS(rv, rv);
     363               0 :   mUnicodeDecoder->SetInputErrorBehavior(nsIUnicodeDecoder::kOnError_Recover);
     364                 : 
     365                 :   // the constructor should throw a SYNTAX_ERROR only if it fails resolving the
     366                 :   // url parameter, so we don't care about the InitChannelAndRequestEventSource
     367                 :   // result.
     368               0 :   InitChannelAndRequestEventSource();
     369                 : 
     370               0 :   return NS_OK;
     371                 : }
     372                 : 
     373                 : //-----------------------------------------------------------------------------
     374                 : // nsEventSource::nsIJSNativeInitializer methods:
     375                 : //-----------------------------------------------------------------------------
     376                 : 
     377                 : /**
     378                 :  * This Initialize method is called from XPConnect via nsIJSNativeInitializer.
     379                 :  * It is used for constructing our nsEventSource from javascript. It expects a
     380                 :  * URL string parameter. Also, initializes the principal, the script context
     381                 :  * and the window owner.
     382                 :  */
     383                 : NS_IMETHODIMP
     384               0 : nsEventSource::Initialize(nsISupports* aOwner,
     385                 :                           JSContext* aContext,
     386                 :                           JSObject* aObject,
     387                 :                           PRUint32 aArgc,
     388                 :                           jsval* aArgv)
     389                 : {
     390               0 :   if (mReadyState != nsIEventSource::CONNECTING || !PrefEnabled() ||
     391                 :       aArgc < 1) {
     392               0 :     return NS_ERROR_FAILURE;
     393                 :   }
     394                 : 
     395               0 :   JSAutoRequest ar(aContext);
     396                 : 
     397               0 :   JSString* jsstr = JS_ValueToString(aContext, aArgv[0]);
     398               0 :   if (!jsstr) {
     399               0 :     return NS_ERROR_DOM_SYNTAX_ERR;
     400                 :   }
     401                 : 
     402               0 :   JS::Anchor<JSString *> deleteProtector(jsstr);
     403                 :   size_t length;
     404               0 :   const jschar *chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
     405               0 :   if (!chars) {
     406               0 :     return NS_ERROR_OUT_OF_MEMORY;
     407                 :   }
     408                 : 
     409               0 :   nsAutoString urlParam;
     410                 : 
     411               0 :   urlParam.Assign(chars, length);
     412                 : 
     413               0 :   nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aOwner);
     414               0 :   NS_ENSURE_STATE(ownerWindow);
     415                 : 
     416               0 :   nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aOwner);
     417               0 :   NS_ENSURE_STATE(sgo);
     418               0 :   nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
     419               0 :   NS_ENSURE_STATE(scriptContext);
     420                 : 
     421                 :   nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
     422               0 :     do_QueryInterface(aOwner);
     423               0 :   NS_ENSURE_STATE(scriptPrincipal);
     424               0 :   nsCOMPtr<nsIPrincipal> principal = scriptPrincipal->GetPrincipal();
     425               0 :   NS_ENSURE_STATE(principal);
     426                 : 
     427               0 :   bool withCredentialsParam = false;
     428               0 :   if (aArgc >= 2) {
     429               0 :     NS_ENSURE_TRUE(!JSVAL_IS_PRIMITIVE(aArgv[1]), NS_ERROR_INVALID_ARG);
     430                 : 
     431               0 :     JSObject *obj = JSVAL_TO_OBJECT(aArgv[1]);
     432               0 :     NS_ASSERTION(obj, "obj shouldn't be null!!");
     433                 : 
     434               0 :     JSBool hasProperty = JS_FALSE;
     435               0 :     NS_ENSURE_TRUE(JS_HasProperty(aContext, obj, "withCredentials",
     436                 :                                   &hasProperty), NS_ERROR_FAILURE);
     437                 : 
     438               0 :     if (hasProperty) {
     439                 :       jsval withCredentialsVal;
     440               0 :       NS_ENSURE_TRUE(JS_GetProperty(aContext, obj, "withCredentials",
     441                 :                                     &withCredentialsVal), NS_ERROR_FAILURE);
     442                 : 
     443               0 :       JSBool withCredentials = JS_FALSE;
     444               0 :       NS_ENSURE_TRUE(JS_ValueToBoolean(aContext, withCredentialsVal,
     445                 :                                        &withCredentials), NS_ERROR_FAILURE);
     446               0 :       withCredentialsParam = !!withCredentials;
     447                 :     }
     448                 :   }
     449                 : 
     450                 :   return Init(principal, scriptContext, ownerWindow,
     451               0 :               urlParam, withCredentialsParam);
     452                 : }
     453                 : 
     454                 : //-----------------------------------------------------------------------------
     455                 : // nsEventSource::nsIObserver
     456                 : //-----------------------------------------------------------------------------
     457                 : 
     458                 : NS_IMETHODIMP
     459               0 : nsEventSource::Observe(nsISupports* aSubject,
     460                 :                        const char* aTopic,
     461                 :                        const PRUnichar* aData)
     462                 : {
     463               0 :   if (mReadyState == nsIEventSource::CLOSED) {
     464               0 :     return NS_OK;
     465                 :   }
     466                 : 
     467               0 :   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aSubject);
     468               0 :   if (!GetOwner() || window != GetOwner()) {
     469               0 :     return NS_OK;
     470                 :   }
     471                 : 
     472                 :   nsresult rv;
     473               0 :   if (strcmp(aTopic, DOM_WINDOW_FROZEN_TOPIC) == 0) {
     474               0 :     rv = Freeze();
     475               0 :     NS_ASSERTION(rv, "Freeze() failed");
     476               0 :   } else if (strcmp(aTopic, DOM_WINDOW_THAWED_TOPIC) == 0) {
     477               0 :     rv = Thaw();
     478               0 :     NS_ASSERTION(rv, "Thaw() failed");
     479               0 :   } else if (strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC) == 0) {
     480               0 :     Close();
     481                 :   }
     482                 : 
     483               0 :   return NS_OK;
     484                 : }
     485                 : 
     486                 : //-----------------------------------------------------------------------------
     487                 : // nsEventSource::nsIStreamListener
     488                 : //-----------------------------------------------------------------------------
     489                 : 
     490                 : NS_IMETHODIMP
     491               0 : nsEventSource::OnStartRequest(nsIRequest *aRequest,
     492                 :                               nsISupports *ctxt)
     493                 : {
     494               0 :   nsresult rv = CheckHealthOfRequestCallback(aRequest);
     495               0 :   NS_ENSURE_SUCCESS(rv, rv);
     496                 : 
     497               0 :   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest, &rv);
     498               0 :   NS_ENSURE_SUCCESS(rv, rv);
     499                 : 
     500                 :   bool requestSucceeded;
     501               0 :   rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
     502               0 :   NS_ENSURE_SUCCESS(rv, rv);
     503                 : 
     504               0 :   nsCAutoString contentType;
     505               0 :   rv = httpChannel->GetContentType(contentType);
     506               0 :   NS_ENSURE_SUCCESS(rv, rv);
     507                 : 
     508               0 :   if (!requestSucceeded || !contentType.EqualsLiteral(TEXT_EVENT_STREAM)) {
     509               0 :     DispatchFailConnection();
     510               0 :     return NS_ERROR_NOT_AVAILABLE;
     511                 :   }
     512                 : 
     513               0 :   nsCOMPtr<nsIPrincipal> principal = mPrincipal;
     514               0 :   if (nsContentUtils::IsSystemPrincipal(principal)) {
     515                 :     // Don't give this channel the system principal.
     516               0 :     principal = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
     517               0 :     NS_ENSURE_SUCCESS(rv, rv);
     518                 :   }
     519               0 :   rv = httpChannel->SetOwner(principal);
     520               0 :   NS_ENSURE_SUCCESS(rv, rv);
     521                 : 
     522                 :   nsCOMPtr<nsIRunnable> event =
     523               0 :     NS_NewRunnableMethod(this, &nsEventSource::AnnounceConnection);
     524               0 :   NS_ENSURE_STATE(event);
     525                 : 
     526               0 :   rv = NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
     527               0 :   NS_ENSURE_SUCCESS(rv, rv);
     528                 : 
     529               0 :   mStatus = PARSE_STATE_BEGIN_OF_STREAM;
     530                 : 
     531               0 :   return NS_OK;
     532                 : }
     533                 : 
     534                 : // this method parses the characters as they become available instead of
     535                 : // buffering them.
     536                 : NS_METHOD
     537               0 : nsEventSource::StreamReaderFunc(nsIInputStream *aInputStream,
     538                 :                                 void *aClosure,
     539                 :                                 const char *aFromRawSegment,
     540                 :                                 PRUint32 aToOffset,
     541                 :                                 PRUint32 aCount,
     542                 :                                 PRUint32 *aWriteCount)
     543                 : {
     544               0 :   nsEventSource* thisObject = static_cast<nsEventSource*>(aClosure);
     545               0 :   if (!thisObject || !aWriteCount) {
     546               0 :     NS_WARNING("nsEventSource cannot read from stream: no aClosure or aWriteCount");
     547               0 :     return NS_ERROR_FAILURE;
     548                 :   }
     549                 : 
     550               0 :   *aWriteCount = 0;
     551                 : 
     552                 :   PRInt32 srcCount, outCount;
     553                 :   PRUnichar out[2];
     554                 :   nsresult rv;
     555                 : 
     556               0 :   const char *p = aFromRawSegment,
     557               0 :              *end = aFromRawSegment + aCount;
     558                 : 
     559               0 :   do {
     560               0 :     srcCount = aCount - (p - aFromRawSegment);
     561               0 :     outCount = 2;
     562                 : 
     563                 :     thisObject->mLastConvertionResult =
     564               0 :       thisObject->mUnicodeDecoder->Convert(p, &srcCount, out, &outCount);
     565                 : 
     566               0 :     if (thisObject->mLastConvertionResult == NS_ERROR_ILLEGAL_INPUT) {
     567                 :       // There's an illegal byte in the input. It's now the responsibility
     568                 :       // of this calling code to output a U+FFFD REPLACEMENT CHARACTER, advance
     569                 :       // over the bad byte and reset the decoder.
     570               0 :       rv = thisObject->ParseCharacter(REPLACEMENT_CHAR);
     571               0 :       NS_ENSURE_SUCCESS(rv, rv);
     572               0 :       p = p + srcCount + 1;
     573               0 :       thisObject->mUnicodeDecoder->Reset();
     574                 :     } else {
     575               0 :       for (PRInt32 i = 0; i < outCount; ++i) {
     576               0 :         rv = thisObject->ParseCharacter(out[i]);
     577               0 :         NS_ENSURE_SUCCESS(rv, rv);
     578                 :       }
     579               0 :       p = p + srcCount;
     580                 :     }
     581                 :   } while (p < end &&
     582                 :            thisObject->mLastConvertionResult != NS_PARTIAL_MORE_INPUT &&
     583                 :            thisObject->mLastConvertionResult != NS_OK);
     584                 : 
     585                 :   // check if the last byte was a bad one and
     586                 :   // clear the state since it was handled above.
     587               0 :   if (thisObject->mLastConvertionResult == NS_ERROR_ILLEGAL_INPUT) {
     588               0 :     thisObject->mLastConvertionResult = NS_OK;
     589                 :   }
     590                 : 
     591               0 :   *aWriteCount = aCount;
     592               0 :   return NS_OK;
     593                 : }
     594                 : 
     595                 : NS_IMETHODIMP
     596               0 : nsEventSource::OnDataAvailable(nsIRequest *aRequest,
     597                 :                                nsISupports *aContext,
     598                 :                                nsIInputStream *aInputStream,
     599                 :                                PRUint32 aOffset,
     600                 :                                PRUint32 aCount)
     601                 : {
     602               0 :   NS_ENSURE_ARG_POINTER(aInputStream);
     603                 : 
     604               0 :   nsresult rv = CheckHealthOfRequestCallback(aRequest);
     605               0 :   NS_ENSURE_SUCCESS(rv, rv);
     606                 : 
     607                 :   PRUint32 totalRead;
     608                 :   return aInputStream->ReadSegments(nsEventSource::StreamReaderFunc, this,
     609               0 :                                     aCount, &totalRead);
     610                 : }
     611                 : 
     612                 : NS_IMETHODIMP
     613               0 : nsEventSource::OnStopRequest(nsIRequest *aRequest,
     614                 :                              nsISupports *aContext,
     615                 :                              nsresult aStatusCode)
     616                 : {
     617               0 :   mWaitingForOnStopRequest = false;
     618                 : 
     619               0 :   if (mReadyState == nsIEventSource::CLOSED) {
     620               0 :     return NS_ERROR_ABORT;
     621                 :   }
     622                 : 
     623               0 :   if (NS_FAILED(aStatusCode)) {
     624               0 :     DispatchFailConnection();
     625               0 :     return aStatusCode;
     626                 :   }
     627                 : 
     628                 :   nsresult rv;
     629               0 :   nsresult healthOfRequestResult = CheckHealthOfRequestCallback(aRequest);
     630               0 :   if (NS_SUCCEEDED(healthOfRequestResult)) {
     631                 :     // check if we had an incomplete UTF8 char at the end of the stream
     632               0 :     if (mLastConvertionResult == NS_PARTIAL_MORE_INPUT) {
     633               0 :       rv = ParseCharacter(REPLACEMENT_CHAR);
     634               0 :       NS_ENSURE_SUCCESS(rv, rv);
     635                 :     }
     636                 : 
     637                 :     // once we reach the end of the stream we must
     638                 :     // dispatch the current event
     639               0 :     switch (mStatus)
     640                 :     {
     641                 :       case PARSE_STATE_CR_CHAR:
     642                 :       case PARSE_STATE_COMMENT:
     643                 :       case PARSE_STATE_FIELD_NAME:
     644                 :       case PARSE_STATE_FIRST_CHAR_OF_FIELD_VALUE:
     645                 :       case PARSE_STATE_FIELD_VALUE:
     646                 :       case PARSE_STATE_BEGIN_OF_LINE:
     647               0 :         rv = SetFieldAndClear();
     648               0 :         NS_ENSURE_SUCCESS(rv, rv);
     649                 : 
     650               0 :         rv = DispatchCurrentMessageEvent();  // there is an empty line (CRCR)
     651               0 :         NS_ENSURE_SUCCESS(rv, rv);
     652                 : 
     653               0 :         break;
     654                 : 
     655                 :       // Just for not getting warnings when compiling
     656                 :       case PARSE_STATE_OFF:
     657                 :       case PARSE_STATE_BEGIN_OF_STREAM:
     658                 :       case PARSE_STATE_BOM_WAS_READ:
     659               0 :         break;
     660                 :     }
     661                 :   }
     662                 : 
     663                 :   nsCOMPtr<nsIRunnable> event =
     664               0 :     NS_NewRunnableMethod(this, &nsEventSource::ReestablishConnection);
     665               0 :   NS_ENSURE_STATE(event);
     666                 : 
     667               0 :   rv = NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
     668               0 :   NS_ENSURE_SUCCESS(rv, rv);
     669                 : 
     670               0 :   return healthOfRequestResult;
     671                 : }
     672                 : 
     673                 : /**
     674                 :  * Simple helper class that just forwards the redirect callback back
     675                 :  * to the nsEventSource.
     676                 :  */
     677                 : class AsyncVerifyRedirectCallbackFwr : public nsIAsyncVerifyRedirectCallback
     678               0 : {
     679                 : public:
     680               0 :   AsyncVerifyRedirectCallbackFwr(nsEventSource* aEventsource)
     681               0 :     : mEventSource(aEventsource)
     682                 :   {
     683               0 :   }
     684                 : 
     685               0 :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     686            1464 :   NS_DECL_CYCLE_COLLECTION_CLASS(AsyncVerifyRedirectCallbackFwr)
     687                 : 
     688                 :   // nsIAsyncVerifyRedirectCallback implementation
     689               0 :   NS_IMETHOD OnRedirectVerifyCallback(nsresult aResult)
     690                 :   {
     691               0 :     nsresult rv = mEventSource->OnRedirectVerifyCallback(aResult);
     692               0 :     if (NS_FAILED(rv)) {
     693               0 :       mEventSource->mErrorLoadOnRedirect = true;
     694               0 :       mEventSource->DispatchFailConnection();
     695                 :     }
     696                 : 
     697               0 :     return NS_OK;
     698                 :   }
     699                 : 
     700                 : private:
     701                 :   nsRefPtr<nsEventSource> mEventSource;
     702                 : };
     703                 : 
     704            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(AsyncVerifyRedirectCallbackFwr)
     705                 : 
     706               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AsyncVerifyRedirectCallbackFwr)
     707               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mEventSource, nsIEventSource)
     708               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     709                 : 
     710               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AsyncVerifyRedirectCallbackFwr)
     711               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mEventSource)
     712               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     713                 : 
     714               0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AsyncVerifyRedirectCallbackFwr)
     715               0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     716               0 :   NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
     717               0 : NS_INTERFACE_MAP_END
     718                 : 
     719               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(AsyncVerifyRedirectCallbackFwr)
     720               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(AsyncVerifyRedirectCallbackFwr)
     721                 : 
     722                 : //-----------------------------------------------------------------------------
     723                 : // nsEventSource::nsIChannelEventSink
     724                 : //-----------------------------------------------------------------------------
     725                 : 
     726                 : NS_IMETHODIMP
     727               0 : nsEventSource::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
     728                 :                                       nsIChannel *aNewChannel,
     729                 :                                       PRUint32    aFlags,
     730                 :                                       nsIAsyncVerifyRedirectCallback *aCallback)
     731                 : {
     732               0 :   nsCOMPtr<nsIRequest> aOldRequest = do_QueryInterface(aOldChannel);
     733               0 :   NS_PRECONDITION(aOldRequest, "Redirect from a null request?");
     734                 : 
     735               0 :   nsresult rv = CheckHealthOfRequestCallback(aOldRequest);
     736               0 :   NS_ENSURE_SUCCESS(rv, rv);
     737                 : 
     738               0 :   NS_PRECONDITION(aNewChannel, "Redirect without a channel?");
     739                 : 
     740               0 :   nsCOMPtr<nsIURI> newURI;
     741               0 :   rv = NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newURI));
     742               0 :   NS_ENSURE_SUCCESS(rv, rv);
     743                 : 
     744               0 :   if (!CheckCanRequestSrc(newURI)) {
     745               0 :     DispatchFailConnection();
     746               0 :     return NS_ERROR_DOM_SECURITY_ERR;
     747                 :   }
     748                 : 
     749                 :   // Prepare to receive callback
     750               0 :   mRedirectFlags = aFlags;
     751               0 :   mRedirectCallback = aCallback;
     752               0 :   mNewRedirectChannel = aNewChannel;
     753                 : 
     754               0 :   if (mChannelEventSink) {
     755                 :     nsRefPtr<AsyncVerifyRedirectCallbackFwr> fwd =
     756               0 :       new AsyncVerifyRedirectCallbackFwr(this);
     757                 : 
     758               0 :     rv = mChannelEventSink->AsyncOnChannelRedirect(aOldChannel,
     759                 :                                                    aNewChannel,
     760               0 :                                                    aFlags, fwd);
     761               0 :     if (NS_FAILED(rv)) {
     762               0 :       mRedirectCallback = nsnull;
     763               0 :       mNewRedirectChannel = nsnull;
     764               0 :       mErrorLoadOnRedirect = true;
     765               0 :       DispatchFailConnection();
     766                 :     }
     767               0 :     return rv;
     768                 :   }
     769               0 :   OnRedirectVerifyCallback(NS_OK);
     770               0 :   return NS_OK;
     771                 : }
     772                 : 
     773                 : nsresult
     774               0 : nsEventSource::OnRedirectVerifyCallback(nsresult aResult)
     775                 : {
     776               0 :   NS_ABORT_IF_FALSE(mRedirectCallback, "mRedirectCallback not set in callback");
     777               0 :   NS_ABORT_IF_FALSE(mNewRedirectChannel,
     778                 :                     "mNewRedirectChannel not set in callback");
     779                 : 
     780               0 :   NS_ENSURE_SUCCESS(aResult, aResult);
     781                 : 
     782                 :   // update our channel
     783                 : 
     784               0 :   mHttpChannel = do_QueryInterface(mNewRedirectChannel);
     785               0 :   NS_ENSURE_STATE(mHttpChannel);
     786                 : 
     787               0 :   nsresult rv = SetupHttpChannel();
     788               0 :   NS_ENSURE_SUCCESS(rv, rv);
     789                 : 
     790               0 :   if ((mRedirectFlags & nsIChannelEventSink::REDIRECT_PERMANENT) != 0) {
     791               0 :     rv = NS_GetFinalChannelURI(mHttpChannel, getter_AddRefs(mSrc));
     792               0 :     NS_ENSURE_SUCCESS(rv, rv);
     793                 :   }
     794                 : 
     795               0 :   mNewRedirectChannel = nsnull;
     796                 : 
     797               0 :   mRedirectCallback->OnRedirectVerifyCallback(aResult);
     798               0 :   mRedirectCallback = nsnull;
     799                 : 
     800               0 :   return NS_OK;
     801                 : }
     802                 : 
     803                 : //-----------------------------------------------------------------------------
     804                 : // nsEventSource::nsIInterfaceRequestor
     805                 : //-----------------------------------------------------------------------------
     806                 : 
     807                 : NS_IMETHODIMP
     808               0 : nsEventSource::GetInterface(const nsIID & aIID,
     809                 :                             void **aResult)
     810                 : {
     811                 :   // Make sure to return ourselves for the channel event sink interface,
     812                 :   // no matter what.  We can forward these to mNotificationCallbacks
     813                 :   // if it wants to get notifications for them.  But we
     814                 :   // need to see these notifications for proper functioning.
     815               0 :   if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
     816               0 :     mChannelEventSink = do_GetInterface(mNotificationCallbacks);
     817               0 :     *aResult = static_cast<nsIChannelEventSink*>(this);
     818               0 :     NS_ADDREF_THIS();
     819               0 :     return NS_OK;
     820                 :   }
     821                 : 
     822                 :   // Now give mNotificationCallbacks (if non-null) a chance to return the
     823                 :   // desired interface.
     824               0 :   if (mNotificationCallbacks) {
     825               0 :     nsresult rv = mNotificationCallbacks->GetInterface(aIID, aResult);
     826               0 :     if (NS_SUCCEEDED(rv)) {
     827               0 :       NS_ASSERTION(*aResult, "Lying nsIInterfaceRequestor implementation!");
     828               0 :       return rv;
     829                 :     }
     830                 :   }
     831                 : 
     832               0 :   if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
     833               0 :       aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
     834               0 :     nsresult rv = CheckInnerWindowCorrectness();
     835               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
     836                 : 
     837                 :     nsCOMPtr<nsIPromptFactory> wwatch =
     838               0 :       do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
     839               0 :     NS_ENSURE_SUCCESS(rv, rv);
     840                 : 
     841                 :     // Get the an auth prompter for our window so that the parenting
     842                 :     // of the dialogs works as it should when using tabs.
     843                 : 
     844               0 :     nsCOMPtr<nsIDOMWindow> window;
     845               0 :     if (GetOwner()) {
     846               0 :       window = GetOwner()->GetOuterWindow();
     847                 :     }
     848                 : 
     849               0 :     return wwatch->GetPrompt(window, aIID, aResult);
     850                 :   }
     851                 : 
     852               0 :   return QueryInterface(aIID, aResult);
     853                 : }
     854                 : 
     855                 : // static
     856                 : bool
     857               0 : nsEventSource::PrefEnabled()
     858                 : {
     859               0 :   return Preferences::GetBool("dom.server-events.enabled", false);
     860                 : }
     861                 : 
     862                 : nsresult
     863               0 : nsEventSource::GetBaseURI(nsIURI **aBaseURI)
     864                 : {
     865               0 :   NS_ENSURE_ARG_POINTER(aBaseURI);
     866                 : 
     867               0 :   *aBaseURI = nsnull;
     868                 : 
     869               0 :   nsCOMPtr<nsIURI> baseURI;
     870                 : 
     871                 :   // first we try from document->GetBaseURI()
     872                 :   nsresult rv;
     873               0 :   nsIScriptContext* sc = GetContextForEventHandlers(&rv);
     874                 :   nsCOMPtr<nsIDocument> doc =
     875               0 :     nsContentUtils::GetDocumentFromScriptContext(sc);
     876               0 :   if (doc) {
     877               0 :     baseURI = doc->GetBaseURI();
     878                 :   }
     879                 : 
     880                 :   // otherwise we get from the doc's principal
     881               0 :   if (!baseURI) {
     882               0 :     rv = mPrincipal->GetURI(getter_AddRefs(baseURI));
     883               0 :     NS_ENSURE_SUCCESS(rv, rv);
     884                 :   }
     885                 : 
     886               0 :   NS_ENSURE_STATE(baseURI);
     887                 : 
     888               0 :   baseURI.forget(aBaseURI);
     889               0 :   return NS_OK;
     890                 : }
     891                 : 
     892                 : nsresult
     893               0 : nsEventSource::SetupHttpChannel()
     894                 : {
     895               0 :   mHttpChannel->SetRequestMethod(NS_LITERAL_CSTRING("GET"));
     896                 : 
     897                 :   /* set the http request headers */
     898                 : 
     899               0 :   mHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
     900               0 :     NS_LITERAL_CSTRING(TEXT_EVENT_STREAM), false);
     901                 : 
     902                 :   // LOAD_BYPASS_CACHE already adds the Cache-Control: no-cache header
     903                 : 
     904               0 :   if (!mLastEventID.IsEmpty()) {
     905               0 :     mHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Last-Event-ID"),
     906               0 :       NS_ConvertUTF16toUTF8(mLastEventID), false);
     907                 :   }
     908                 : 
     909               0 :   nsCOMPtr<nsIURI> codebase;
     910               0 :   nsresult rv = GetBaseURI(getter_AddRefs(codebase));
     911               0 :   if (NS_SUCCEEDED(rv)) {
     912               0 :     rv = mHttpChannel->SetReferrer(codebase);
     913               0 :     NS_ENSURE_SUCCESS(rv, rv);
     914                 :   }
     915                 : 
     916               0 :   return NS_OK;
     917                 : }
     918                 : 
     919                 : nsresult
     920               0 : nsEventSource::InitChannelAndRequestEventSource()
     921                 : {
     922               0 :   if (mReadyState == nsIEventSource::CLOSED) {
     923               0 :     return NS_ERROR_ABORT;
     924                 :   }
     925                 : 
     926                 :   // eventsource validation
     927                 : 
     928               0 :   if (!CheckCanRequestSrc()) {
     929               0 :     DispatchFailConnection();
     930               0 :     return NS_ERROR_DOM_SECURITY_ERR;
     931                 :   }
     932                 : 
     933                 :   nsLoadFlags loadFlags;
     934               0 :   loadFlags = nsIRequest::LOAD_BACKGROUND | nsIRequest::LOAD_BYPASS_CACHE;
     935                 : 
     936                 :   // get Content Security Policy from principal to pass into channel
     937               0 :   nsCOMPtr<nsIChannelPolicy> channelPolicy;
     938               0 :   nsCOMPtr<nsIContentSecurityPolicy> csp;
     939               0 :   nsresult rv = mPrincipal->GetCsp(getter_AddRefs(csp));
     940               0 :   NS_ENSURE_SUCCESS(rv, rv);
     941               0 :   if (csp) {
     942               0 :     channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
     943               0 :     channelPolicy->SetContentSecurityPolicy(csp);
     944               0 :     channelPolicy->SetLoadType(nsIContentPolicy::TYPE_DATAREQUEST);
     945                 :   }
     946                 : 
     947               0 :   nsCOMPtr<nsIChannel> channel;
     948               0 :   rv = NS_NewChannel(getter_AddRefs(channel), mSrc, nsnull, mLoadGroup,
     949               0 :                      nsnull, loadFlags, channelPolicy);
     950               0 :   NS_ENSURE_SUCCESS(rv, rv);
     951                 : 
     952               0 :   mHttpChannel = do_QueryInterface(channel);
     953               0 :   NS_ENSURE_TRUE(mHttpChannel, NS_ERROR_NO_INTERFACE);
     954                 : 
     955               0 :   rv = SetupHttpChannel();
     956               0 :   NS_ENSURE_SUCCESS(rv, rv);
     957                 : 
     958               0 :   nsCOMPtr<nsIInterfaceRequestor> notificationCallbacks;
     959               0 :   mHttpChannel->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks));
     960               0 :   if (notificationCallbacks != this) {
     961               0 :     mNotificationCallbacks = notificationCallbacks;
     962               0 :     mHttpChannel->SetNotificationCallbacks(this);
     963                 :   }
     964                 : 
     965                 :   nsCOMPtr<nsIStreamListener> listener =
     966                 :     new nsCORSListenerProxy(this, mPrincipal, mHttpChannel,
     967               0 :                             mWithCredentials, &rv);
     968               0 :   NS_ENSURE_SUCCESS(rv, rv);
     969                 : 
     970                 :   // Start reading from the channel
     971               0 :   rv = mHttpChannel->AsyncOpen(listener, nsnull);
     972               0 :   if (NS_SUCCEEDED(rv)) {
     973               0 :     mWaitingForOnStopRequest = true;
     974                 :   }
     975               0 :   return rv;
     976                 : }
     977                 : 
     978                 : void
     979               0 : nsEventSource::AnnounceConnection()
     980                 : {
     981               0 :   if (mReadyState == nsIEventSource::CLOSED) {
     982               0 :     return;
     983                 :   }
     984                 : 
     985               0 :   if (mReadyState != nsIEventSource::CONNECTING) {
     986               0 :     NS_WARNING("Unexpected mReadyState!!!");
     987               0 :     return;
     988                 :   }
     989                 : 
     990                 :   // When a user agent is to announce the connection, the user agent must set
     991                 :   // the readyState attribute to OPEN and queue a task to fire a simple event
     992                 :   // named open at the EventSource object.
     993                 : 
     994               0 :   mReadyState = nsIEventSource::OPEN;
     995                 : 
     996               0 :   nsresult rv = CheckInnerWindowCorrectness();
     997               0 :   if (NS_FAILED(rv)) {
     998               0 :     return;
     999                 :   }
    1000                 : 
    1001               0 :   nsCOMPtr<nsIDOMEvent> event;
    1002               0 :   rv = NS_NewDOMEvent(getter_AddRefs(event), nsnull, nsnull);
    1003               0 :   if (NS_FAILED(rv)) {
    1004               0 :     NS_WARNING("Failed to create the open event!!!");
    1005                 :     return;
    1006                 :   }
    1007                 : 
    1008                 :   // it doesn't bubble, and it isn't cancelable
    1009               0 :   rv = event->InitEvent(NS_LITERAL_STRING("open"), false, false);
    1010               0 :   if (NS_FAILED(rv)) {
    1011               0 :     NS_WARNING("Failed to init the open event!!!");
    1012                 :     return;
    1013                 :   }
    1014                 : 
    1015               0 :   nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(event);
    1016               0 :   privateEvent->SetTrusted(true);
    1017                 : 
    1018               0 :   rv = DispatchDOMEvent(nsnull, event, nsnull, nsnull);
    1019               0 :   if (NS_FAILED(rv)) {
    1020               0 :     NS_WARNING("Failed to dispatch the open event!!!");
    1021                 :     return;
    1022                 :   }
    1023                 : }
    1024                 : 
    1025                 : nsresult
    1026               0 : nsEventSource::ResetConnection()
    1027                 : {
    1028               0 :   if (mHttpChannel) {
    1029               0 :     mHttpChannel->Cancel(NS_ERROR_ABORT);
    1030                 :   }
    1031                 : 
    1032               0 :   if (mUnicodeDecoder) {
    1033               0 :     mUnicodeDecoder->Reset();
    1034                 :   }
    1035               0 :   mLastConvertionResult = NS_OK;
    1036                 : 
    1037               0 :   mHttpChannel = nsnull;
    1038               0 :   mNotificationCallbacks = nsnull;
    1039               0 :   mChannelEventSink = nsnull;
    1040               0 :   mStatus = PARSE_STATE_OFF;
    1041               0 :   mRedirectCallback = nsnull;
    1042               0 :   mNewRedirectChannel = nsnull;
    1043                 : 
    1044               0 :   mReadyState = nsIEventSource::CONNECTING;
    1045                 : 
    1046               0 :   return NS_OK;
    1047                 : }
    1048                 : 
    1049                 : void
    1050               0 : nsEventSource::ReestablishConnection()
    1051                 : {
    1052               0 :   if (mReadyState == nsIEventSource::CLOSED) {
    1053               0 :     return;
    1054                 :   }
    1055                 : 
    1056               0 :   if (mReadyState != nsIEventSource::OPEN) {
    1057               0 :     NS_WARNING("Unexpected mReadyState!!!");
    1058               0 :     return;
    1059                 :   }
    1060                 : 
    1061               0 :   nsresult rv = ResetConnection();
    1062               0 :   if (NS_FAILED(rv)) {
    1063               0 :     NS_WARNING("Failed to reset the connection!!!");
    1064               0 :     return;
    1065                 :   }
    1066                 : 
    1067               0 :   rv = CheckInnerWindowCorrectness();
    1068               0 :   if (NS_FAILED(rv)) {
    1069               0 :     return;
    1070                 :   }
    1071                 : 
    1072               0 :   nsCOMPtr<nsIDOMEvent> event;
    1073               0 :   rv = NS_NewDOMEvent(getter_AddRefs(event), nsnull, nsnull);
    1074               0 :   if (NS_FAILED(rv)) {
    1075               0 :     NS_WARNING("Failed to create the error event!!!");
    1076                 :     return;
    1077                 :   }
    1078                 : 
    1079                 :   // it doesn't bubble, and it isn't cancelable
    1080               0 :   rv = event->InitEvent(NS_LITERAL_STRING("error"), false, false);
    1081               0 :   if (NS_FAILED(rv)) {
    1082               0 :     NS_WARNING("Failed to init the error event!!!");
    1083                 :     return;
    1084                 :   }
    1085                 : 
    1086               0 :   nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(event);
    1087               0 :   privateEvent->SetTrusted(true);
    1088                 : 
    1089               0 :   rv = DispatchDOMEvent(nsnull, event, nsnull, nsnull);
    1090               0 :   if (NS_FAILED(rv)) {
    1091               0 :     NS_WARNING("Failed to dispatch the error event!!!");
    1092                 :     return;
    1093                 :   }
    1094                 : 
    1095               0 :   rv = SetReconnectionTimeout();
    1096               0 :   if (NS_FAILED(rv)) {
    1097               0 :     NS_WARNING("Failed to set the timeout for reestablishing the connection!!!");
    1098                 :     return;
    1099                 :   }
    1100                 : }
    1101                 : 
    1102                 : nsresult
    1103               0 : nsEventSource::SetReconnectionTimeout()
    1104                 : {
    1105               0 :   if (mReadyState == nsIEventSource::CLOSED) {
    1106               0 :     return NS_ERROR_ABORT;
    1107                 :   }
    1108                 : 
    1109                 :   // the timer will be used whenever the requests are going finished.
    1110               0 :   if (!mTimer) {
    1111               0 :     mTimer = do_CreateInstance("@mozilla.org/timer;1");
    1112               0 :     NS_ENSURE_STATE(mTimer);
    1113                 :   }
    1114                 : 
    1115                 :   NS_ASSERTION(mReconnectionTime >= 0, "mReconnectionTime lies");
    1116               0 :   nsresult rv = mTimer->InitWithFuncCallback(TimerCallback, this,
    1117                 :                                              mReconnectionTime,
    1118               0 :                                              nsITimer::TYPE_ONE_SHOT);
    1119               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1120                 : 
    1121               0 :   return NS_OK;
    1122                 : }
    1123                 : 
    1124                 : nsresult
    1125               0 : nsEventSource::PrintErrorOnConsole(const char *aBundleURI,
    1126                 :                                    const PRUnichar *aError,
    1127                 :                                    const PRUnichar **aFormatStrings,
    1128                 :                                    PRUint32 aFormatStringsLen)
    1129                 : {
    1130                 :   nsCOMPtr<nsIStringBundleService> bundleService =
    1131               0 :     mozilla::services::GetStringBundleService();
    1132               0 :   NS_ENSURE_STATE(bundleService);
    1133                 : 
    1134               0 :   nsCOMPtr<nsIStringBundle> strBundle;
    1135                 :   nsresult rv =
    1136               0 :     bundleService->CreateBundle(aBundleURI, getter_AddRefs(strBundle));
    1137               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1138                 : 
    1139                 :   nsCOMPtr<nsIConsoleService> console(
    1140               0 :     do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv));
    1141               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1142                 : 
    1143                 :   nsCOMPtr<nsIScriptError> errObj(
    1144               0 :     do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv));
    1145               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1146                 : 
    1147                 :   // Localize the error message
    1148               0 :   nsXPIDLString message;
    1149               0 :   if (aFormatStrings) {
    1150               0 :     rv = strBundle->FormatStringFromName(aError, aFormatStrings,
    1151                 :                                          aFormatStringsLen,
    1152               0 :                                          getter_Copies(message));
    1153                 :   } else {
    1154               0 :     rv = strBundle->GetStringFromName(aError, getter_Copies(message));
    1155                 :   }
    1156               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1157                 : 
    1158               0 :   rv = errObj->InitWithWindowID(message.get(),
    1159                 :                                 mScriptFile.get(),
    1160                 :                                 nsnull,
    1161                 :                                 mScriptLine, 0,
    1162                 :                                 nsIScriptError::errorFlag,
    1163               0 :                                 "Event Source", mInnerWindowID);
    1164               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1165                 : 
    1166                 :   // print the error message directly to the JS console
    1167               0 :   rv = console->LogMessage(errObj);
    1168               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1169                 : 
    1170               0 :   return NS_OK;
    1171                 : }
    1172                 : 
    1173                 : nsresult
    1174               0 : nsEventSource::ConsoleError()
    1175                 : {
    1176               0 :   nsCAutoString targetSpec;
    1177               0 :   nsresult rv = mSrc->GetSpec(targetSpec);
    1178               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1179                 : 
    1180               0 :   NS_ConvertUTF8toUTF16 specUTF16(targetSpec);
    1181               0 :   const PRUnichar *formatStrings[] = { specUTF16.get() };
    1182                 : 
    1183               0 :   if (mReadyState == nsIEventSource::CONNECTING) {
    1184                 :     rv = PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
    1185               0 :                              NS_LITERAL_STRING("connectionFailure").get(),
    1186               0 :                              formatStrings, ArrayLength(formatStrings));
    1187                 :   } else {
    1188                 :     rv = PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
    1189               0 :                              NS_LITERAL_STRING("netInterrupt").get(),
    1190               0 :                              formatStrings, ArrayLength(formatStrings));
    1191                 :   }
    1192               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1193                 : 
    1194               0 :   return NS_OK;
    1195                 : }
    1196                 : 
    1197                 : nsresult
    1198               0 : nsEventSource::DispatchFailConnection()
    1199                 : {
    1200                 :   nsCOMPtr<nsIRunnable> event =
    1201               0 :     NS_NewRunnableMethod(this, &nsEventSource::FailConnection);
    1202               0 :   NS_ENSURE_STATE(event);
    1203                 : 
    1204               0 :   return NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
    1205                 : }
    1206                 : 
    1207                 : void
    1208               0 : nsEventSource::FailConnection()
    1209                 : {
    1210               0 :   if (mReadyState == nsIEventSource::CLOSED) {
    1211               0 :     return;
    1212                 :   }
    1213                 : 
    1214               0 :   nsresult rv = ConsoleError();
    1215               0 :   if (NS_FAILED(rv)) {
    1216               0 :     NS_WARNING("Failed to print to the console error");
    1217                 :   }
    1218                 : 
    1219                 :   // When a user agent is to fail the connection, the user agent must set the
    1220                 :   // readyState attribute to CLOSED and queue a task to fire a simple event
    1221                 :   // named error at the EventSource  object.
    1222                 : 
    1223               0 :   Close(); // it sets mReadyState to CLOSED
    1224                 : 
    1225               0 :   rv = CheckInnerWindowCorrectness();
    1226               0 :   if (NS_FAILED(rv)) {
    1227               0 :     return;
    1228                 :   }
    1229                 : 
    1230               0 :   nsCOMPtr<nsIDOMEvent> event;
    1231               0 :   rv = NS_NewDOMEvent(getter_AddRefs(event), nsnull, nsnull);
    1232               0 :   if (NS_FAILED(rv)) {
    1233               0 :     NS_WARNING("Failed to create the error event!!!");
    1234                 :     return;
    1235                 :   }
    1236                 : 
    1237                 :   // it doesn't bubble, and it isn't cancelable
    1238               0 :   rv = event->InitEvent(NS_LITERAL_STRING("error"), false, false);
    1239               0 :   if (NS_FAILED(rv)) {
    1240               0 :     NS_WARNING("Failed to init the error event!!!");
    1241                 :     return;
    1242                 :   }
    1243                 : 
    1244               0 :   nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(event);
    1245               0 :   privateEvent->SetTrusted(true);
    1246                 : 
    1247               0 :   rv = DispatchDOMEvent(nsnull, event, nsnull, nsnull);
    1248               0 :   if (NS_FAILED(rv)) {
    1249               0 :     NS_WARNING("Failed to dispatch the error event!!!");
    1250                 :     return;
    1251                 :   }
    1252                 : }
    1253                 : 
    1254                 : bool
    1255               0 : nsEventSource::CheckCanRequestSrc(nsIURI* aSrc)
    1256                 : {
    1257               0 :   if (mReadyState == nsIEventSource::CLOSED) {
    1258               0 :     return false;
    1259                 :   }
    1260                 : 
    1261               0 :   bool isValidURI = false;
    1262               0 :   bool isValidContentLoadPolicy = false;
    1263               0 :   bool isValidProtocol = false;
    1264                 : 
    1265               0 :   nsCOMPtr<nsIURI> srcToTest = aSrc ? aSrc : mSrc.get();
    1266               0 :   NS_ENSURE_TRUE(srcToTest, false);
    1267                 : 
    1268                 :   PRUint32 aCheckURIFlags =
    1269                 :     nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL |
    1270               0 :     nsIScriptSecurityManager::DISALLOW_SCRIPT;
    1271                 : 
    1272               0 :   nsresult rv = nsContentUtils::GetSecurityManager()->
    1273                 :     CheckLoadURIWithPrincipal(mPrincipal,
    1274                 :                               srcToTest,
    1275               0 :                               aCheckURIFlags);
    1276               0 :   isValidURI = NS_SUCCEEDED(rv);
    1277                 : 
    1278                 :   // After the security manager, the content-policy check
    1279                 : 
    1280               0 :   nsIScriptContext* sc = GetContextForEventHandlers(&rv);
    1281                 :   nsCOMPtr<nsIDocument> doc =
    1282               0 :     nsContentUtils::GetDocumentFromScriptContext(sc);
    1283                 : 
    1284                 :   // mScriptContext should be initialized because of GetBaseURI() above.
    1285                 :   // Still need to consider the case that doc is nsnull however.
    1286               0 :   rv = CheckInnerWindowCorrectness();
    1287               0 :   NS_ENSURE_SUCCESS(rv, false);
    1288               0 :   PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
    1289                 :   rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_DATAREQUEST,
    1290                 :                                  srcToTest,
    1291                 :                                  mPrincipal,
    1292                 :                                  doc,
    1293               0 :                                  NS_LITERAL_CSTRING(TEXT_EVENT_STREAM),
    1294                 :                                  nsnull,    // extra
    1295                 :                                  &shouldLoad,
    1296                 :                                  nsContentUtils::GetContentPolicy(),
    1297               0 :                                  nsContentUtils::GetSecurityManager());
    1298               0 :   isValidContentLoadPolicy = NS_SUCCEEDED(rv) && NS_CP_ACCEPTED(shouldLoad);
    1299                 : 
    1300               0 :   nsCAutoString targetURIScheme;
    1301               0 :   rv = srcToTest->GetScheme(targetURIScheme);
    1302               0 :   if (NS_SUCCEEDED(rv)) {
    1303                 :     // We only have the http support for now
    1304               0 :     isValidProtocol = targetURIScheme.EqualsLiteral("http") ||
    1305               0 :                       targetURIScheme.EqualsLiteral("https");
    1306                 :   }
    1307                 : 
    1308               0 :   return isValidURI && isValidContentLoadPolicy && isValidProtocol;
    1309                 : }
    1310                 : 
    1311                 : // static
    1312                 : void
    1313               0 : nsEventSource::TimerCallback(nsITimer* aTimer, void* aClosure)
    1314                 : {
    1315               0 :   nsRefPtr<nsEventSource> thisObject = static_cast<nsEventSource*>(aClosure);
    1316                 : 
    1317               0 :   if (thisObject->mReadyState == nsIEventSource::CLOSED) {
    1318                 :     return;
    1319                 :   }
    1320                 : 
    1321               0 :   NS_PRECONDITION(!thisObject->mHttpChannel,
    1322                 :                   "the channel hasn't been cancelled!!");
    1323                 : 
    1324               0 :   if (!thisObject->mFrozen) {
    1325               0 :     nsresult rv = thisObject->InitChannelAndRequestEventSource();
    1326               0 :     if (NS_FAILED(rv)) {
    1327               0 :       NS_WARNING("thisObject->InitChannelAndRequestEventSource() failed");
    1328                 :       return;
    1329                 :     }
    1330                 :   }
    1331                 : }
    1332                 : 
    1333                 : nsresult
    1334               0 : nsEventSource::Thaw()
    1335                 : {
    1336               0 :   if (mReadyState == nsIEventSource::CLOSED || !mFrozen) {
    1337               0 :     return NS_OK;
    1338                 :   }
    1339                 : 
    1340               0 :   NS_ASSERTION(!mHttpChannel, "the connection hasn't been closed!!!");
    1341                 : 
    1342               0 :   mFrozen = false;
    1343                 :   nsresult rv;
    1344               0 :   if (!mGoingToDispatchAllMessages && mMessagesToDispatch.GetSize() > 0) {
    1345                 :     nsCOMPtr<nsIRunnable> event =
    1346               0 :       NS_NewRunnableMethod(this, &nsEventSource::DispatchAllMessageEvents);
    1347               0 :     NS_ENSURE_STATE(event);
    1348                 : 
    1349               0 :     mGoingToDispatchAllMessages = true;
    1350                 : 
    1351               0 :     rv = NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
    1352               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1353                 :   }
    1354                 : 
    1355               0 :   rv = InitChannelAndRequestEventSource();
    1356               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1357                 : 
    1358               0 :   return NS_OK;
    1359                 : }
    1360                 : 
    1361                 : nsresult
    1362               0 : nsEventSource::Freeze()
    1363                 : {
    1364               0 :   if (mReadyState == nsIEventSource::CLOSED || mFrozen) {
    1365               0 :     return NS_OK;
    1366                 :   }
    1367                 : 
    1368               0 :   NS_ASSERTION(!mHttpChannel, "the connection hasn't been closed!!!");
    1369               0 :   mFrozen = true;
    1370               0 :   return NS_OK;
    1371                 : }
    1372                 : 
    1373                 : nsresult
    1374               0 : nsEventSource::DispatchCurrentMessageEvent()
    1375                 : {
    1376               0 :   nsAutoPtr<Message> message(new Message());
    1377               0 :   *message = mCurrentMessage;
    1378                 : 
    1379               0 :   ClearFields();
    1380                 : 
    1381               0 :   if (message->mData.IsEmpty()) {
    1382               0 :     return NS_OK;
    1383                 :   }
    1384                 : 
    1385                 :   // removes the trailing LF from mData
    1386               0 :   NS_ASSERTION(message->mData.CharAt(message->mData.Length() - 1) == LF_CHAR,
    1387                 :                "Invalid trailing character! LF was expected instead.");
    1388               0 :   message->mData.SetLength(message->mData.Length() - 1);
    1389                 : 
    1390               0 :   if (message->mEventName.IsEmpty()) {
    1391               0 :     message->mEventName.AssignLiteral("message");
    1392                 :   }
    1393                 : 
    1394               0 :   if (message->mLastEventID.IsEmpty() && !mLastEventID.IsEmpty()) {
    1395               0 :     message->mLastEventID.Assign(mLastEventID);
    1396                 :   }
    1397                 : 
    1398               0 :   PRInt32 sizeBefore = mMessagesToDispatch.GetSize();
    1399               0 :   mMessagesToDispatch.Push(message.forget());
    1400               0 :   NS_ENSURE_TRUE(mMessagesToDispatch.GetSize() == sizeBefore + 1,
    1401                 :                  NS_ERROR_OUT_OF_MEMORY);
    1402                 : 
    1403                 : 
    1404               0 :   if (!mGoingToDispatchAllMessages) {
    1405                 :     nsCOMPtr<nsIRunnable> event =
    1406               0 :       NS_NewRunnableMethod(this, &nsEventSource::DispatchAllMessageEvents);
    1407               0 :     NS_ENSURE_STATE(event);
    1408                 : 
    1409               0 :     mGoingToDispatchAllMessages = true;
    1410                 : 
    1411               0 :     return NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
    1412                 :   }
    1413                 : 
    1414               0 :   return NS_OK;
    1415                 : }
    1416                 : 
    1417                 : void
    1418               0 : nsEventSource::DispatchAllMessageEvents()
    1419                 : {
    1420               0 :   if (mReadyState == nsIEventSource::CLOSED || mFrozen) {
    1421               0 :     return;
    1422                 :   }
    1423                 : 
    1424               0 :   mGoingToDispatchAllMessages = false;
    1425                 : 
    1426               0 :   nsresult rv = CheckInnerWindowCorrectness();
    1427               0 :   if (NS_FAILED(rv)) {
    1428               0 :     return;
    1429                 :   }
    1430                 : 
    1431                 :   // Let's play get the JSContext
    1432               0 :   nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(GetOwner());
    1433               0 :   NS_ENSURE_TRUE(sgo,);
    1434                 : 
    1435               0 :   nsIScriptContext* scriptContext = sgo->GetContext();
    1436               0 :   NS_ENSURE_TRUE(scriptContext,);
    1437                 : 
    1438               0 :   JSContext* cx = scriptContext->GetNativeContext();
    1439               0 :   NS_ENSURE_TRUE(cx,);
    1440                 : 
    1441               0 :   while (mMessagesToDispatch.GetSize() > 0) {
    1442                 :     nsAutoPtr<Message>
    1443               0 :       message(static_cast<Message*>(mMessagesToDispatch.PopFront()));
    1444                 : 
    1445                 :     // Now we can turn our string into a jsval
    1446                 :     jsval jsData;
    1447                 :     {
    1448                 :       JSString* jsString;
    1449               0 :       JSAutoRequest ar(cx);
    1450                 :       jsString = JS_NewUCStringCopyN(cx,
    1451               0 :                                      message->mData.get(),
    1452               0 :                                      message->mData.Length());
    1453               0 :       NS_ENSURE_TRUE(jsString,);
    1454                 : 
    1455               0 :       jsData = STRING_TO_JSVAL(jsString);
    1456                 :     }
    1457                 : 
    1458                 :     // create an event that uses the MessageEvent interface,
    1459                 :     // which does not bubble, is not cancelable, and has no default action
    1460                 : 
    1461               0 :     nsCOMPtr<nsIDOMEvent> event;
    1462               0 :     rv = NS_NewDOMMessageEvent(getter_AddRefs(event), nsnull, nsnull);
    1463               0 :     if (NS_FAILED(rv)) {
    1464               0 :       NS_WARNING("Failed to create the message event!!!");
    1465                 :       return;
    1466                 :     }
    1467                 : 
    1468               0 :     nsCOMPtr<nsIDOMMessageEvent> messageEvent = do_QueryInterface(event);
    1469               0 :     rv = messageEvent->InitMessageEvent(message->mEventName,
    1470                 :                                         false, false,
    1471                 :                                         jsData,
    1472                 :                                         mOrigin,
    1473               0 :                                         message->mLastEventID, nsnull);
    1474               0 :     if (NS_FAILED(rv)) {
    1475               0 :       NS_WARNING("Failed to init the message event!!!");
    1476                 :       return;
    1477                 :     }
    1478                 : 
    1479               0 :     nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(event);
    1480               0 :     privateEvent->SetTrusted(true);
    1481                 : 
    1482               0 :     rv = DispatchDOMEvent(nsnull, event, nsnull, nsnull);
    1483               0 :     if (NS_FAILED(rv)) {
    1484               0 :       NS_WARNING("Failed to dispatch the message event!!!");
    1485                 :       return;
    1486                 :     }
    1487                 :   }
    1488                 : }
    1489                 : 
    1490                 : nsresult
    1491               0 : nsEventSource::ClearFields()
    1492                 : {
    1493                 :   // mLastEventID and mReconnectionTime must be cached
    1494                 : 
    1495               0 :   mCurrentMessage.mEventName.Truncate();
    1496               0 :   mCurrentMessage.mLastEventID.Truncate();
    1497               0 :   mCurrentMessage.mData.Truncate();
    1498                 : 
    1499               0 :   mLastFieldName.Truncate();
    1500               0 :   mLastFieldValue.Truncate();
    1501                 : 
    1502               0 :   return NS_OK;
    1503                 : }
    1504                 : 
    1505                 : nsresult
    1506               0 : nsEventSource::SetFieldAndClear()
    1507                 : {
    1508               0 :   if (mLastFieldName.IsEmpty()) {
    1509               0 :     mLastFieldValue.Truncate();
    1510               0 :     return NS_OK;
    1511                 :   }
    1512                 : 
    1513                 :   PRUnichar first_char;
    1514               0 :   first_char = mLastFieldName.CharAt(0);
    1515                 : 
    1516               0 :   switch (first_char)  // with no case folding performed
    1517                 :   {
    1518                 :     case PRUnichar('d'):
    1519               0 :       if (mLastFieldName.EqualsLiteral("data")) {
    1520                 :         // If the field name is "data" append the field value to the data
    1521                 :         // buffer, then append a single U+000A LINE FEED (LF) character
    1522                 :         // to the data buffer.
    1523               0 :         mCurrentMessage.mData.Append(mLastFieldValue);
    1524               0 :         mCurrentMessage.mData.Append(LF_CHAR);
    1525                 :       }
    1526               0 :       break;
    1527                 : 
    1528                 :     case PRUnichar('e'):
    1529               0 :       if (mLastFieldName.EqualsLiteral("event")) {
    1530               0 :         mCurrentMessage.mEventName.Assign(mLastFieldValue);
    1531                 :       }
    1532               0 :       break;
    1533                 : 
    1534                 :     case PRUnichar('i'):
    1535               0 :       if (mLastFieldName.EqualsLiteral("id")) {
    1536               0 :         mCurrentMessage.mLastEventID.Assign(mLastFieldValue);
    1537               0 :         mLastEventID.Assign(mLastFieldValue);
    1538                 :       }
    1539               0 :       break;
    1540                 : 
    1541                 :     case PRUnichar('r'):
    1542               0 :       if (mLastFieldName.EqualsLiteral("retry")) {
    1543               0 :         PRUint32 newValue=0;
    1544               0 :         PRUint32 i = 0;  // we must ensure that there are only digits
    1545               0 :         bool assign = true;
    1546               0 :         for (i = 0; i < mLastFieldValue.Length(); ++i) {
    1547               0 :           if (mLastFieldValue.CharAt(i) < (PRUnichar)'0' ||
    1548               0 :               mLastFieldValue.CharAt(i) > (PRUnichar)'9') {
    1549               0 :             assign = false;
    1550               0 :             break;
    1551                 :           }
    1552                 :           newValue = newValue*10 +
    1553               0 :                      (((PRUint32)mLastFieldValue.CharAt(i))-
    1554               0 :                        ((PRUint32)((PRUnichar)'0')));
    1555                 :         }
    1556                 : 
    1557               0 :         if (assign) {
    1558               0 :           if (newValue < MIN_RECONNECTION_TIME_VALUE) {
    1559               0 :             mReconnectionTime = MIN_RECONNECTION_TIME_VALUE;
    1560               0 :           } else if (newValue > MAX_RECONNECTION_TIME_VALUE) {
    1561               0 :             mReconnectionTime = MAX_RECONNECTION_TIME_VALUE;
    1562                 :           } else {
    1563               0 :             mReconnectionTime = newValue;
    1564                 :           }
    1565                 :         }
    1566               0 :         break;
    1567                 :       }
    1568               0 :       break;
    1569                 :   }
    1570                 : 
    1571               0 :   mLastFieldName.Truncate();
    1572               0 :   mLastFieldValue.Truncate();
    1573                 : 
    1574               0 :   return NS_OK;
    1575                 : }
    1576                 : 
    1577                 : nsresult
    1578               0 : nsEventSource::CheckHealthOfRequestCallback(nsIRequest *aRequestCallback)
    1579                 : {
    1580                 :   // check if we have been closed or if the request has been canceled
    1581                 :   // or if we have been frozen
    1582               0 :   if (mReadyState == nsIEventSource::CLOSED || !mHttpChannel ||
    1583                 :       mFrozen || mErrorLoadOnRedirect) {
    1584               0 :     return NS_ERROR_ABORT;
    1585                 :   }
    1586                 : 
    1587               0 :   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequestCallback);
    1588               0 :   NS_ENSURE_STATE(httpChannel);
    1589                 : 
    1590               0 :   if (httpChannel != mHttpChannel) {
    1591               0 :     NS_WARNING("wrong channel from request callback");
    1592               0 :     return NS_ERROR_ABORT;
    1593                 :   }
    1594                 : 
    1595               0 :   return NS_OK;
    1596                 : }
    1597                 : 
    1598                 : nsresult
    1599               0 : nsEventSource::ParseCharacter(PRUnichar aChr)
    1600                 : {
    1601                 :   nsresult rv;
    1602                 : 
    1603               0 :   if (mReadyState == nsIEventSource::CLOSED) {
    1604               0 :     return NS_ERROR_ABORT;
    1605                 :   }
    1606                 : 
    1607               0 :   switch (mStatus)
    1608                 :   {
    1609                 :     case PARSE_STATE_OFF:
    1610               0 :       NS_ERROR("Invalid state");
    1611               0 :       return NS_ERROR_FAILURE;
    1612                 :       break;
    1613                 : 
    1614                 :     case PARSE_STATE_BEGIN_OF_STREAM:
    1615               0 :       if (aChr == BOM_CHAR) {
    1616               0 :         mStatus = PARSE_STATE_BOM_WAS_READ;  // ignore it
    1617               0 :       } else if (aChr == CR_CHAR) {
    1618               0 :         mStatus = PARSE_STATE_CR_CHAR;
    1619               0 :       } else if (aChr == LF_CHAR) {
    1620               0 :         mStatus = PARSE_STATE_BEGIN_OF_LINE;
    1621               0 :       } else if (aChr == COLON_CHAR) {
    1622               0 :         mStatus = PARSE_STATE_COMMENT;
    1623                 :       } else {
    1624               0 :         mLastFieldName += aChr;
    1625               0 :         mStatus = PARSE_STATE_FIELD_NAME;
    1626                 :       }
    1627                 : 
    1628               0 :       break;
    1629                 : 
    1630                 :     case PARSE_STATE_BOM_WAS_READ:
    1631               0 :       if (aChr == CR_CHAR) {
    1632               0 :         mStatus = PARSE_STATE_CR_CHAR;
    1633               0 :       } else if (aChr == LF_CHAR) {
    1634               0 :         mStatus = PARSE_STATE_BEGIN_OF_LINE;
    1635               0 :       } else if (aChr == COLON_CHAR) {
    1636               0 :         mStatus = PARSE_STATE_COMMENT;
    1637                 :       } else {
    1638               0 :         mLastFieldName += aChr;
    1639               0 :         mStatus = PARSE_STATE_FIELD_NAME;
    1640                 :       }
    1641               0 :       break;
    1642                 : 
    1643                 :     case PARSE_STATE_CR_CHAR:
    1644               0 :       if (aChr == CR_CHAR) {
    1645               0 :         rv = DispatchCurrentMessageEvent();  // there is an empty line (CRCR)
    1646               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1647               0 :       } else if (aChr == LF_CHAR) {
    1648               0 :         mStatus = PARSE_STATE_BEGIN_OF_LINE;
    1649               0 :       } else if (aChr == COLON_CHAR) {
    1650               0 :         mStatus = PARSE_STATE_COMMENT;
    1651                 :       } else {
    1652               0 :         mLastFieldName += aChr;
    1653               0 :         mStatus = PARSE_STATE_FIELD_NAME;
    1654                 :       }
    1655                 : 
    1656               0 :       break;
    1657                 : 
    1658                 :     case PARSE_STATE_COMMENT:
    1659               0 :       if (aChr == CR_CHAR) {
    1660               0 :         mStatus = PARSE_STATE_CR_CHAR;
    1661               0 :       } else if (aChr == LF_CHAR) {
    1662               0 :         mStatus = PARSE_STATE_BEGIN_OF_LINE;
    1663                 :       }
    1664                 : 
    1665               0 :       break;
    1666                 : 
    1667                 :     case PARSE_STATE_FIELD_NAME:
    1668               0 :       if (aChr == CR_CHAR) {
    1669               0 :         rv = SetFieldAndClear();
    1670               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1671                 : 
    1672               0 :         mStatus = PARSE_STATE_CR_CHAR;
    1673               0 :       } else if (aChr == LF_CHAR) {
    1674               0 :         rv = SetFieldAndClear();
    1675               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1676                 : 
    1677               0 :         mStatus = PARSE_STATE_BEGIN_OF_LINE;
    1678               0 :       } else if (aChr == COLON_CHAR) {
    1679               0 :         mStatus = PARSE_STATE_FIRST_CHAR_OF_FIELD_VALUE;
    1680                 :       } else {
    1681               0 :         mLastFieldName += aChr;
    1682                 :       }
    1683                 : 
    1684               0 :       break;
    1685                 : 
    1686                 :     case PARSE_STATE_FIRST_CHAR_OF_FIELD_VALUE:
    1687               0 :       if (aChr == CR_CHAR) {
    1688               0 :         rv = SetFieldAndClear();
    1689               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1690                 : 
    1691               0 :         mStatus = PARSE_STATE_CR_CHAR;
    1692               0 :       } else if (aChr == LF_CHAR) {
    1693               0 :         rv = SetFieldAndClear();
    1694               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1695                 : 
    1696               0 :         mStatus = PARSE_STATE_BEGIN_OF_LINE;
    1697               0 :       } else if (aChr == SPACE_CHAR) {
    1698               0 :         mStatus = PARSE_STATE_FIELD_VALUE;
    1699                 :       } else {
    1700               0 :         mLastFieldValue += aChr;
    1701               0 :         mStatus = PARSE_STATE_FIELD_VALUE;
    1702                 :       }
    1703                 : 
    1704               0 :       break;
    1705                 : 
    1706                 :     case PARSE_STATE_FIELD_VALUE:
    1707               0 :       if (aChr == CR_CHAR) {
    1708               0 :         rv = SetFieldAndClear();
    1709               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1710                 : 
    1711               0 :         mStatus = PARSE_STATE_CR_CHAR;
    1712               0 :       } else if (aChr == LF_CHAR) {
    1713               0 :         rv = SetFieldAndClear();
    1714               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1715                 : 
    1716               0 :         mStatus = PARSE_STATE_BEGIN_OF_LINE;
    1717                 :       } else {
    1718               0 :         mLastFieldValue += aChr;
    1719                 :       }
    1720                 : 
    1721               0 :       break;
    1722                 : 
    1723                 :     case PARSE_STATE_BEGIN_OF_LINE:
    1724               0 :       if (aChr == CR_CHAR) {
    1725               0 :         rv = DispatchCurrentMessageEvent();  // there is an empty line
    1726               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1727                 : 
    1728               0 :         mStatus = PARSE_STATE_CR_CHAR;
    1729               0 :       } else if (aChr == LF_CHAR) {
    1730               0 :         rv = DispatchCurrentMessageEvent();  // there is an empty line
    1731               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1732                 : 
    1733               0 :         mStatus = PARSE_STATE_BEGIN_OF_LINE;
    1734               0 :       } else if (aChr == COLON_CHAR) {
    1735               0 :         mStatus = PARSE_STATE_COMMENT;
    1736                 :       } else {
    1737               0 :         mLastFieldName += aChr;
    1738               0 :         mStatus = PARSE_STATE_FIELD_NAME;
    1739                 :       }
    1740                 : 
    1741               0 :       break;
    1742                 :   }
    1743                 : 
    1744               0 :   return NS_OK;
    1745            4392 : }

Generated by: LCOV version 1.7