Bug 537787 - Remote websockets. r=jduell
authorJosh Matthews <josh@joshmatthews.net>
Wed, 04 May 2011 15:36:23 +0200
changeset 72966 4a894d4dc4da26a41e9ef1d1fea436d10324347d
parent 72965 dbad9fdb83e6d125a3f7145288e8f75b9b3e2492
child 72967 7a747adc8303dea9846ab4a291b0394952c9eb3d
push id45
push userffxbld
push dateThu, 22 Sep 2011 17:29:26 +0000
treeherdermozilla-release@b3273da80b44 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell
bugs537787
milestone7.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 537787 - Remote websockets. r=jduell
content/base/src/nsWebSocket.cpp
ipc/ipdl/Makefile.in
netwerk/build/nsNetModule.cpp
netwerk/ipc/ChannelEventQueue.cpp
netwerk/ipc/ChannelEventQueue.h
netwerk/ipc/NeckoChild.cpp
netwerk/ipc/NeckoChild.h
netwerk/ipc/NeckoParent.cpp
netwerk/ipc/NeckoParent.h
netwerk/ipc/PNecko.ipdl
netwerk/protocol/ftp/FTPChannelChild.cpp
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/websocket/BaseWebSocketChannel.cpp
netwerk/protocol/websocket/BaseWebSocketChannel.h
netwerk/protocol/websocket/Makefile.in
netwerk/protocol/websocket/PWebSocket.ipdl
netwerk/protocol/websocket/WebSocketChannelChild.cpp
netwerk/protocol/websocket/WebSocketChannelChild.h
netwerk/protocol/websocket/WebSocketChannelParent.cpp
netwerk/protocol/websocket/WebSocketChannelParent.h
netwerk/protocol/websocket/WebSocketLog.h
netwerk/protocol/websocket/ipdl.mk
netwerk/protocol/websocket/nsWebSocketHandler.cpp
netwerk/protocol/websocket/nsWebSocketHandler.h
--- a/content/base/src/nsWebSocket.cpp
+++ b/content/base/src/nsWebSocket.cpp
@@ -1239,17 +1239,17 @@ nsWebSocket::Send(const nsAString& aData
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   *aRet = PR_FALSE;
 
   if (mReadyState == nsIWebSocket::CONNECTING) {
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
-  // We need to check if there isn't unpaired surrogates.
+  // Check for unpaired surrogates.
   PRUint32 i, length = aData.Length();
   for (i = 0; i < length; ++i) {
     if (NS_IS_LOW_SURROGATE(aData[i])) {
       return NS_ERROR_DOM_SYNTAX_ERR;
     }
     if (NS_IS_HIGH_SURROGATE(aData[i])) {
       if (i + 1 == length || !NS_IS_LOW_SURROGATE(aData[i + 1])) {
         return NS_ERROR_DOM_SYNTAX_ERR;
--- a/ipc/ipdl/Makefile.in
+++ b/ipc/ipdl/Makefile.in
@@ -62,16 +62,17 @@ IPDLDIRS =  \
   ipc/testshell  \
   js/ipc  \
   js/jetpack \
   layout/ipc \
   netwerk/ipc  \
   netwerk/protocol/ftp \
   netwerk/protocol/http  \
   netwerk/protocol/wyciwyg \
+  netwerk/protocol/websocket \
   netwerk/cookie  \
   uriloader/prefetch  \
   $(NULL)
 
 ifdef MOZ_IPDL_TESTS #{
 IPDLDIRS += ipc/ipdl/test/cxx
 endif #}
 ##-----------------------------------------------------------------------------
--- a/netwerk/build/nsNetModule.cpp
+++ b/netwerk/build/nsNetModule.cpp
@@ -59,16 +59,17 @@
 #include "nsSOCKSSocketProvider.h"
 #include "nsCacheService.h"
 #include "nsDiskCacheDeviceSQL.h"
 #include "nsApplicationCache.h"
 #include "nsMimeTypes.h"
 #include "nsNetStrings.h"
 #include "nsDNSPrefetch.h"
 #include "nsAboutProtocolHandler.h"
+#include "nsXULAppAPI.h"
 
 #include "nsNetCID.h"
 
 #if defined(XP_MACOSX)
 #if !defined(__LP64__)
 #define BUILD_APPLEFILE_DECODER 1
 #endif
 #else
@@ -278,20 +279,57 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsViewSou
 
 #ifdef NECKO_PROTOCOL_wyciwyg
 #include "nsWyciwygProtocolHandler.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsWyciwygProtocolHandler)
 #endif
 
 #ifdef NECKO_PROTOCOL_websocket
 #include "nsWebSocketHandler.h"
+#include "WebSocketChannelChild.h"
 namespace mozilla {
 namespace net {
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsWebSocketHandler)
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsWebSocketSSLHandler)
+static BaseWebSocketChannel*
+WebSocketHandlerConstructor(bool aSecure)
+{
+  if (IsNeckoChild()) {
+    return new WebSocketChannelChild(aSecure);
+  }
+
+  if (aSecure) {
+    return new nsWebSocketSSLHandler;
+  } else {
+    return new nsWebSocketHandler;
+  }
+}
+
+#define WEB_SOCKET_HANDLER_CONSTRUCTOR(type, secure)  \
+static nsresult                                       \
+type##Constructor(nsISupports *aOuter, REFNSIID aIID, \
+                  void **aResult)                     \
+{                                                     \
+  nsresult rv;                                        \
+                                                      \
+  BaseWebSocketChannel * inst;                        \
+                                                      \
+  *aResult = NULL;                                    \
+  if (NULL != aOuter) {                               \
+    rv = NS_ERROR_NO_AGGREGATION;                     \
+    return rv;                                        \
+  }                                                   \
+  inst = WebSocketHandlerConstructor(secure);         \
+  NS_ADDREF(inst);                                    \
+  rv = inst->QueryInterface(aIID, aResult);           \
+  NS_RELEASE(inst);                                   \
+  return rv;                                          \
+}
+
+WEB_SOCKET_HANDLER_CONSTRUCTOR(nsWebSocketHandler, false)
+WEB_SOCKET_HANDLER_CONSTRUCTOR(nsWebSocketSSLHandler, true)
+#undef WEB_SOCKET_HANDLER_CONSTRUCTOR
 } // namespace mozilla::net
 } // namespace mozilla
 #endif
 
 ///////////////////////////////////////////////////////////////////////////////
 
 #include "nsURIChecker.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsURIChecker)
--- a/netwerk/ipc/ChannelEventQueue.cpp
+++ b/netwerk/ipc/ChannelEventQueue.cpp
@@ -34,29 +34,29 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include "nsIChannel.h"
+#include "nsISupports.h"
 #include "mozilla/net/ChannelEventQueue.h"
 
 namespace mozilla {
 namespace net {
 
 void
 ChannelEventQueue::FlushQueue()
 {
   // Events flushed could include destruction of channel (and our own
   // destructor) unless we make sure its refcount doesn't drop to 0 while this
   // method is running.
-  nsCOMPtr<nsIChannel> kungFuDeathGrip(mOwner);
+  nsCOMPtr<nsISupports> kungFuDeathGrip(mOwner);
 
   // Prevent flushed events from flushing the queue recursively
   mFlushing = true;
 
   PRUint32 i;
   for (i = 0; i < mEventQueue.Length(); i++) {
     mEventQueue[i]->Run();
     if (mSuspended)
--- a/netwerk/ipc/ChannelEventQueue.h
+++ b/netwerk/ipc/ChannelEventQueue.h
@@ -40,17 +40,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_net_ChannelEventQueue_h
 #define mozilla_net_ChannelEventQueue_h
 
 #include <nsTArray.h>
 #include <nsAutoPtr.h>
 
-class nsIChannel;
+class nsISupports;
 
 namespace mozilla {
 namespace net {
 
 class ChannelEvent
 {
  public:
   ChannelEvent() { MOZ_COUNT_CTOR(ChannelEvent); }
@@ -65,17 +65,17 @@ class ChannelEvent
 // instance) to be dispatched and called before mListener->OnStartRequest has
 // completed.
 
 class AutoEventEnqueuerBase;
 
 class ChannelEventQueue
 {
  public:
-  ChannelEventQueue(nsIChannel *owner)
+  ChannelEventQueue(nsISupports *owner)
     : mForced(false)
     , mSuspended(false)
     , mFlushing(false)
     , mOwner(owner) {}
 
   ~ChannelEventQueue() {}
 
   // Checks to determine if an IPDL-generated channel event can be processed
@@ -111,17 +111,17 @@ class ChannelEventQueue
 
   nsTArray<nsAutoPtr<ChannelEvent> > mEventQueue;
 
   bool mForced;
   bool mSuspended;
   bool mFlushing;
 
   // Keep ptr to avoid refcount cycle: only grab ref during flushing.
-  nsIChannel *mOwner;
+  nsISupports *mOwner;
 
   friend class AutoEventEnqueuer;
 };
 
 inline bool
 ChannelEventQueue::ShouldEnqueue()
 {
   bool answer =  mForced || mSuspended || mFlushing;
--- a/netwerk/ipc/NeckoChild.cpp
+++ b/netwerk/ipc/NeckoChild.cpp
@@ -41,16 +41,17 @@
 
 #include "nsHttp.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/net/HttpChannelChild.h"
 #include "mozilla/net/CookieServiceChild.h"
 #include "mozilla/net/WyciwygChannelChild.h"
 #include "mozilla/net/FTPChannelChild.h"
+#include "mozilla/net/WebSocketChannelChild.h"
 
 namespace mozilla {
 namespace net {
 
 PNeckoChild *gNeckoChild = nsnull;
 
 // C++ file contents
 NeckoChild::NeckoChild()
@@ -162,10 +163,25 @@ NeckoChild::DeallocPWyciwygChannel(PWyci
 {
   NS_ABORT_IF_FALSE(IsNeckoChild(), "DeallocPWyciwygChannel called by non-child!");
 
   WyciwygChannelChild *p = static_cast<WyciwygChannelChild*>(channel);
   p->ReleaseIPDLReference();
   return true;
 }
 
+PWebSocketChild*
+NeckoChild::AllocPWebSocket(PBrowserChild* browser)
+{
+  NS_NOTREACHED("AllocPWebSocket should not be called");
+  return nsnull;
+}
+
+bool
+NeckoChild::DeallocPWebSocket(PWebSocketChild* child)
+{
+  WebSocketChannelChild* p = static_cast<WebSocketChannelChild*>(child);
+  p->ReleaseIPDLReference();
+  return true;
+}
+
 }} // mozilla::net
 
--- a/netwerk/ipc/NeckoChild.h
+++ b/netwerk/ipc/NeckoChild.h
@@ -62,16 +62,18 @@ protected:
   virtual PHttpChannelChild* AllocPHttpChannel(PBrowserChild* iframeEmbedding);
   virtual bool DeallocPHttpChannel(PHttpChannelChild*);
   virtual PCookieServiceChild* AllocPCookieService();
   virtual bool DeallocPCookieService(PCookieServiceChild*);
   virtual PWyciwygChannelChild* AllocPWyciwygChannel();
   virtual bool DeallocPWyciwygChannel(PWyciwygChannelChild*);
   virtual PFTPChannelChild* AllocPFTPChannel();
   virtual bool DeallocPFTPChannel(PFTPChannelChild*);
+  virtual PWebSocketChild* AllocPWebSocket(PBrowserChild*);
+  virtual bool DeallocPWebSocket(PWebSocketChild*);
 };
 
 /**
  * Reference to the PNecko Child protocol.
  * Null if this is not a content process.
  */
 extern PNeckoChild *gNeckoChild;
 
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -39,19 +39,23 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsHttp.h"
 #include "mozilla/net/NeckoParent.h"
 #include "mozilla/net/HttpChannelParent.h"
 #include "mozilla/net/CookieServiceParent.h"
 #include "mozilla/net/WyciwygChannelParent.h"
 #include "mozilla/net/FTPChannelParent.h"
+#include "mozilla/net/WebSocketChannelParent.h"
+#include "mozilla/dom/TabParent.h"
 
 #include "nsHTMLDNSPrefetch.h"
 
+using mozilla::dom::TabParent;
+
 namespace mozilla {
 namespace net {
 
 // C++ file contents
 NeckoParent::NeckoParent()
 {
 }
 
@@ -115,16 +119,33 @@ NeckoParent::AllocPWyciwygChannel()
 bool
 NeckoParent::DeallocPWyciwygChannel(PWyciwygChannelParent* channel)
 {
   WyciwygChannelParent *p = static_cast<WyciwygChannelParent *>(channel);
   p->Release();
   return true;
 }
 
+PWebSocketParent*
+NeckoParent::AllocPWebSocket(PBrowserParent* browser)
+{
+  TabParent* tabParent = static_cast<TabParent*>(browser);
+  WebSocketChannelParent* p = new WebSocketChannelParent(tabParent);
+  p->AddRef();
+  return p;
+}
+
+bool
+NeckoParent::DeallocPWebSocket(PWebSocketParent* actor)
+{
+  WebSocketChannelParent* p = static_cast<WebSocketChannelParent*>(actor);
+  p->Release();
+  return true;
+}
+
 bool
 NeckoParent::RecvHTMLDNSPrefetch(const nsString& hostname,
                                  const PRUint16& flags)
 {
   nsAutoString h(hostname);
   nsHTMLDNSPrefetch::Prefetch(h, flags);
   return true;
 }
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -59,16 +59,18 @@ protected:
   virtual PHttpChannelParent* AllocPHttpChannel(PBrowserParent* browser);
   virtual bool DeallocPHttpChannel(PHttpChannelParent*);
   virtual PCookieServiceParent* AllocPCookieService();
   virtual bool DeallocPCookieService(PCookieServiceParent*);
   virtual PWyciwygChannelParent* AllocPWyciwygChannel();
   virtual bool DeallocPWyciwygChannel(PWyciwygChannelParent*);
   virtual PFTPChannelParent* AllocPFTPChannel();
   virtual bool DeallocPFTPChannel(PFTPChannelParent*);
+  virtual PWebSocketParent* AllocPWebSocket(PBrowserParent* browser);
+  virtual bool DeallocPWebSocket(PWebSocketParent*);
   virtual bool RecvHTMLDNSPrefetch(const nsString& hostname,
                                    const PRUint16& flags);
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_NeckoParent_h
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -39,36 +39,39 @@
  * ***** END LICENSE BLOCK ***** */
 
 include protocol PContent;
 include protocol PHttpChannel;
 include protocol PCookieService;
 include protocol PBrowser;
 include protocol PWyciwygChannel;
 include protocol PFTPChannel;
+include protocol PWebSocket;
 
 namespace mozilla {
 namespace net {
 
 
 //-------------------------------------------------------------------
 sync protocol PNecko
 {
   manager PContent;
   manages PHttpChannel;
   manages PCookieService;
   manages PWyciwygChannel;
   manages PFTPChannel;
+  manages PWebSocket;
 
 parent:
   __delete__();
 
   PCookieService();
   PWyciwygChannel();
   PFTPChannel();
+  PWebSocket(PBrowser browser);
 
   HTMLDNSPrefetch(nsString hostname, PRUint16 flags);
 
 both:
   PHttpChannel(nullable PBrowser browser);
 };
 
 
--- a/netwerk/protocol/ftp/FTPChannelChild.cpp
+++ b/netwerk/protocol/ftp/FTPChannelChild.cpp
@@ -52,17 +52,17 @@
 #undef LOG
 #define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args)
 
 namespace mozilla {
 namespace net {
 
 FTPChannelChild::FTPChannelChild(nsIURI* uri)
 : mIPCOpen(false)
-, mEventQ(this)
+, mEventQ(static_cast<nsIFTPChannel*>(this))
 , mCanceled(false)
 , mSuspendCount(0)
 , mIsPending(PR_FALSE)
 , mWasOpened(PR_FALSE)
 , mLastModifiedTime(0)
 , mStartPos(0)
 {
   LOG(("Creating FTPChannelChild @%x\n", this));
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -61,17 +61,17 @@ namespace net {
 HttpChannelChild::HttpChannelChild()
   : HttpAsyncAborter<HttpChannelChild>(this)
   , mIsFromCache(PR_FALSE)
   , mCacheEntryAvailable(PR_FALSE)
   , mCacheExpirationTime(nsICache::NO_EXPIRATION_TIME)
   , mSendResumeAt(false)
   , mIPCOpen(false)
   , mKeptAlive(false)
-  , mEventQ(this)
+  , mEventQ(static_cast<nsIHttpChannel*>(this))
 {
   LOG(("Creating HttpChannelChild @%x\n", this));
 }
 
 HttpChannelChild::~HttpChannelChild()
 {
   LOG(("Destroying HttpChannelChild @%x\n", this));
 }
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/websocket/BaseWebSocketChannel.cpp
@@ -0,0 +1,222 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "WebSocketLog.h"
+#include "BaseWebSocketChannel.h"
+#include "nsWebSocketHandler.h"
+#include "nsILoadGroup.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIURI.h"
+#include "nsAutoPtr.h"
+#include "nsStandardURL.h"
+
+#if defined(PR_LOGGING)
+PRLogModuleInfo *webSocketLog = nsnull;
+#endif
+
+namespace mozilla {
+namespace net {
+
+BaseWebSocketChannel::BaseWebSocketChannel()
+  : mEncrypted(false)
+{
+#if defined(PR_LOGGING)
+  if (!webSocketLog)
+    webSocketLog = PR_NewLogModule("nsWebSocket");
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// BaseWebSocketChannel::nsIWebSocketProtocol
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+BaseWebSocketChannel::GetOriginalURI(nsIURI **aOriginalURI)
+{
+  LOG(("BaseWebSocketChannel::GetOriginalURI() %p\n", this));
+
+  if (!mOriginalURI)
+    return NS_ERROR_NOT_INITIALIZED;
+  NS_ADDREF(*aOriginalURI = mOriginalURI);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BaseWebSocketChannel::GetURI(nsIURI **aURI)
+{
+  LOG(("BaseWebSocketChannel::GetURI() %p\n", this));
+
+  if (!mOriginalURI)
+    return NS_ERROR_NOT_INITIALIZED;
+  if (mURI)
+    NS_ADDREF(*aURI = mURI);
+  else
+    NS_ADDREF(*aURI = mOriginalURI);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BaseWebSocketChannel::
+GetNotificationCallbacks(nsIInterfaceRequestor **aNotificationCallbacks)
+{
+  LOG(("BaseWebSocketChannel::GetNotificationCallbacks() %p\n", this));
+  NS_IF_ADDREF(*aNotificationCallbacks = mCallbacks);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BaseWebSocketChannel::
+SetNotificationCallbacks(nsIInterfaceRequestor *aNotificationCallbacks)
+{
+  LOG(("BaseWebSocketChannel::SetNotificationCallbacks() %p\n", this));
+  mCallbacks = aNotificationCallbacks;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BaseWebSocketChannel::GetLoadGroup(nsILoadGroup **aLoadGroup)
+{
+  LOG(("BaseWebSocketChannel::GetLoadGroup() %p\n", this));
+  NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BaseWebSocketChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
+{
+  LOG(("BaseWebSocketChannel::SetLoadGroup() %p\n", this));
+  mLoadGroup = aLoadGroup;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BaseWebSocketChannel::GetProtocol(nsACString &aProtocol)
+{
+  LOG(("BaseWebSocketChannel::GetProtocol() %p\n", this));
+  aProtocol = mProtocol;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BaseWebSocketChannel::SetProtocol(const nsACString &aProtocol)
+{
+  LOG(("BaseWebSocketChannel::SetProtocol() %p\n", this));
+  mProtocol = aProtocol;                        /* the sub protocol */
+  return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+// BaseWebSocketChannel::nsIProtocolHandler
+//-----------------------------------------------------------------------------
+
+
+NS_IMETHODIMP
+BaseWebSocketChannel::GetScheme(nsACString &aScheme)
+{
+  LOG(("BaseWebSocketHandler::GetScheme() %p\n", this));
+
+  if (mEncrypted)
+    aScheme.AssignLiteral("wss");
+  else
+    aScheme.AssignLiteral("ws");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BaseWebSocketChannel::GetDefaultPort(PRInt32 *aDefaultPort)
+{
+  LOG(("BaseWebSocketHandler::GetDefaultPort() %p\n", this));
+
+  if (mEncrypted)
+    *aDefaultPort = kDefaultWSSPort;
+  else
+    *aDefaultPort = kDefaultWSPort;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BaseWebSocketChannel::GetProtocolFlags(PRUint32 *aProtocolFlags)
+{
+  LOG(("BaseWebSocketHandler::GetProtocolFlags() %p\n", this));
+
+  *aProtocolFlags = URI_NORELATIVE | URI_NON_PERSISTABLE | ALLOWS_PROXY | 
+      ALLOWS_PROXY_HTTP | URI_DOES_NOT_RETURN_DATA | URI_DANGEROUS_TO_LOAD;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BaseWebSocketChannel::NewURI(const nsACString & aSpec, const char *aOriginCharset,
+                             nsIURI *aBaseURI, nsIURI **_retval NS_OUTPARAM)
+{
+  LOG(("BaseWebSocketHandler::NewURI() %p\n", this));
+
+  PRInt32 port;
+  nsresult rv = GetDefaultPort(&port);
+  if (NS_FAILED(rv))
+    return rv;
+
+  nsRefPtr<nsStandardURL> url = new nsStandardURL();
+  rv = url->Init(nsIStandardURL::URLTYPE_AUTHORITY, port, aSpec,
+                aOriginCharset, aBaseURI);
+  if (NS_FAILED(rv))
+    return rv;
+  NS_ADDREF(*_retval = url);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BaseWebSocketChannel::NewChannel(nsIURI *aURI, nsIChannel **_retval NS_OUTPARAM)
+{
+  LOG(("BaseWebSocketHandler::NewChannel() %p\n", this));
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+BaseWebSocketChannel::AllowPort(PRInt32 port, const char *scheme,
+                                PRBool *_retval NS_OUTPARAM)
+{
+  LOG(("BaseWebSocketHandler::AllowPort() %p\n", this));
+
+  // do not override any blacklisted ports
+  *_retval = PR_FALSE;
+  return NS_OK;
+}
+
+} // namespace net
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/websocket/BaseWebSocketChannel.h
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_net_BaseWebSocketChannel_h
+#define mozilla_net_BaseWebSocketChannel_h
+
+#include "nsIWebSocketProtocol.h"
+#include "nsIProtocolHandler.h"
+#include "nsCOMPtr.h"
+#include "nsString.h"
+
+namespace mozilla {
+namespace net {
+
+const static PRInt32 kDefaultWSPort     = 80;
+const static PRInt32 kDefaultWSSPort    = 443;
+
+class BaseWebSocketChannel : public nsIWebSocketProtocol,
+                             public nsIProtocolHandler
+{
+ public:
+  BaseWebSocketChannel();
+
+  NS_DECL_NSIPROTOCOLHANDLER
+
+  NS_IMETHOD QueryInterface(const nsIID & uuid, void **result NS_OUTPARAM) = 0;
+  NS_IMETHOD_(nsrefcnt ) AddRef(void) = 0;
+  NS_IMETHOD_(nsrefcnt ) Release(void) = 0;
+
+  // Partial implementation of nsIWebSocketProtocol
+  //
+  NS_IMETHOD GetOriginalURI(nsIURI **aOriginalURI);
+  NS_IMETHOD GetURI(nsIURI **aURI);
+  NS_IMETHOD GetNotificationCallbacks(nsIInterfaceRequestor **aNotificationCallbacks);
+  NS_IMETHOD SetNotificationCallbacks(nsIInterfaceRequestor *aNotificationCallbacks);
+  NS_IMETHOD GetLoadGroup(nsILoadGroup **aLoadGroup);
+  NS_IMETHOD SetLoadGroup(nsILoadGroup *aLoadGroup);
+  NS_IMETHOD GetProtocol(nsACString &aProtocol);
+  NS_IMETHOD SetProtocol(const nsACString &aProtocol);
+
+ protected:
+  nsCOMPtr<nsIURI>                mOriginalURI;
+  nsCOMPtr<nsIURI>                mURI;
+  nsCOMPtr<nsIWebSocketListener>  mListener;
+  nsCOMPtr<nsISupports>           mContext;
+  nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
+  nsCOMPtr<nsILoadGroup>          mLoadGroup;
+
+  nsCString                       mProtocol;
+  nsCString                       mOrigin;
+
+  PRBool                          mEncrypted;
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif // mozilla_net_BaseWebSocketChannel_h
--- a/netwerk/protocol/websocket/Makefile.in
+++ b/netwerk/protocol/websocket/Makefile.in
@@ -44,26 +44,40 @@ include $(DEPTH)/config/autoconf.mk
 
 MODULE         = necko
 LIBRARY_NAME   = nkwebsocket_s
 LIBXUL_LIBRARY = 1
 XPIDL_MODULE   = necko_websocket
 GRE_MODULE     = 1
 FORCE_STATIC_LIB = 1
 
+EXPORTS_NAMESPACES = mozilla/net
+
 XPIDLSRCS = \
   nsIWebSocketProtocol.idl \
   $(NULL)
 
 CPPSRCS = \
-  nsWebSocketHandler.cpp
+  nsWebSocketHandler.cpp \
+  WebSocketChannelParent.cpp \
+  WebSocketChannelChild.cpp \
+  BaseWebSocketChannel.cpp \
+  $(NULL)
+
+EXPORTS_mozilla/net = \
+  nsWebSocketHandler.h \
+  WebSocketChannelParent.h \
+  WebSocketChannelChild.h \
+  BaseWebSocketChannel.h \
   $(NULL)
 
 LOCAL_INCLUDES = \
   -I$(srcdir)/../../base/src \
+  -I$(topsrcdir)/content/base/src \
+  -I$(topsrcdir)/content/events/src \
   -I$(topsrcdir)/xpcom/ds \
   $(NULL)
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 DEFINES += -DIMPL_NS_NET
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/websocket/PWebSocket.ipdl
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *  The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+include protocol PNecko;
+include protocol PBrowser;
+
+include "mozilla/net/NeckoMessageUtils.h";
+
+using IPC::URI;
+
+namespace mozilla {
+namespace net {
+
+async protocol PWebSocket
+{
+  manager PNecko;
+
+parent:
+  // Forwarded methods corresponding to methods on nsIWebSocketProtocolHandler
+  AsyncOpen(URI aURI, nsCString aOrigin, nsCString aProtocol, bool aSecure);
+  Close();
+  SendMsg(nsCString aMsg);
+  SendBinaryMsg(nsCString aMsg);
+
+  DeleteSelf();
+
+child:
+  // Forwarded notifications corresponding to the nsIWebSocketListener interface
+  OnStart(nsCString aProtocol);
+  OnStop(nsresult aStatusCode);
+  OnMessageAvailable(nsCString aMsg);
+  OnBinaryMessageAvailable(nsCString aMsg);
+  OnAcknowledge(PRUint32 aSize);
+  OnServerClose();
+
+  // Only sent in the event that AsyncOpen fails
+  AsyncOpenFailed();
+
+  __delete__();
+
+};
+
+} //namespace net
+} //namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/websocket/WebSocketChannelChild.cpp
@@ -0,0 +1,446 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "WebSocketLog.h"
+#include "mozilla/dom/TabChild.h"
+#include "mozilla/net/NeckoChild.h"
+#include "WebSocketChannelChild.h"
+#include "nsITabChild.h"
+
+namespace mozilla {
+namespace net {
+
+NS_IMPL_ADDREF(WebSocketChannelChild)
+
+NS_IMETHODIMP_(nsrefcnt) WebSocketChannelChild::Release()
+{
+  NS_PRECONDITION(0 != mRefCnt, "dup release");
+  NS_ASSERT_OWNINGTHREAD(WebSocketChannelChild);
+  --mRefCnt;
+  NS_LOG_RELEASE(this, mRefCnt, "WebSocketChannelChild");
+
+  if (mRefCnt == 1 && mIPCOpen) {
+    SendDeleteSelf();
+    return mRefCnt;
+  }
+
+  if (mRefCnt == 0) {
+    mRefCnt = 1; /* stabilize */
+    delete this;
+    return 0;
+  }
+  return mRefCnt;
+}
+
+NS_INTERFACE_MAP_BEGIN(WebSocketChannelChild)
+  NS_INTERFACE_MAP_ENTRY(nsIWebSocketProtocol)
+  NS_INTERFACE_MAP_ENTRY(nsIProtocolHandler)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebSocketProtocol)
+NS_INTERFACE_MAP_END
+
+WebSocketChannelChild::WebSocketChannelChild(bool aSecure)
+: mEventQ(static_cast<nsIWebSocketProtocol*>(this))
+, mIPCOpen(false)
+, mCancelled(false)
+{
+  LOG(("WebSocketChannelChild::WebSocketChannelChild() %p\n", this));
+  BaseWebSocketChannel::mEncrypted = aSecure;
+}
+
+WebSocketChannelChild::~WebSocketChannelChild()
+{
+  LOG(("WebSocketChannelChild::~WebSocketChannelChild() %p\n", this));
+}
+
+void
+WebSocketChannelChild::AddIPDLReference()
+{
+  NS_ABORT_IF_FALSE(!mIPCOpen, "Attempt to retain more than one IPDL reference");
+  mIPCOpen = true;
+  AddRef();
+}
+
+void
+WebSocketChannelChild::ReleaseIPDLReference()
+{
+  NS_ABORT_IF_FALSE(mIPCOpen, "Attempt to release nonexistent IPDL reference");
+  mIPCOpen = false;
+  Release();
+}
+
+class StartEvent : public ChannelEvent
+{
+ public:
+  StartEvent(WebSocketChannelChild* aChild,
+             const nsCString& aProtocol)
+  : mChild(aChild)
+  , mProtocol(aProtocol)
+  {}
+
+  void Run()
+  {
+    mChild->OnStart(mProtocol);
+  }
+ private:
+  WebSocketChannelChild* mChild;
+  nsCString mProtocol;
+};
+
+bool
+WebSocketChannelChild::RecvOnStart(const nsCString& aProtocol)
+{
+  if (mEventQ.ShouldEnqueue()) {
+    mEventQ.Enqueue(new StartEvent(this, aProtocol));
+  } else {
+    OnStart(aProtocol);
+  }
+  return true;
+}
+
+void
+WebSocketChannelChild::OnStart(const nsCString& aProtocol)
+{
+  LOG(("WebSocketChannelChild::RecvOnStart() %p\n", this));
+  SetProtocol(aProtocol);
+  if (mListener) {
+    AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
+    mListener->OnStart(mContext);
+  }
+}
+
+class StopEvent : public ChannelEvent
+{
+ public:
+  StopEvent(WebSocketChannelChild* aChild,
+            const nsresult& aStatusCode)
+  : mChild(aChild)
+  , mStatusCode(aStatusCode)
+  {}
+
+  void Run()
+  {
+    mChild->OnStop(mStatusCode);
+  }
+ private:
+  WebSocketChannelChild* mChild;
+  nsresult mStatusCode;
+};
+
+bool
+WebSocketChannelChild::RecvOnStop(const nsresult& aStatusCode)
+{
+  if (mEventQ.ShouldEnqueue()) {
+    mEventQ.Enqueue(new StopEvent(this, aStatusCode));
+  } else {
+    OnStop(aStatusCode);
+  }
+  return true;
+}
+
+void
+WebSocketChannelChild::OnStop(const nsresult& aStatusCode)
+{
+  LOG(("WebSocketChannelChild::RecvOnStop() %p\n", this));
+  if (mListener) {
+    AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
+    mListener->OnStop(mContext, aStatusCode);
+  }
+}
+
+class MessageEvent : public ChannelEvent
+{
+ public:
+  MessageEvent(WebSocketChannelChild* aChild,
+               const nsCString& aMessage,
+               bool aBinary)
+  : mChild(aChild)
+  , mMessage(aMessage)
+  , mBinary(aBinary)
+  {}
+
+  void Run()
+  {
+    if (!mBinary) {
+      mChild->OnMessageAvailable(mMessage);
+    } else {
+      mChild->OnBinaryMessageAvailable(mMessage);
+    }
+  }
+ private:
+  WebSocketChannelChild* mChild;
+  nsCString mMessage;
+  bool mBinary;
+};
+
+bool
+WebSocketChannelChild::RecvOnMessageAvailable(const nsCString& aMsg)
+{
+  if (mEventQ.ShouldEnqueue()) {
+    mEventQ.Enqueue(new MessageEvent(this, aMsg, false));
+  } else {
+    OnMessageAvailable(aMsg);
+  }
+  return true;
+}
+
+void
+WebSocketChannelChild::OnMessageAvailable(const nsCString& aMsg)
+{
+  LOG(("WebSocketChannelChild::RecvOnMessageAvailable() %p\n", this));
+  if (mListener) {
+    AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
+    mListener->OnMessageAvailable(mContext, aMsg);
+  }
+}
+
+bool
+WebSocketChannelChild::RecvOnBinaryMessageAvailable(const nsCString& aMsg)
+{
+  if (mEventQ.ShouldEnqueue()) {
+    mEventQ.Enqueue(new MessageEvent(this, aMsg, true));
+  } else {
+    OnBinaryMessageAvailable(aMsg);
+  }
+  return true;
+}
+
+void
+WebSocketChannelChild::OnBinaryMessageAvailable(const nsCString& aMsg)
+{
+  LOG(("WebSocketChannelChild::RecvOnBinaryMessageAvailable() %p\n", this));
+  if (mListener) {
+    AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
+    mListener->OnBinaryMessageAvailable(mContext, aMsg);
+  }
+}
+
+class AcknowledgeEvent : public ChannelEvent
+{
+ public:
+  AcknowledgeEvent(WebSocketChannelChild* aChild,
+                   const PRUint32& aSize)
+  : mChild(aChild)
+  , mSize(aSize)
+  {}
+
+  void Run()
+  {
+    mChild->OnAcknowledge(mSize);
+  }
+ private:
+  WebSocketChannelChild* mChild;
+  PRUint32 mSize;
+};
+
+bool
+WebSocketChannelChild::RecvOnAcknowledge(const PRUint32& aSize)
+{
+  if (mEventQ.ShouldEnqueue()) {
+    mEventQ.Enqueue(new AcknowledgeEvent(this, aSize));
+  } else {
+    OnAcknowledge(aSize);
+  }
+  return true;
+}
+
+void
+WebSocketChannelChild::OnAcknowledge(const PRUint32& aSize)
+{
+  LOG(("WebSocketChannelChild::RecvOnAcknowledge() %p\n", this));
+  if (mListener) {
+    AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
+    mListener->OnAcknowledge(mContext, aSize);
+  }
+}
+
+class ServerCloseEvent : public ChannelEvent
+{
+ public:
+  ServerCloseEvent(WebSocketChannelChild* aChild)
+  : mChild(aChild)
+  {}
+
+  void Run()
+  {
+    mChild->OnServerClose();
+  }
+ private:
+  WebSocketChannelChild* mChild;
+};
+
+bool
+WebSocketChannelChild::RecvOnServerClose()
+{
+  if (mEventQ.ShouldEnqueue()) {
+    mEventQ.Enqueue(new ServerCloseEvent(this));
+  } else {
+    OnServerClose();
+  }
+  return true;
+}
+
+void
+WebSocketChannelChild::OnServerClose()
+{
+  LOG(("WebSocketChannelChild::RecvOnServerClose() %p\n", this));
+  if (mListener) {
+    AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
+    mListener->OnServerClose(mContext);
+  }
+}
+
+class AsyncOpenFailedEvent : public ChannelEvent
+{
+ public:
+  AsyncOpenFailedEvent(WebSocketChannelChild* aChild)
+  : mChild(aChild)
+  {}
+
+  void Run()
+  {
+    mChild->AsyncOpenFailed();
+  }
+ private:
+  WebSocketChannelChild* mChild;
+};
+
+bool
+WebSocketChannelChild::RecvAsyncOpenFailed()
+{
+  if (mEventQ.ShouldEnqueue()) {
+    mEventQ.Enqueue(new AsyncOpenFailedEvent(this));
+  } else {
+    AsyncOpenFailed();
+  }
+  return true;
+}
+
+void
+WebSocketChannelChild::AsyncOpenFailed()
+{
+  LOG(("WebSocketChannelChild::RecvAsyncOpenFailed() %p\n", this));
+  mCancelled = true;
+  if (mIPCOpen)
+    SendDeleteSelf();
+}
+
+NS_IMETHODIMP
+WebSocketChannelChild::AsyncOpen(nsIURI *aURI,
+                                 const nsACString &aOrigin,
+                                 nsIWebSocketListener *aListener,
+                                 nsISupports *aContext)
+{
+  LOG(("WebSocketChannelChild::AsyncOpen() %p\n", this));
+
+  NS_ABORT_IF_FALSE(aURI && aListener && !mListener, 
+                    "Invalid state for WebSocketChannelChild::AsyncOpen");
+
+  mozilla::dom::TabChild* tabChild = nsnull;
+  nsCOMPtr<nsITabChild> iTabChild;
+  NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
+                                NS_GET_IID(nsITabChild),
+                                getter_AddRefs(iTabChild));
+  if (iTabChild) {
+    tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
+  }
+
+  // Corresponding release in DeallocPWebSocket
+  AddIPDLReference();
+
+  gNeckoChild->SendPWebSocketConstructor(this, tabChild);
+  if (!SendAsyncOpen(aURI, nsCString(aOrigin), mProtocol, mEncrypted))
+    return NS_ERROR_UNEXPECTED;
+
+  mOriginalURI = aURI;
+  mURI = mOriginalURI;
+  mListener = aListener;
+  mContext = aContext;
+  mOrigin = aOrigin;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WebSocketChannelChild::Close()
+{
+  LOG(("WebSocketChannelChild::Close() %p\n", this));
+
+  if (mCancelled)
+    return NS_ERROR_UNEXPECTED;
+
+  if (!mIPCOpen || !SendClose())
+    return NS_ERROR_UNEXPECTED;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WebSocketChannelChild::SendMsg(const nsACString &aMsg)
+{
+  LOG(("WebSocketChannelChild::SendMsg() %p\n", this));
+
+  if (mCancelled)
+    return NS_ERROR_UNEXPECTED;
+
+  if (!mIPCOpen || !SendSendMsg(nsCString(aMsg)))
+    return NS_ERROR_UNEXPECTED;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WebSocketChannelChild::SendBinaryMsg(const nsACString &aMsg)
+{
+  LOG(("WebSocketChannelChild::SendBinaryMsg() %p\n", this));
+
+  if (mCancelled)
+    return NS_ERROR_UNEXPECTED;
+
+  if (!mIPCOpen || !SendSendBinaryMsg(nsCString(aMsg)))
+    return NS_ERROR_UNEXPECTED;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WebSocketChannelChild::GetSecurityInfo(nsISupports **aSecurityInfo)
+{
+  LOG(("WebSocketChannelChild::GetSecurityInfo() %p\n", this));
+  return NS_ERROR_NOT_AVAILABLE;
+}
+
+} // namespace net
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/websocket/WebSocketChannelChild.h
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_net_WebSocketChannelChild_h
+#define mozilla_net_WebSocketChannelChild_h
+
+#include "mozilla/net/PWebSocketChild.h"
+#include "mozilla/net/ChannelEventQueue.h"
+#include "mozilla/net/BaseWebSocketChannel.h"
+#include "nsCOMPtr.h"
+#include "nsString.h"
+
+namespace mozilla {
+namespace net {
+
+class WebSocketChannelChild : public BaseWebSocketChannel,
+                              public PWebSocketChild
+{
+ public:
+  WebSocketChannelChild(bool aSecure);
+  ~WebSocketChannelChild();
+
+  NS_DECL_ISUPPORTS
+
+  // nsIWebSocketProtocol methods BaseWebSocketChannel didn't implement for us
+  //
+  NS_SCRIPTABLE NS_IMETHOD AsyncOpen(nsIURI *aURI,
+                                     const nsACString &aOrigin,
+                                     nsIWebSocketListener *aListener,
+                                     nsISupports *aContext);
+  NS_SCRIPTABLE NS_IMETHOD Close();
+  NS_SCRIPTABLE NS_IMETHOD SendMsg(const nsACString &aMsg);
+  NS_SCRIPTABLE NS_IMETHOD SendBinaryMsg(const nsACString &aMsg);
+  NS_SCRIPTABLE NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo);
+
+  void AddIPDLReference();
+  void ReleaseIPDLReference();
+
+ private:
+  bool RecvOnStart(const nsCString& aProtocol);
+  bool RecvOnStop(const nsresult& aStatusCode);
+  bool RecvOnMessageAvailable(const nsCString& aMsg);
+  bool RecvOnBinaryMessageAvailable(const nsCString& aMsg);
+  bool RecvOnAcknowledge(const PRUint32& aSize);
+  bool RecvOnServerClose();
+  bool RecvAsyncOpenFailed();
+
+  void OnStart(const nsCString& aProtocol);
+  void OnStop(const nsresult& aStatusCode);
+  void OnMessageAvailable(const nsCString& aMsg);
+  void OnBinaryMessageAvailable(const nsCString& aMsg);
+  void OnAcknowledge(const PRUint32& aSize);
+  void OnServerClose();
+  void AsyncOpenFailed();  
+
+  ChannelEventQueue mEventQ;
+  bool mIPCOpen;
+  bool mCancelled;
+
+  friend class StartEvent;
+  friend class StopEvent;
+  friend class MessageEvent;
+  friend class AcknowledgeEvent;
+  friend class ServerCloseEvent;
+  friend class AsyncOpenFailedEvent;
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif // mozilla_net_WebSocketChannelChild_h
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/websocket/WebSocketChannelParent.cpp
@@ -0,0 +1,226 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "WebSocketLog.h"
+#include "WebSocketChannelParent.h"
+#include "nsIAuthPromptProvider.h"
+
+namespace mozilla {
+namespace net {
+
+NS_IMPL_THREADSAFE_ISUPPORTS2(WebSocketChannelParent,
+                              nsIWebSocketListener,
+                              nsIInterfaceRequestor)
+
+WebSocketChannelParent::WebSocketChannelParent(nsIAuthPromptProvider* aAuthProvider)
+  : mAuthProvider(aAuthProvider)
+  , mIPCOpen(true)
+{
+#if defined(PR_LOGGING)
+  if (!webSocketLog)
+    webSocketLog = PR_NewLogModule("nsWebSocket");
+#endif
+}
+
+bool
+WebSocketChannelParent::RecvDeleteSelf()
+{
+  LOG(("WebSocketChannelParent::RecvDeleteSelf() %p\n", this));
+  mChannel = nsnull;
+  mAuthProvider = nsnull;
+  return mIPCOpen ? Send__delete__(this) : true;
+}
+
+bool
+WebSocketChannelParent::RecvAsyncOpen(const IPC::URI& aURI,
+                                      const nsCString& aOrigin,
+                                      const nsCString& aProtocol,
+                                      const bool& aSecure)
+{
+  LOG(("WebSocketChannelParent::RecvAsyncOpen() %p\n", this));
+  nsresult rv;
+  if (aSecure) {
+    mChannel =
+      do_CreateInstance("@mozilla.org/network/protocol;1?name=wss", &rv);
+  } else {
+    mChannel =
+      do_CreateInstance("@mozilla.org/network/protocol;1?name=ws", &rv);
+  }
+  if (NS_FAILED(rv))
+    return CancelEarly();
+
+  rv = mChannel->SetNotificationCallbacks(this);
+  if (NS_FAILED(rv))
+    return CancelEarly();
+
+  rv = mChannel->SetProtocol(aProtocol);
+  if (NS_FAILED(rv))
+    return CancelEarly();
+
+  rv = mChannel->AsyncOpen(aURI, aOrigin, this, nsnull);
+  if (NS_FAILED(rv))
+    return CancelEarly();
+
+  return true;
+}
+
+bool
+WebSocketChannelParent::RecvClose()
+{
+  LOG(("WebSocketChannelParent::RecvClose() %p\n", this));
+  if (mChannel) {
+    nsresult rv = mChannel->Close();
+    NS_ENSURE_SUCCESS(rv, true);
+  }
+  return true;
+}
+
+bool
+WebSocketChannelParent::RecvSendMsg(const nsCString& aMsg)
+{
+  LOG(("WebSocketChannelParent::RecvSendMsg() %p\n", this));
+  if (mChannel) {
+    nsresult rv = mChannel->SendMsg(aMsg);
+    NS_ENSURE_SUCCESS(rv, true);
+  }
+  return true;
+}
+
+bool
+WebSocketChannelParent::RecvSendBinaryMsg(const nsCString& aMsg)
+{
+  LOG(("WebSocketChannelParent::RecvSendBinaryMsg() %p\n", this));
+  if (mChannel) {
+    nsresult rv = mChannel->SendBinaryMsg(aMsg);
+    NS_ENSURE_SUCCESS(rv, true);
+  }
+  return true;
+}
+
+bool
+WebSocketChannelParent::CancelEarly()
+{
+  LOG(("WebSocketChannelParent::CancelEarly() %p\n", this));
+  return mIPCOpen ? SendAsyncOpenFailed() : true;
+}
+
+NS_IMETHODIMP
+WebSocketChannelParent::GetInterface(const nsIID & iid, void **result NS_OUTPARAM)
+{
+  LOG(("WebSocketChannelParent::GetInterface() %p\n", this));
+  if (mAuthProvider && iid.Equals(NS_GET_IID(nsIAuthPromptProvider)))
+    return mAuthProvider->GetAuthPrompt(nsIAuthPromptProvider::PROMPT_NORMAL,
+                                        iid, result);
+
+  return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+WebSocketChannelParent::OnStart(nsISupports *aContext)
+{
+  LOG(("WebSocketChannelParent::OnStart() %p\n", this));
+  nsCAutoString protocol;
+  if (mChannel) {
+    mChannel->GetProtocol(protocol);
+  }
+  if (!mIPCOpen || !SendOnStart(protocol)) {
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WebSocketChannelParent::OnStop(nsISupports *aContext, nsresult aStatusCode)
+{
+  LOG(("WebSocketChannelParent::OnStop() %p\n", this));
+  if (!mIPCOpen || !SendOnStop(aStatusCode)) {
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WebSocketChannelParent::OnMessageAvailable(nsISupports *aContext, const nsACString& aMsg)
+{
+  LOG(("WebSocketChannelParent::OnMessageAvailable() %p\n", this));
+  if (!mIPCOpen || !SendOnMessageAvailable(nsCString(aMsg))) {
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WebSocketChannelParent::OnBinaryMessageAvailable(nsISupports *aContext, const nsACString& aMsg)
+{
+  LOG(("WebSocketChannelParent::OnBinaryMessageAvailable() %p\n", this));
+  if (!mIPCOpen || !SendOnBinaryMessageAvailable(nsCString(aMsg))) {
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WebSocketChannelParent::OnAcknowledge(nsISupports *aContext, PRUint32 aSize)
+{
+  LOG(("WebSocketChannelParent::OnAcknowledge() %p\n", this));
+  if (!mIPCOpen || !SendOnAcknowledge(aSize)) {
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WebSocketChannelParent::OnServerClose(nsISupports *aContext)
+{
+  LOG(("WebSocketChannelParent::OnServerClose() %p\n", this));
+  if (!mIPCOpen || !SendOnServerClose()) {
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
+void
+WebSocketChannelParent::ActorDestroy(ActorDestroyReason why)
+{
+  LOG(("WebSocketChannelParent::ActorDestroy() %p\n", this));
+  mIPCOpen = false;
+}
+
+} // namespace net
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/websocket/WebSocketChannelParent.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_net_WebSocketChannelParent_h
+#define mozilla_net_WebSocketChannelParent_h
+
+#include "mozilla/net/PWebSocketParent.h"
+#include "mozilla/net/nsWebSocketHandler.h"
+#include "nsCOMPtr.h"
+#include "nsString.h"
+
+class nsIAuthPromptProvider;
+
+namespace mozilla {
+namespace net {
+
+class WebSocketChannelParent : public PWebSocketParent,
+                               public nsIWebSocketListener,
+                               public nsIInterfaceRequestor
+{
+ public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIWEBSOCKETLISTENER
+  NS_DECL_NSIINTERFACEREQUESTOR
+
+  WebSocketChannelParent(nsIAuthPromptProvider* aAuthProvider);
+
+ private:
+  bool RecvAsyncOpen(const IPC::URI& aURI,
+                     const nsCString& aOrigin,
+                     const nsCString& aProtocol,
+                     const bool& aSecure);
+  bool RecvClose();
+  bool RecvSendMsg(const nsCString& aMsg);
+  bool RecvSendBinaryMsg(const nsCString& aMsg);
+  bool RecvDeleteSelf();
+  bool CancelEarly();
+
+  void ActorDestroy(ActorDestroyReason why);
+
+  nsCOMPtr<nsIAuthPromptProvider> mAuthProvider;
+  nsCOMPtr<nsIWebSocketProtocol> mChannel;
+  bool mIPCOpen;
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif // mozilla_net_WebSocketChannelParent_h
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/websocket/WebSocketLog.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef WebSocketLog_h
+#define WebSocketLog_h
+
+#ifdef MOZ_LOGGING
+#define FORCE_PR_LOG
+#endif
+
+#if defined(PR_LOG)
+#error "This file must be #included before any IPDL-generated files or other files that #include prlog.h"
+#endif
+
+#include "base/basictypes.h"
+#include "prlog.h"
+#include "mozilla/net/NeckoChild.h"
+
+#ifdef PR_LOGGING
+extern PRLogModuleInfo* webSocketLog;
+#endif
+
+#undef LOG
+#define LOG(args) PR_LOG(webSocketLog, PR_LOG_DEBUG, args)
+
+#endif
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/websocket/ipdl.mk
@@ -0,0 +1,40 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla Firefox.
+#
+# The Initial Developer of the Original Code is
+# The Mozilla Foundation <http://www.mozilla.org/>.
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Josh Matthews <josh@joshmatthews.net>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+IPDLSRCS =        \
+  PWebSocket.ipdl \
+  $(NULL)
--- a/netwerk/protocol/websocket/nsWebSocketHandler.cpp
+++ b/netwerk/protocol/websocket/nsWebSocketHandler.cpp
@@ -32,16 +32,17 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "WebSocketLog.h"
 #include "nsWebSocketHandler.h"
 
 #include "nsISocketTransportService.h"
 #include "nsIURI.h"
 #include "nsIChannel.h"
 #include "nsICryptoHash.h"
 #include "nsIRunnable.h"
 #include "nsIPrefBranch.h"
@@ -64,17 +65,16 @@
 #include "nsStringStream.h"
 #include "nsAlgorithm.h"
 #include "nsProxyRelease.h"
 
 #include "plbase64.h"
 #include "prmem.h"
 #include "prnetdb.h"
 #include "prbit.h"
-#include "prlog.h"
 #include "zlib.h"
 
 extern PRThread *gSocketThread;
 
 namespace mozilla {
 namespace net {
 
 NS_IMPL_THREADSAFE_ISUPPORTS11(nsWebSocketHandler,
@@ -85,21 +85,16 @@ NS_IMPL_THREADSAFE_ISUPPORTS11(nsWebSock
                                nsIProtocolHandler,
                                nsIInputStreamCallback,
                                nsIOutputStreamCallback,
                                nsITimerCallback,
                                nsIDNSListener,
                                nsIInterfaceRequestor,
                                nsIChannelEventSink)
 
-#if defined(PR_LOGGING)
-static PRLogModuleInfo *webSocketLog = nsnull;
-#endif
-#define LOG(args) PR_LOG(webSocketLog, PR_LOG_DEBUG, args)
-
 // Use this fake ptr so the Fin message stays in sequence in the
 // main transmit queue
 #define kFinMessage (reinterpret_cast<nsCString *>(0x01))
 
 // An implementation of draft-ietf-hybi-thewebsocketprotocol-08
 #define SEC_WEBSOCKET_VERSION "8"
 
 /*
@@ -485,17 +480,16 @@ private:
     PRUint8   mBuffer[kBufferLen];
 };
 
 static nsWSAdmissionManager *sWebSocketAdmissions = nsnull;
 
 // nsWebSocketHandler
 
 nsWebSocketHandler::nsWebSocketHandler() :
-    mEncrypted(PR_FALSE),
     mCloseTimeout(20000),
     mOpenTimeout(20000),
     mPingTimeout(0),
     mPingResponseTimeout(10000),
     mMaxConcurrentConnections(200),
     mRecvdHttpOnStartRequest(0),
     mRecvdHttpUpgradeTransport(0),
     mRequestedClose(0),
@@ -517,20 +511,16 @@ nsWebSocketHandler::nsWebSocketHandler()
     mBufferSize(16384),
     mCurrentOut(nsnull),
     mCurrentOutSent(0),
     mCompressor(nsnull),
     mDynamicOutputSize(0),
     mDynamicOutput(nsnull)
 {
     NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
-#if defined(PR_LOGGING)
-    if (!webSocketLog)
-        webSocketLog = PR_NewLogModule("nsWebSocket");
-#endif
 
     LOG(("WebSocketHandler::nsWebSocketHandler() %p\n", this));
     
     if (!sWebSocketAdmissions)
         sWebSocketAdmissions = new nsWSAdmissionManager();
 
     mFramePtr = mBuffer = static_cast<PRUint8 *>(moz_xmalloc(mBufferSize));
 }
@@ -1889,105 +1879,30 @@ nsWebSocketHandler::Notify(nsITimer *tim
     }
     else {
         NS_ABORT_IF_FALSE(0, "Unknown Timer");
     }
 
     return NS_OK;
 }
 
-// nsIWebSocketProtocol
-
-NS_IMETHODIMP
-nsWebSocketHandler::GetOriginalURI(nsIURI **aOriginalURI)
-{
-    LOG(("WebSocketHandler::GetOriginalURI() %p\n", this));
-
-    if (!mOriginalURI)
-        return NS_ERROR_NOT_INITIALIZED;
-    NS_ADDREF(*aOriginalURI = mOriginalURI);
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketHandler::GetURI(nsIURI **aURI)
-{
-    LOG(("WebSocketHandler::GetURI() %p\n", this));
-
-    if (!mOriginalURI)
-        return NS_ERROR_NOT_INITIALIZED;
-    if (mURI)
-        NS_ADDREF(*aURI = mURI);
-    else
-        NS_ADDREF(*aURI = mOriginalURI);
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketHandler::
-GetNotificationCallbacks(nsIInterfaceRequestor **aNotificationCallbacks)
-{
-    LOG(("WebSocketHandler::GetNotificationCallbacks() %p\n", this));
-    NS_IF_ADDREF(*aNotificationCallbacks = mCallbacks);
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketHandler::
-SetNotificationCallbacks(nsIInterfaceRequestor *aNotificationCallbacks)
-{
-    LOG(("WebSocketHandler::SetNotificationCallbacks() %p\n", this));
-    mCallbacks = aNotificationCallbacks;
-    return NS_OK;
-}
 
 NS_IMETHODIMP
 nsWebSocketHandler::GetSecurityInfo(nsISupports **aSecurityInfo)
 {
     LOG(("WebSocketHandler::GetSecurityInfo() %p\n", this));
     NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
 
     if (mTransport) {
         if (NS_FAILED(mTransport->GetSecurityInfo(aSecurityInfo)))
             *aSecurityInfo = nsnull;
     }
     return NS_OK;
 }
 
-NS_IMETHODIMP
-nsWebSocketHandler::GetLoadGroup(nsILoadGroup **aLoadGroup)
-{
-    LOG(("WebSocketHandler::GetLoadGroup() %p\n", this));
-    NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketHandler::SetLoadGroup(nsILoadGroup *aLoadGroup)
-{
-    LOG(("WebSocketHandler::SetLoadGroup() %p\n", this));
-    mLoadGroup = aLoadGroup;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketHandler::GetProtocol(nsACString &aProtocol)
-{
-    LOG(("WebSocketHandler::GetProtocol() %p\n", this));
-    aProtocol = mProtocol;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketHandler::SetProtocol(const nsACString &aProtocol)
-{
-    LOG(("WebSocketHandler::SetProtocol() %p\n", this));
-    mProtocol = aProtocol;                        /* the sub protocol */
-    return NS_OK;
-}
 
 NS_IMETHODIMP
 nsWebSocketHandler::AsyncOpen(nsIURI *aURI,
                               const nsACString &aOrigin,
                               nsIWebSocketListener *aListener,
                               nsISupports *aContext)
 {
     LOG(("WebSocketHandler::AsyncOpen() %p\n", this));
@@ -2659,84 +2574,10 @@ nsWebSocketHandler::OnDataAvailable(nsIR
     // OnStartRequest().. so we can ignore the data here
 
     LOG(("WebSocketHandler::OnDataAvailable HTTP data unexpected len>=%u\n",
          aCount));
 
     return NS_OK;
 }
 
-// nsIProtocolHandler
-
-NS_IMETHODIMP
-nsWebSocketHandler::GetScheme(nsACString &aScheme)
-{
-    LOG(("WebSocketHandler::GetScheme() %p\n", this));
-
-    if (mEncrypted)
-        aScheme.AssignLiteral("wss");
-    else
-        aScheme.AssignLiteral("ws");
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketHandler::GetDefaultPort(PRInt32 *aDefaultPort)
-{
-    LOG(("WebSocketHandler::GetDefaultPort() %p\n", this));
-
-    if (mEncrypted)
-        *aDefaultPort = kDefaultWSSPort;
-    else
-        *aDefaultPort = kDefaultWSPort;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketHandler::GetProtocolFlags(PRUint32 *aProtocolFlags)
-{
-    LOG(("WebSocketHandler::GetProtocolFlags() %p\n", this));
-
-    *aProtocolFlags = URI_NORELATIVE | URI_NON_PERSISTABLE | ALLOWS_PROXY | 
-        ALLOWS_PROXY_HTTP | URI_DOES_NOT_RETURN_DATA | URI_DANGEROUS_TO_LOAD;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketHandler::NewURI(const nsACString & aSpec, const char *aOriginCharset,
-                           nsIURI *aBaseURI, nsIURI **_retval NS_OUTPARAM)
-{
-    LOG(("WebSocketHandler::NewURI() %p\n", this));
-
-    PRInt32 port;
-    nsresult rv = GetDefaultPort(&port);
-    if (NS_FAILED(rv))
-        return rv;
-
-    nsRefPtr<nsStandardURL> url = new nsStandardURL();
-    rv = url->Init(nsIStandardURL::URLTYPE_AUTHORITY, port, aSpec,
-                   aOriginCharset, aBaseURI);
-    if (NS_FAILED(rv))
-        return rv;
-    NS_ADDREF(*_retval = url);
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWebSocketHandler::NewChannel(nsIURI *aURI, nsIChannel **_retval NS_OUTPARAM)
-{
-    LOG(("WebSocketHandler::NewChannel() %p\n", this));
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsWebSocketHandler::AllowPort(PRInt32 port, const char *scheme,
-                              PRBool *_retval NS_OUTPARAM)
-{
-    LOG(("WebSocketHandler::AllowPort() %p\n", this));
-
-    // do not override any blacklisted ports
-    *_retval = PR_FALSE;
-    return NS_OK;
-}
-
 } // namespace mozilla::net
 } // namespace mozilla
--- a/netwerk/protocol/websocket/nsWebSocketHandler.h
+++ b/netwerk/protocol/websocket/nsWebSocketHandler.h
@@ -32,16 +32,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#ifndef mozilla_net_nsWebSocketHandler_h
+#define mozilla_net_nsWebSocketHandler_h
 
 #include "nsIWebSocketProtocol.h"
 #include "nsIURI.h"
 #include "nsISupports.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIEventTarget.h"
 #include "nsIStreamListener.h"
 #include "nsIProtocolHandler.h"
@@ -52,86 +54,92 @@
 #include "nsITimer.h"
 #include "nsIDNSListener.h"
 #include "nsIHttpChannel.h"
 #include "nsIChannelEventSink.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsIStringStream.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIRandomGenerator.h"
+#include "BaseWebSocketChannel.h"
 
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsDeque.h"
 
 namespace mozilla { namespace net {
 
 class nsPostMessage;
 class nsWSAdmissionManager;
 class nsWSCompression;
 
-class nsWebSocketHandler : public nsIWebSocketProtocol,
+class nsWebSocketHandler : public BaseWebSocketChannel,
                            public nsIHttpUpgradeListener,
                            public nsIStreamListener,
-                           public nsIProtocolHandler,
                            public nsIInputStreamCallback,
                            public nsIOutputStreamCallback,
                            public nsITimerCallback,
                            public nsIDNSListener,
                            public nsIInterfaceRequestor,
                            public nsIChannelEventSink
 {
 public:
   NS_DECL_ISUPPORTS
-  NS_DECL_NSIWEBSOCKETPROTOCOL
   NS_DECL_NSIHTTPUPGRADELISTENER
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
-  NS_DECL_NSIPROTOCOLHANDLER
   NS_DECL_NSIINPUTSTREAMCALLBACK
   NS_DECL_NSIOUTPUTSTREAMCALLBACK
   NS_DECL_NSITIMERCALLBACK
   NS_DECL_NSIDNSLISTENER
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSICHANNELEVENTSINK
 
+  // nsIWebSocketProtocol methods BaseWebSocketChannel didn't implement for us
+  //
+  NS_IMETHOD AsyncOpen(nsIURI *aURI,
+                       const nsACString &aOrigin,
+                       nsIWebSocketListener *aListener,
+                       nsISupports *aContext);
+  NS_IMETHOD Close();
+  NS_IMETHOD SendMsg(const nsACString &aMsg);
+  NS_IMETHOD SendBinaryMsg(const nsACString &aMsg);
+  NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo);
+
   nsWebSocketHandler();
   static void Shutdown();
   
   enum {
       // Non Control Frames
       kContinuation = 0x0,
       kText =         0x1,
       kBinary =       0x2,
 
       // Control Frames
       kClose =        0x8,
       kPing =         0x9,
       kPong =         0xA
   };
   
   const static PRUint32 kControlFrameMask = 0x8;
-  const static PRInt32 kDefaultWSPort     = 80;
-  const static PRInt32 kDefaultWSSPort    = 443;
   const static PRUint8 kMaskBit           = 0x80;
   const static PRUint8 kFinalFragBit      = 0x80;
 
   // section 7.4.1 defines these
   const static PRUint16 kCloseNormal        = 1000;
   const static PRUint16 kCloseGoingAway     = 1001;
   const static PRUint16 kCloseProtocolError = 1002;
   const static PRUint16 kCloseUnsupported   = 1003;
   const static PRUint16 kCloseTooLarge      = 1004;
   const static PRUint16 kCloseNoStatus      = 1005;
   const static PRUint16 kCloseAbnormal      = 1006;
 
 protected:
   virtual ~nsWebSocketHandler();
-  PRBool  mEncrypted;
-  
+
 private:
   friend class nsPostMessage;
   friend class nsWSAdmissionManager;
 
   void SendMsgInternal(nsCString *aMsg, PRInt32 datalen);
   void PrimeNewOutgoingMessage();
   void GeneratePong(PRUint8 *payload, PRUint32 len);
   void GeneratePing();
@@ -191,31 +199,24 @@ private:
       { return (PRUint8 *)(mMsg ? mMsg->BeginReading() : nsnull); }
 
   private:
       nsCString *mMsg;
       PRBool     mIsControl;
       PRInt32    mBinaryLen;
   };
   
-  nsCOMPtr<nsIURI>                         mOriginalURI;
-  nsCOMPtr<nsIURI>                         mURI;
-  nsCOMPtr<nsIWebSocketListener>           mListener;
-  nsCOMPtr<nsISupports>                    mContext;
-  nsCOMPtr<nsIInterfaceRequestor>          mCallbacks;
   nsCOMPtr<nsIEventTarget>                 mSocketThread;
   nsCOMPtr<nsIHttpChannelInternal>         mChannel;
   nsCOMPtr<nsIHttpChannel>                 mHttpChannel;
   nsCOMPtr<nsILoadGroup>                   mLoadGroup;
   nsCOMPtr<nsICancelable>                  mDNSRequest;
   nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
   nsCOMPtr<nsIRandomGenerator>             mRandomGenerator;
   
-  nsCString                       mProtocol;
-  nsCString                       mOrigin;
   nsCString                       mHashedSecret;
   nsCString                       mAddress;
 
   nsCOMPtr<nsISocketTransport>    mTransport;
   nsCOMPtr<nsIAsyncInputStream>   mSocketIn;
   nsCOMPtr<nsIAsyncOutputStream>  mSocketOut;
 
   nsCOMPtr<nsITimer>              mCloseTimer;
@@ -275,14 +276,16 @@ private:
   nsWSCompression                *mCompressor;
   PRUint32                        mDynamicOutputSize;
   PRUint8                        *mDynamicOutput;
 };
 
 class nsWebSocketSSLHandler : public nsWebSocketHandler
 {
 public:
-    nsWebSocketSSLHandler() {nsWebSocketHandler::mEncrypted = PR_TRUE;}
+    nsWebSocketSSLHandler() { BaseWebSocketChannel::mEncrypted = PR_TRUE; }
 protected:
     virtual ~nsWebSocketSSLHandler() {}
 };
 
 }} // namespace mozilla::net
+
+#endif // mozilla_net_nsWebSocketHandler_h