Bug 537787 - Remote websockets. r=jduell
authorJosh Matthews <josh@joshmatthews.net>
Wed, 04 May 2011 15:36:23 +0200
changeset 72530 4a894d4dc4da26a41e9ef1d1fea436d10324347d
parent 72529 dbad9fdb83e6d125a3f7145288e8f75b9b3e2492
child 72531 7a747adc8303dea9846ab4a291b0394952c9eb3d
push id209
push userbzbarsky@mozilla.com
push dateTue, 05 Jul 2011 17:42:16 +0000
treeherdermozilla-aurora@cc6e30cce8af [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell
bugs537787
milestone7.0a1
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