Bug 819639 - Part b: Move EventSource to Paris bindings; r=bz
authorMs2ger <ms2ger@gmail.com>
Sat, 22 Dec 2012 09:17:05 +0100
changeset 116679 da12f650d014d37691eba37a114bcdf375b6213d
parent 116678 23817988285b65fc89b3301cda0385e41ed3cd56
child 116680 dbb76b67ed73ef9a61bfe89953aaf15afe8f98df
push idunknown
push userunknown
push dateunknown
reviewersbz
bugs819639
milestone20.0a1
Bug 819639 - Part b: Move EventSource to Paris bindings; r=bz
content/base/public/Makefile.in
content/base/public/nsIEventSource.idl
content/base/src/EventSource.cpp
content/base/src/EventSource.h
content/base/test/test_bug338583.html
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/webidl/EventSource.webidl
dom/webidl/WebIDL.mk
--- a/content/base/public/Makefile.in
+++ b/content/base/public/Makefile.in
@@ -79,13 +79,12 @@ XPIDLSRCS	= \
 		nsIScriptLoaderObserver.idl  \
 		nsIDroppedLinkHandler.idl \
 		nsIImageLoadingContent.idl \
 		nsIObjectLoadingContent.idl \
 		nsIFrameLoader.idl \
 		nsIXMLHttpRequest.idl \
 		nsIContentSecurityPolicy.idl \
 		nsIMessageManager.idl \
-		nsIEventSource.idl \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
deleted file mode 100644
--- a/content/base/public/nsIEventSource.idl
+++ /dev/null
@@ -1,67 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * The nsIEventSource interface is the interface for server-sent
- * DOM events as described in
- * http://dev.w3.org/html5/eventsource/#eventsource
- *
- */
-
-#include "nsISupports.idl"
-
-interface nsIDOMEventListener;
-interface nsIPrincipal;
-interface nsIScriptContext;
-interface nsPIDOMWindow;
-
-[scriptable, uuid(778e5ae3-c72c-4d4b-9dc7-4a6477651957)]
-interface nsIEventSource : nsISupports
-{
-  readonly attribute DOMString url;
-
-  // ready state
-  const unsigned short CONNECTING = 0;
-  const unsigned short OPEN = 1;
-  const unsigned short CLOSED = 2;
-  readonly attribute long readyState;
-
-  // if true then cross-site Access-Control requests are made using credentials
-  // such as cookies and authorization headers. Never affects same-site
-  // requests.
-  readonly attribute boolean withCredentials;
-
-  // event handler attributes
-  [implicit_jscontext] attribute jsval onopen;
-  [implicit_jscontext] attribute jsval onmessage;
-  [implicit_jscontext] attribute jsval onerror;
-
-  /**
-   * Close the connection, if any, and set the readyState attribute to CLOSED.
-   * If the connection is already closed, the method does nothing.
-   */
-  void close();
-
-  /**
-   * Initialize the object for use from C++ code with the principal, script
-   * context, and owner window that should be used.
-   *
-   * @param principal The principal to use for the request. This must not be
-   *                  null.
-   * @param scriptContext The script context to use for the request. May be
-   *                      null.
-   * @param ownerWindow The associated window for the request. May be null.
-   * @param url The EventSource's url. This must not be empty.
-   * @param withCredentials When set to true attempts to make cross-site
-   *                        Access-Control requests with credentials such as
-   *                        cookies and authorization headers. Never affects
-   *                        same-site requests.
-   */
-  [noscript] void init(in nsIPrincipal principal,
-                       in nsIScriptContext scriptContext,
-                       in nsPIDOMWindow ownerWindow,
-                       in DOMString url,
-                       in boolean withCredentials);
-};
--- a/content/base/src/EventSource.cpp
+++ b/content/base/src/EventSource.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/EventSource.h"
 
 #include "mozilla/DebugOnly.h"
+#include "mozilla/dom/EventSourceBinding.h"
 #include "mozilla/Util.h"
 
 #include "nsNetUtil.h"
 #include "nsMimeTypes.h"
 #include "nsDOMMessageEvent.h"
 #include "nsIJSContextStack.h"
 #include "nsIPromptFactory.h"
 #include "nsIWindowWatcher.h"
@@ -29,21 +30,18 @@
 #include "nsIContentSecurityPolicy.h"
 #include "nsContentUtils.h"
 #include "mozilla/Preferences.h"
 #include "xpcpublic.h"
 #include "nsCrossSiteListenerProxy.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsDOMEventTargetHelper.h"
 #include "mozilla/Attributes.h"
-#include "nsDOMClassInfoID.h"
 #include "nsError.h"
 
-DOMCI_DATA(EventSource, mozilla::dom::EventSource)
-
 namespace mozilla {
 namespace dom {
 
 #define REPLACEMENT_CHAR     (PRUnichar)0xFFFD
 #define BOM_CHAR             (PRUnichar)0xFEFF
 #define SPACE_CHAR           (PRUnichar)0x0020
 #define CR_CHAR              (PRUnichar)0x000D
 #define LF_CHAR              (PRUnichar)0x000A
@@ -60,20 +58,21 @@ namespace dom {
 EventSource::EventSource() :
   mStatus(PARSE_STATE_OFF),
   mFrozen(false),
   mErrorLoadOnRedirect(false),
   mGoingToDispatchAllMessages(false),
   mWithCredentials(false),
   mWaitingForOnStopRequest(false),
   mLastConvertionResult(NS_OK),
-  mReadyState(nsIEventSource::CONNECTING),
+  mReadyState(CONNECTING),
   mScriptLine(0),
   mInnerWindowID(0)
 {
+  SetIsDOMBinding();
 }
 
 EventSource::~EventSource()
 {
   Close();
 }
 
 //-----------------------------------------------------------------------------
@@ -118,73 +117,39 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUnicodeDecoder)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(EventSource, nsDOMEventTargetHelper)
   tmp->Close();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(EventSource)
-  NS_INTERFACE_MAP_ENTRY(nsIEventSource)
-  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
   NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(EventSource)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(EventSource, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(EventSource, nsDOMEventTargetHelper)
 
-NS_IMPL_EVENT_HANDLER(EventSource, open)
-NS_IMPL_EVENT_HANDLER(EventSource, message)
-NS_IMPL_EVENT_HANDLER(EventSource, error)
-
 void
 EventSource::DisconnectFromOwner()
 {
   nsDOMEventTargetHelper::DisconnectFromOwner();
   Close();
 }
 
-//-----------------------------------------------------------------------------
-// EventSource::nsIEventSource
-//-----------------------------------------------------------------------------
-
-NS_IMETHODIMP
-EventSource::GetUrl(nsAString& aURL)
-{
-  aURL = mOriginalURL;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-EventSource::GetReadyState(int32_t *aReadyState)
-{
-  NS_ENSURE_ARG_POINTER(aReadyState);
-  *aReadyState = mReadyState;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-EventSource::GetWithCredentials(bool *aWithCredentials)
-{
-  NS_ENSURE_ARG_POINTER(aWithCredentials);
-  *aWithCredentials = mWithCredentials;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
+void
 EventSource::Close()
 {
-  if (mReadyState == nsIEventSource::CLOSED) {
-    return NS_OK;
+  if (mReadyState == CLOSED) {
+    return;
   }
 
   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   if (os) {
     os->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
     os->RemoveObserver(this, DOM_WINDOW_FROZEN_TOPIC);
     os->RemoveObserver(this, DOM_WINDOW_THAWED_TOPIC);
   }
@@ -202,45 +167,46 @@ EventSource::Close()
     delete static_cast<Message*>(mMessagesToDispatch.PopFront());
   }
 
   mSrc = nullptr;
   mFrozen = false;
 
   mUnicodeDecoder = nullptr;
 
-  mReadyState = nsIEventSource::CLOSED;
-
-  return NS_OK;
+  mReadyState = CLOSED;
 }
 
-/**
- * This Init method should only be called by C++ consumers.
- */
-NS_IMETHODIMP
-EventSource::Init(nsIPrincipal* aPrincipal,
-                  nsIScriptContext* aScriptContext,
-                  nsPIDOMWindow* aOwnerWindow,
+nsresult
+EventSource::Init(nsISupports* aOwner,
                   const nsAString& aURL,
                   bool aWithCredentials)
 {
-  NS_ENSURE_ARG(aPrincipal);
-
-  if (mReadyState != nsIEventSource::CONNECTING || !PrefEnabled()) {
+  if (mReadyState != CONNECTING || !PrefEnabled()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
-  mPrincipal = aPrincipal;
+  nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aOwner);
+  NS_ENSURE_STATE(ownerWindow);
+  MOZ_ASSERT(ownerWindow->IsInnerWindow());
+
+  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aOwner);
+  NS_ENSURE_STATE(sgo);
+  nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
+  NS_ENSURE_STATE(scriptContext);
+
+  nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
+    do_QueryInterface(aOwner);
+  NS_ENSURE_STATE(scriptPrincipal);
+  nsCOMPtr<nsIPrincipal> principal = scriptPrincipal->GetPrincipal();
+  NS_ENSURE_STATE(principal);
+
+  mPrincipal = principal;
   mWithCredentials = aWithCredentials;
-  if (aOwnerWindow) {
-    BindToOwner(aOwnerWindow->IsOuterWindow() ?
-      aOwnerWindow->GetCurrentInnerWindow() : aOwnerWindow);
-  } else {
-    BindToOwner(aOwnerWindow);
-  }
+  BindToOwner(ownerWindow);
 
   nsCOMPtr<nsIJSContextStack> stack =
     do_GetService("@mozilla.org/js/xpc/ContextStack;1");
   JSContext* cx = nullptr;
   if (stack && NS_SUCCEEDED(stack->Peek(&cx)) && cx) {
     const char *filename;
     if (nsJSUtils::GetCallingLocation(cx, &filename, &mScriptLine)) {
       mScriptFile.AssignASCII(filename);
@@ -308,107 +274,42 @@ EventSource::Init(nsIPrincipal* aPrincip
   // the constructor should throw a SYNTAX_ERROR only if it fails resolving the
   // url parameter, so we don't care about the InitChannelAndRequestEventSource
   // result.
   InitChannelAndRequestEventSource();
 
   return NS_OK;
 }
 
-//-----------------------------------------------------------------------------
-// EventSource::nsIJSNativeInitializer methods:
-//-----------------------------------------------------------------------------
-
-/**
- * This Initialize method is called from XPConnect via nsIJSNativeInitializer.
- * It is used for constructing our EventSource from javascript. It expects a
- * URL string parameter. Also, initializes the principal, the script context
- * and the window owner.
- */
-NS_IMETHODIMP
-EventSource::Initialize(nsISupports* aOwner,
-                        JSContext* aContext,
-                        JSObject* aObject,
-                        uint32_t aArgc,
-                        jsval* aArgv)
+/* virtual */ JSObject*
+EventSource::WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap)
 {
-  if (mReadyState != nsIEventSource::CONNECTING || !PrefEnabled() ||
-      aArgc < 1) {
-    return NS_ERROR_FAILURE;
-  }
-
-  JSAutoRequest ar(aContext);
-
-  JSString* jsstr = JS_ValueToString(aContext, aArgv[0]);
-  if (!jsstr) {
-    return NS_ERROR_DOM_SYNTAX_ERR;
-  }
-
-  JS::Anchor<JSString *> deleteProtector(jsstr);
-  size_t length;
-  const jschar *chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
-  if (!chars) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  nsAutoString urlParam;
-
-  urlParam.Assign(chars, length);
+  return EventSourceBinding::Wrap(aCx, aScope, this, aTriedToWrap);
+}
 
-  nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aOwner);
-  NS_ENSURE_STATE(ownerWindow);
-
-  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aOwner);
-  NS_ENSURE_STATE(sgo);
-  nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
-  NS_ENSURE_STATE(scriptContext);
-
-  nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
-    do_QueryInterface(aOwner);
-  NS_ENSURE_STATE(scriptPrincipal);
-  nsCOMPtr<nsIPrincipal> principal = scriptPrincipal->GetPrincipal();
-  NS_ENSURE_STATE(principal);
-
-  bool withCredentialsParam = false;
-  if (aArgc >= 2) {
-    NS_ENSURE_TRUE(!JSVAL_IS_PRIMITIVE(aArgv[1]), NS_ERROR_INVALID_ARG);
-
-    JSObject *obj = JSVAL_TO_OBJECT(aArgv[1]);
-    NS_ASSERTION(obj, "obj shouldn't be null!!");
-
-    JSBool hasProperty = JS_FALSE;
-    NS_ENSURE_TRUE(JS_HasProperty(aContext, obj, "withCredentials",
-                                  &hasProperty), NS_ERROR_FAILURE);
-
-    if (hasProperty) {
-      jsval withCredentialsVal;
-      NS_ENSURE_TRUE(JS_GetProperty(aContext, obj, "withCredentials",
-                                    &withCredentialsVal), NS_ERROR_FAILURE);
-
-      JSBool withCredentials = JS_FALSE;
-      NS_ENSURE_TRUE(JS_ValueToBoolean(aContext, withCredentialsVal,
-                                       &withCredentials), NS_ERROR_FAILURE);
-      withCredentialsParam = !!withCredentials;
-    }
-  }
-
-  return Init(principal, scriptContext, ownerWindow,
-              urlParam, withCredentialsParam);
+/* static */ already_AddRefed<EventSource>
+EventSource::Constructor(nsISupports* aOwner, const nsAString& aURL,
+                         const EventSourceInit& aEventSourceInitDict,
+                         ErrorResult& aRv)
+{
+  nsRefPtr<EventSource> eventSource = new EventSource();
+  aRv = eventSource->Init(aOwner, aURL, aEventSourceInitDict.mWithCredentials);
+  return eventSource.forget();
 }
 
 //-----------------------------------------------------------------------------
 // EventSource::nsIObserver
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 EventSource::Observe(nsISupports* aSubject,
                      const char* aTopic,
                      const PRUnichar* aData)
 {
-  if (mReadyState == nsIEventSource::CLOSED) {
+  if (mReadyState == CLOSED) {
     return NS_OK;
   }
 
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aSubject);
   if (!GetOwner() || window != GetOwner()) {
     return NS_OK;
   }
 
@@ -539,17 +440,17 @@ EventSource::OnDataAvailable(nsIRequest 
 
 NS_IMETHODIMP
 EventSource::OnStopRequest(nsIRequest *aRequest,
                            nsISupports *aContext,
                            nsresult aStatusCode)
 {
   mWaitingForOnStopRequest = false;
 
-  if (mReadyState == nsIEventSource::CLOSED) {
+  if (mReadyState == CLOSED) {
     return NS_ERROR_ABORT;
   }
 
   if (NS_FAILED(aStatusCode)) {
     DispatchFailConnection();
     return aStatusCode;
   }
 
@@ -842,17 +743,17 @@ EventSource::SetupHttpChannel()
   }
 
   return NS_OK;
 }
 
 nsresult
 EventSource::InitChannelAndRequestEventSource()
 {
-  if (mReadyState == nsIEventSource::CLOSED) {
+  if (mReadyState == CLOSED) {
     return NS_ERROR_ABORT;
   }
 
   // eventsource validation
 
   if (!CheckCanRequestSrc()) {
     DispatchFailConnection();
     return NS_ERROR_DOM_SECURITY_ERR;
@@ -901,30 +802,30 @@ EventSource::InitChannelAndRequestEventS
     mWaitingForOnStopRequest = true;
   }
   return rv;
 }
 
 void
 EventSource::AnnounceConnection()
 {
-  if (mReadyState == nsIEventSource::CLOSED) {
+  if (mReadyState == CLOSED) {
     return;
   }
 
-  if (mReadyState != nsIEventSource::CONNECTING) {
+  if (mReadyState != CONNECTING) {
     NS_WARNING("Unexpected mReadyState!!!");
     return;
   }
 
   // When a user agent is to announce the connection, the user agent must set
   // the readyState attribute to OPEN and queue a task to fire a simple event
   // named open at the EventSource object.
 
-  mReadyState = nsIEventSource::OPEN;
+  mReadyState = OPEN;
 
   nsresult rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return;
   }
 
   nsCOMPtr<nsIDOMEvent> event;
   rv = NS_NewDOMEvent(getter_AddRefs(event), nullptr, nullptr);
@@ -963,29 +864,29 @@ EventSource::ResetConnection()
 
   mHttpChannel = nullptr;
   mNotificationCallbacks = nullptr;
   mChannelEventSink = nullptr;
   mStatus = PARSE_STATE_OFF;
   mRedirectCallback = nullptr;
   mNewRedirectChannel = nullptr;
 
-  mReadyState = nsIEventSource::CONNECTING;
+  mReadyState = CONNECTING;
 
   return NS_OK;
 }
 
 void
 EventSource::ReestablishConnection()
 {
-  if (mReadyState == nsIEventSource::CLOSED) {
+  if (mReadyState == CLOSED) {
     return;
   }
 
-  if (mReadyState != nsIEventSource::OPEN) {
+  if (mReadyState != OPEN) {
     NS_WARNING("Unexpected mReadyState!!!");
     return;
   }
 
   nsresult rv = ResetConnection();
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to reset the connection!!!");
     return;
@@ -1023,17 +924,17 @@ EventSource::ReestablishConnection()
     NS_WARNING("Failed to set the timeout for reestablishing the connection!!!");
     return;
   }
 }
 
 nsresult
 EventSource::SetReconnectionTimeout()
 {
-  if (mReadyState == nsIEventSource::CLOSED) {
+  if (mReadyState == CLOSED) {
     return NS_ERROR_ABORT;
   }
 
   // the timer will be used whenever the requests are going finished.
   if (!mTimer) {
     mTimer = do_CreateInstance("@mozilla.org/timer;1");
     NS_ENSURE_STATE(mTimer);
   }
@@ -1100,17 +1001,17 @@ EventSource::ConsoleError()
 {
   nsAutoCString targetSpec;
   nsresult rv = mSrc->GetSpec(targetSpec);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ConvertUTF8toUTF16 specUTF16(targetSpec);
   const PRUnichar *formatStrings[] = { specUTF16.get() };
 
-  if (mReadyState == nsIEventSource::CONNECTING) {
+  if (mReadyState == CONNECTING) {
     rv = PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
                              NS_LITERAL_STRING("connectionFailure").get(),
                              formatStrings, ArrayLength(formatStrings));
   } else {
     rv = PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
                              NS_LITERAL_STRING("netInterrupt").get(),
                              formatStrings, ArrayLength(formatStrings));
   }
@@ -1127,17 +1028,17 @@ EventSource::DispatchFailConnection()
   NS_ENSURE_STATE(event);
 
   return NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
 }
 
 void
 EventSource::FailConnection()
 {
-  if (mReadyState == nsIEventSource::CLOSED) {
+  if (mReadyState == CLOSED) {
     return;
   }
 
   nsresult rv = ConsoleError();
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to print to the console error");
   }
 
@@ -1173,17 +1074,17 @@ EventSource::FailConnection()
     NS_WARNING("Failed to dispatch the error event!!!");
     return;
   }
 }
 
 bool
 EventSource::CheckCanRequestSrc(nsIURI* aSrc)
 {
-  if (mReadyState == nsIEventSource::CLOSED) {
+  if (mReadyState == CLOSED) {
     return false;
   }
 
   bool isValidURI = false;
   bool isValidContentLoadPolicy = false;
   bool isValidProtocol = false;
 
   nsCOMPtr<nsIURI> srcToTest = aSrc ? aSrc : mSrc.get();
@@ -1233,17 +1134,17 @@ EventSource::CheckCanRequestSrc(nsIURI* 
 }
 
 // static
 void
 EventSource::TimerCallback(nsITimer* aTimer, void* aClosure)
 {
   nsRefPtr<EventSource> thisObject = static_cast<EventSource*>(aClosure);
 
-  if (thisObject->mReadyState == nsIEventSource::CLOSED) {
+  if (thisObject->mReadyState == CLOSED) {
     return;
   }
 
   NS_PRECONDITION(!thisObject->mHttpChannel,
                   "the channel hasn't been cancelled!!");
 
   if (!thisObject->mFrozen) {
     nsresult rv = thisObject->InitChannelAndRequestEventSource();
@@ -1252,17 +1153,17 @@ EventSource::TimerCallback(nsITimer* aTi
       return;
     }
   }
 }
 
 nsresult
 EventSource::Thaw()
 {
-  if (mReadyState == nsIEventSource::CLOSED || !mFrozen) {
+  if (mReadyState == CLOSED || !mFrozen) {
     return NS_OK;
   }
 
   NS_ASSERTION(!mHttpChannel, "the connection hasn't been closed!!!");
 
   mFrozen = false;
   nsresult rv;
   if (!mGoingToDispatchAllMessages && mMessagesToDispatch.GetSize() > 0) {
@@ -1280,17 +1181,17 @@ EventSource::Thaw()
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
 EventSource::Freeze()
 {
-  if (mReadyState == nsIEventSource::CLOSED || mFrozen) {
+  if (mReadyState == CLOSED || mFrozen) {
     return NS_OK;
   }
 
   NS_ASSERTION(!mHttpChannel, "the connection hasn't been closed!!!");
   mFrozen = true;
   return NS_OK;
 }
 
@@ -1336,17 +1237,17 @@ EventSource::DispatchCurrentMessageEvent
   }
 
   return NS_OK;
 }
 
 void
 EventSource::DispatchAllMessageEvents()
 {
-  if (mReadyState == nsIEventSource::CLOSED || mFrozen) {
+  if (mReadyState == CLOSED || mFrozen) {
     return;
   }
 
   mGoingToDispatchAllMessages = false;
 
   nsresult rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return;
@@ -1497,17 +1398,17 @@ EventSource::SetFieldAndClear()
   return NS_OK;
 }
 
 nsresult
 EventSource::CheckHealthOfRequestCallback(nsIRequest *aRequestCallback)
 {
   // check if we have been closed or if the request has been canceled
   // or if we have been frozen
-  if (mReadyState == nsIEventSource::CLOSED || !mHttpChannel ||
+  if (mReadyState == CLOSED || !mHttpChannel ||
       mFrozen || mErrorLoadOnRedirect) {
     return NS_ERROR_ABORT;
   }
 
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequestCallback);
   NS_ENSURE_STATE(httpChannel);
 
   if (httpChannel != mHttpChannel) {
@@ -1518,17 +1419,17 @@ EventSource::CheckHealthOfRequestCallbac
   return NS_OK;
 }
 
 nsresult
 EventSource::ParseCharacter(PRUnichar aChr)
 {
   nsresult rv;
 
-  if (mReadyState == nsIEventSource::CLOSED) {
+  if (mReadyState == CLOSED) {
     return NS_ERROR_ABORT;
   }
 
   switch (mStatus)
   {
     case PARSE_STATE_OFF:
       NS_ERROR("Invalid state");
       return NS_ERROR_FAILURE;
--- a/content/base/src/EventSource.h
+++ b/content/base/src/EventSource.h
@@ -8,18 +8,16 @@
  * spec has defined event streams only for http. HTTP is required because
  * this implementation uses some http headers: "Last-Event-ID", "Cache-Control"
  * and "Accept".
  */
 
 #ifndef mozilla_dom_EventSource_h
 #define mozilla_dom_EventSource_h
 
-#include "nsIEventSource.h"
-#include "nsIJSNativeInitializer.h"
 #include "nsDOMEventTargetHelper.h"
 #include "nsIObserver.h"
 #include "nsIStreamListener.h"
 #include "nsIChannelEventSink.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsITimer.h"
 #include "nsIHttpChannel.h"
 #include "nsWeakReference.h"
@@ -28,56 +26,98 @@
 
 #define NS_EVENTSOURCE_CID                          \
  { /* 755e2d2d-a836-4539-83f4-16b51156341f */       \
   0x755e2d2d, 0xa836, 0x4539,                       \
  {0x83, 0xf4, 0x16, 0xb5, 0x11, 0x56, 0x34, 0x1f} }
 
 #define NS_EVENTSOURCE_CONTRACTID "@mozilla.org/eventsource;1"
 
+class nsPIDOMWindow;
+
 namespace mozilla {
+
+class ErrorResult;
+
 namespace dom {
 
 class AsyncVerifyRedirectCallbackFwr;
+struct EventSourceInit;
 
 class EventSource : public nsDOMEventTargetHelper
-                  , public nsIEventSource
-                  , public nsIJSNativeInitializer
                   , public nsIObserver
                   , public nsIStreamListener
                   , public nsIChannelEventSink
                   , public nsIInterfaceRequestor
                   , public nsSupportsWeakReference
 {
 friend class AsyncVerifyRedirectCallbackFwr;
 
 public:
   EventSource();
   virtual ~EventSource();
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_INHERITED(EventSource,
                                                                    nsDOMEventTargetHelper)
 
-  NS_DECL_NSIEVENTSOURCE
-
-  // nsIJSNativeInitializer
-  NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
-                        uint32_t argc, jsval* argv);
-
   NS_DECL_NSIOBSERVER
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSICHANNELEVENTSINK
   NS_DECL_NSIINTERFACEREQUESTOR
 
+  // nsWrapperCache
+  virtual JSObject*
+  WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap) MOZ_OVERRIDE;
+
+  // WebIDL
+  nsPIDOMWindow*
+  GetParentObject() const
+  {
+    return GetOwner();
+  }
+  static already_AddRefed<EventSource>
+  Constructor(nsISupports* aOwner, const nsAString& aURL,
+              const EventSourceInit& aEventSourceInitDict,
+              ErrorResult& aRv);
+
+  void GetUrl(nsAString& aURL) const
+  {
+    aURL = mOriginalURL;
+  }
+  bool WithCredentials() const
+  {
+    return mWithCredentials;
+  }
+
+  enum {
+    CONNECTING = 0U,
+    OPEN = 1U,
+    CLOSED = 2U
+  };
+  uint16_t ReadyState() const
+  {
+    return mReadyState;
+  }
+
+  IMPL_EVENT_HANDLER(open)
+  IMPL_EVENT_HANDLER(message)
+  IMPL_EVENT_HANDLER(error)
+  void Close();
+
   // Determine if preferences allow EventSource
   static bool PrefEnabled();
 
   virtual void DisconnectFromOwner();
+
 protected:
+  nsresult Init(nsISupports* aOwner,
+                const nsAString& aURL,
+                bool aWithCredentials);
+
   nsresult GetBaseURI(nsIURI **aBaseURI);
 
   nsresult SetupHttpChannel();
   nsresult InitChannelAndRequestEventSource();
   nsresult ResetConnection();
   nsresult DispatchFailConnection();
   nsresult SetReconnectionTimeout();
 
@@ -202,17 +242,17 @@ protected:
    */
   nsCOMPtr<nsIInterfaceRequestor> mNotificationCallbacks;
   nsCOMPtr<nsIChannelEventSink>   mChannelEventSink;
 
   nsCOMPtr<nsIHttpChannel> mHttpChannel;
 
   nsCOMPtr<nsITimer> mTimer;
 
-  int32_t mReadyState;
+  uint16_t mReadyState;
   nsString mOriginalURL;
 
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsString mOrigin;
 
   uint32_t mRedirectFlags;
   nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
   nsCOMPtr<nsIChannel> mNewRedirectChannel;
--- a/content/base/test/test_bug338583.html
+++ b/content/base/test/test_bug338583.html
@@ -115,17 +115,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     return true;
   }
 
 // in order to test (1):
 //   a) if the EventSource constructor parameter is equal to its url attribute
 //   b) let its fn_onmessage, fn_event_listener_message, and fn_other_event_name functions listeners be hit four times each
 //   c) the close method (we expect readyState == CLOSED)
 //   d) the close method (we expect no message events anymore)
-//   e) if the ctor throws an exception when the second parameter is null
+//   e) use the default for withCredentials when passing dictionary arguments that don't explicitly set it
 
   function doTest1(test_id) {
     gEventSourceObj1 = new EventSource("eventsource.resource");
     ok(gEventSourceObj1.url == "http://mochi.test:8888/tests/content/base/test/eventsource.resource", "Test 1.a failed.");
     ok(gEventSourceObj1.readyState == 0 || gEventSourceObj1.readyState == 1, "Test 1.a failed.");
 
     doTest1_b(test_id);
   }
@@ -165,21 +165,23 @@ https://bugzilla.mozilla.org/show_bug.cg
       ok(!bhits, "Test 1.d failed.");
       gEventSourceObj1.close();
       setTestHasFinished(test_id);
     }, parseInt(2000*stress_factor));
   }
 
   function doTest1_e(test_id) {
     try {
-      gEventSourceObj1_e = new EventSource("eventsource.resource", null);
+      for (var options of [null, undefined, {}]) {
+        gEventSourceObj1_e = new EventSource("eventsource.resource", options);
+        is(gEventSourceObj1_e.withCredentials, false, "withCredentials should default to false");
+        gEventSourceObj1_e.close();
+      }
+    } catch (e) {
       ok(false, "Test 1.e failed");
-      gEventSourceObj1_e.close();
-    } catch (e) {
-      ok(true, "Test 1.e failed");
     }
     setTestHasFinished(test_id);
   }
 
 // in order to test (2)
 //   a) set a eventsource that give the dom events messages
 //   b) expect trusted events
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -518,17 +518,16 @@ using mozilla::dom::indexedDB::IDBWrappe
 #include "nsIDOMCanvasRenderingContext2D.h"
 #include "DOMFileHandle.h"
 #include "FileRequest.h"
 #include "LockedFile.h"
 #include "GeneratedEvents.h"
 #include "nsDebug.h"
 
 #include "mozilla/dom/BindingUtils.h"
-#include "mozilla/dom/EventSource.h"
 #include "mozilla/dom/HTMLCollectionBinding.h"
 #include "mozilla/Likely.h"
 
 #ifdef MOZ_SYS_MSG
 #include "mozilla/dom/Activity.h"
 #endif
 
 #ifdef MOZ_TIME_MANAGER
@@ -1368,19 +1367,16 @@ static nsDOMClassInfoData sClassInfoData
                            nsIXPCScriptable::DONT_ENUM_STATIC_PROPS |
                            nsIXPCScriptable::WANT_NEWENUMERATE)
   NS_DEFINE_CLASSINFO_DATA(StorageItem, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(XMLHttpProgressEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
-  NS_DEFINE_CLASSINFO_DATA(EventSource, nsEventTargetSH,
-                           EVENTTARGET_SCRIPTABLE_FLAGS)
-
   NS_DEFINE_CLASSINFO_DATA(ClientRect, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(ClientRectList, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(SVGForeignObjectElement, nsElementSH,
                            ELEMENT_SCRIPTABLE_FLAGS)
 
@@ -1673,17 +1669,16 @@ static nsDOMClassInfoData sClassInfoData
     native.forget(aInstancePtrResult);                                          \
     return rv;                                                                  \
   }
 
 NS_DEFINE_CONTRACT_CTOR(FileReader, NS_FILEREADER_CONTRACTID)
 NS_DEFINE_CONTRACT_CTOR(ArchiveReader, NS_ARCHIVEREADER_CONTRACTID)
 NS_DEFINE_CONTRACT_CTOR(XSLTProcessor,
                         "@mozilla.org/document-transformer;1?type=xslt")
-NS_DEFINE_CONTRACT_CTOR(EventSource, NS_EVENTSOURCE_CONTRACTID)
 #ifdef MOZ_SYS_MSG
 NS_DEFINE_CONTRACT_CTOR(MozActivity, NS_DOMACTIVITY_CONTRACTID)
 #endif
 
 #undef NS_DEFINE_CONTRACT_CTOR
 
 #define NS_DEFINE_EVENT_CTOR(_class)                        \
   static nsresult                                           \
@@ -1734,17 +1729,16 @@ static const nsConstructorFuncMapData kC
 #define MOZ_GENERATED_EVENT(_event_interface) \
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(_event_interface)
 #include "GeneratedEvents.h"
 #undef MOZ_GENERATED_EVENT_LIST
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozSmsFilter, sms::SmsFilter::NewSmsFilter)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(FileReader, FileReaderCtor)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(ArchiveReader, ArchiveReaderCtor)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(XSLTProcessor, XSLTProcessorCtor)
-  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(EventSource, EventSourceCtor)
 #ifdef MOZ_SYS_MSG
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozActivity, MozActivityCtor)
 #endif
 };
 #undef NS_DEFINE_CONSTRUCTOR_FUNC_DATA
 #undef NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA
 
 nsIXPConnect *nsDOMClassInfo::sXPConnect = nullptr;
@@ -3836,21 +3830,16 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XMLHttpProgressEvent, nsIDOMEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMLSProgressEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMProgressEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(EventSource, nsIEventSource)
-    DOM_CLASSINFO_MAP_ENTRY(nsIEventSource)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN(XULCommandEvent, nsIDOMXULCommandEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULCommandEvent)
     DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(CommandEvent, nsIDOMCommandEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCommandEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
@@ -6549,23 +6538,16 @@ ConstructorEnabled(const nsGlobalNameStr
              aStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfo);
 
   // Don't expose chrome only constructors to content windows.
   if (aStruct->mChromeOnly &&
       !nsContentUtils::IsSystemPrincipal(aWin->GetPrincipal())) {
     return false;
   }
 
-  // For now don't expose server events unless user has explicitly enabled them
-  if (aStruct->mDOMClassInfoID == eDOMClassInfo_EventSource_id) {
-    if (!EventSource::PrefEnabled()) {
-      return false;
-    }
-  }
-
   // Don't expose CSSSupportsRule unless @supports processing is enabled.
   if (aStruct->mDOMClassInfoID == eDOMClassInfo_CSSSupportsRule_id) {
     if (!CSSSupportsRule::PrefEnabled()) {
       return false;
     }
   }
 
   // Don't expose ArchiveReader unless user has explicitly enabled it
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -327,19 +327,16 @@ DOMCI_CLASS(XPathResult)
 // WhatWG WebApps Objects
 DOMCI_CLASS(StorageObsolete)
 DOMCI_CLASS(Storage)
 DOMCI_CLASS(StorageItem)
 
 // XMLHttpRequest
 DOMCI_CLASS(XMLHttpProgressEvent)
 
-// Server-sent events
-DOMCI_CLASS(EventSource)
-
 DOMCI_CLASS(ClientRect)
 DOMCI_CLASS(ClientRectList)
 
 DOMCI_CLASS(SVGForeignObjectElement)
 
 DOMCI_CLASS(XULCommandEvent)
 DOMCI_CLASS(CommandEvent)
 DOMCI_CLASS(OfflineResourceList)
new file mode 100644
--- /dev/null
+++ b/dom/webidl/EventSource.webidl
@@ -0,0 +1,39 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://www.whatwg.org/specs/web-apps/current-work/
+ *
+ * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
+ * Opera Software ASA. You are granted a license to use, reproduce
+ * and create derivative works of this document.
+ */
+
+[Constructor(DOMString url, optional EventSourceInit eventSourceInitDict), PrefControlled]
+interface EventSource : EventTarget {
+  [Constant]
+  readonly attribute DOMString url;
+  [Constant]
+  readonly attribute boolean withCredentials;
+
+  // ready state
+  const unsigned short CONNECTING = 0;
+  const unsigned short OPEN = 1;
+  const unsigned short CLOSED = 2;
+  readonly attribute unsigned short readyState;
+
+  // networking
+  [SetterThrows]
+           attribute EventHandler onopen;
+  [SetterThrows]
+           attribute EventHandler onmessage;
+  [SetterThrows]
+           attribute EventHandler onerror;
+  void close();
+};
+
+dictionary EventSourceInit {
+  boolean withCredentials = false;
+};
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -30,16 +30,17 @@ webidl_files = \
   DOMParser.webidl \
   DOMSettableTokenList.webidl \
   DOMStringMap.webidl \
   DOMTokenList.webidl \
   DynamicsCompressorNode.webidl \
   Element.webidl \
   EventHandler.webidl \
   EventListener.webidl \
+  EventSource.webidl \
   EventTarget.webidl \
   File.webidl \
   FileHandle.webidl \
   FileList.webidl \
   FileReaderSync.webidl \
   FormData.webidl \
   Function.webidl \
   GainNode.webidl \