Bug 885982 - Part 3: Add e10s support to TCPSocket and TCPServerSocket. r=asuth,mayhemer,bz
authorJosh Matthews <josh@joshmatthews.net>
Wed, 25 Mar 2015 10:36:56 -0400
changeset 263456 7877ab6c64ca511513120de41818fc97162ddc5d
parent 263455 2ad05ac8aac349d23626add9ffd85cbd06bd4de5
child 263457 e6895a6883048a7166d9ce5e3917da27f3fb67c7
push id29401
push userphilringnalda@gmail.com
push dateMon, 21 Sep 2015 00:50:02 +0000
treeherdermozilla-central@4013ca84d244 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth, mayhemer, bz
bugs885982
milestone43.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 885982 - Part 3: Add e10s support to TCPSocket and TCPServerSocket. r=asuth,mayhemer,bz
dom/bindings/Bindings.conf
dom/network/PTCPServerSocket.ipdl
dom/network/PTCPSocket.ipdl
dom/network/TCPServerSocket.cpp
dom/network/TCPServerSocket.h
dom/network/TCPServerSocketChild.cpp
dom/network/TCPServerSocketChild.h
dom/network/TCPServerSocketParent.cpp
dom/network/TCPServerSocketParent.h
dom/network/TCPSocket.cpp
dom/network/TCPSocket.h
dom/network/TCPSocketChild.cpp
dom/network/TCPSocketChild.h
dom/network/TCPSocketParent.cpp
dom/network/TCPSocketParent.h
dom/network/moz.build
dom/network/tests/unit/test_tcpsocket.js
dom/network/tests/unit/xpcshell.ini
dom/network/tests/unit_ipc/test_tcpsocket_ipc.js
dom/network/tests/unit_ipc/xpcshell.ini
layout/build/nsLayoutModule.cpp
netwerk/ipc/NeckoChild.cpp
netwerk/ipc/NeckoChild.h
netwerk/ipc/NeckoParent.cpp
netwerk/ipc/NeckoParent.h
netwerk/ipc/PNecko.ipdl
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1308,16 +1308,20 @@ DOMInterfaces = {
 'TextEncoder': {
     'wrapperCache': False
 },
 
 'TextMetrics': {
     'wrapperCache': False
 },
 
+'TCPSocket': {
+    'implicitJSContext': ['send']
+},
+
 'ThreadSafeChromeUtils': {
     # The codegen is dumb, and doesn't understand that this interface is only a
     # collection of static methods, so we have this `concrete: False` hack.
     'concrete': False,
     'headerFile': 'mozilla/dom/ChromeUtils.h',
     'implicitJSContext': ['readHeapSnapshot', 'saveHeapSnapshot']
 },
 
--- a/dom/network/PTCPServerSocket.ipdl
+++ b/dom/network/PTCPServerSocket.ipdl
@@ -19,16 +19,14 @@ protocol PTCPServerSocket
   manager PNecko;
 
 parent:
   Close();
   RequestDelete();
 
 child:
   CallbackAccept(PTCPSocket socket);
-  CallbackError(nsString message, nsString filename,
-                uint32_t lineNumber, uint32_t columnNumber);
   __delete__();
 };
 
 } // namespace net
 } // namespace mozilla
 
--- a/dom/network/PTCPSocket.ipdl
+++ b/dom/network/PTCPSocket.ipdl
@@ -8,21 +8,22 @@
 include protocol PNecko;
 
 include "mozilla/net/NeckoMessageUtils.h";
 
 using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 
 struct TCPError {
   nsString name;
+  nsString message;
 };
 
 union SendableData {
   uint8_t[];
-  nsString;
+  nsCString;
 };
 
 union CallbackData {
   void_t;
   SendableData;
   TCPError;
 };
 
@@ -33,17 +34,17 @@ namespace net {
 protocol PTCPSocket
 {
   manager PNecko;
 
 parent:
   // Forward calling to child's open() method to parent, expect TCPOptions
   // is expanded to |useSSL| (from TCPOptions.useSecureTransport) and
   // |binaryType| (from TCPOption.binaryType).
-  Open(nsString host, uint16_t port, bool useSSL, nsString binaryType);
+  Open(nsString host, uint16_t port, bool useSSL, bool useArrayBuffers);
 
   // When child's send() is called, this message requrests parent to send
   // data and update it's trackingNumber.
   Data(SendableData data, uint32_t trackingNumber);
 
   // Forward calling to child's upgradeToSecure() method to parent.
   StartTLS();
 
@@ -53,17 +54,17 @@ parent:
   // Forward calling to child's resume() method to parent.
   Resume();
 
   // Forward calling to child's close() method to parent.
   Close();
 
 child:
   // Forward events that are dispatched by parent.
-  Callback(nsString type, CallbackData data, nsString readyState);
+  Callback(nsString type, CallbackData data, uint32_t readyState);
 
   // Update child's bufferedAmount when parent's bufferedAmount is updated.
   // trackingNumber is also passed back to child to ensure the bufferedAmount
   // is corresponding the last call to send().
   UpdateBufferedAmount(uint32_t bufferedAmount, uint32_t trackingNumber);
 
 both:
   RequestDelete();
--- a/dom/network/TCPServerSocket.cpp
+++ b/dom/network/TCPServerSocket.cpp
@@ -1,37 +1,43 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/TCPServerSocketBinding.h"
 #include "mozilla/dom/TCPServerSocketEvent.h"
 #include "mozilla/dom/TCPSocketBinding.h"
+#include "TCPServerSocketParent.h"
+#include "TCPServerSocketChild.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/ErrorResult.h"
 #include "TCPServerSocket.h"
 #include "TCPSocket.h"
 
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(TCPServerSocket)
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(TCPServerSocket,
                                                DOMEventTargetHelper)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TCPServerSocket,
                                                   DOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServerSocket)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServerBridgeChild)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServerBridgeParent)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TCPServerSocket,
                                                 DOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mServerSocket)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mServerBridgeChild)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mServerBridgeParent)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_ADDREF_INHERITED(TCPServerSocket, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(TCPServerSocket, DOMEventTargetHelper)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TCPServerSocket)
   NS_INTERFACE_MAP_ENTRY(nsIServerSocketListener)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
@@ -47,20 +53,26 @@ TCPServerSocket::TCPServerSocket(nsIGlob
 
 TCPServerSocket::~TCPServerSocket()
 {
 }
 
 nsresult
 TCPServerSocket::Init()
 {
-  if (mServerSocket) {
+  if (mServerSocket || mServerBridgeChild) {
+    NS_WARNING("Child TCPServerSocket is already listening.");
     return NS_ERROR_FAILURE;
   }
 
+  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+    mServerBridgeChild = new TCPServerSocketChild(this, mPort, mBacklog, mUseArrayBuffers);
+    return NS_OK;
+  }
+
   nsresult rv;
   mServerSocket = do_CreateInstance("@mozilla.org/network/server-socket;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = mServerSocket->Init(mPort, false, mBacklog);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = mServerSocket->GetPort(&mPort);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = mServerSocket->AsyncListen(this);
@@ -94,16 +106,19 @@ uint16_t
 TCPServerSocket::LocalPort()
 {
   return mPort;
 }
 
 void
 TCPServerSocket::Close()
 {
+  if (mServerBridgeChild) {
+    mServerBridgeChild->Close();
+  }
   if (mServerSocket) {
     mServerSocket->Close();
   }
 }
 
 void
 TCPServerSocket::FireEvent(const nsAString& aType, TCPSocket* aSocket)
 {
@@ -115,24 +130,31 @@ TCPServerSocket::FireEvent(const nsAStri
   init.mCancelable = false;
   init.mSocket = aSocket;
 
   nsRefPtr<TCPServerSocketEvent> event =
       TCPServerSocketEvent::Constructor(this, aType, init);
   event->SetTrusted(true);
   bool dummy;
   DispatchEvent(event, &dummy);
+
+  if (mServerBridgeParent) {
+    mServerBridgeParent->OnConnect(event);
+  }
 }
 
 NS_IMETHODIMP
 TCPServerSocket::OnSocketAccepted(nsIServerSocket* aServer, nsISocketTransport* aTransport)
 {
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
-  NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
   nsRefPtr<TCPSocket> socket = TCPSocket::CreateAcceptedSocket(global, aTransport, mUseArrayBuffers);
+  if (mServerBridgeParent) {
+    socket->SetAppIdAndBrowser(mServerBridgeParent->GetAppId(),
+                               mServerBridgeParent->GetInBrowser());
+  }
   FireEvent(NS_LITERAL_STRING("connect"), socket);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TCPServerSocket::OnStopListening(nsIServerSocket* aServer, nsresult aStatus)
 {
   if (aStatus != NS_BINDING_ABORTED) {
@@ -145,13 +167,30 @@ TCPServerSocket::OnStopListening(nsIServ
 
     NS_WARNING("Server socket was closed by unexpected reason.");
     return NS_ERROR_FAILURE;
   }
   mServerSocket = nullptr;
   return NS_OK;
 }
 
+nsresult
+TCPServerSocket::AcceptChildSocket(TCPSocketChild* aSocketChild)
+{
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
+  NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
+  nsRefPtr<TCPSocket> socket = TCPSocket::CreateAcceptedSocket(global, aSocketChild, mUseArrayBuffers);
+  NS_ENSURE_TRUE(socket, NS_ERROR_FAILURE);
+  FireEvent(NS_LITERAL_STRING("connect"), socket);
+  return NS_OK;
+}
+
+void
+TCPServerSocket::SetServerBridgeParent(TCPServerSocketParent* aBridgeParent)
+{
+  mServerBridgeParent = aBridgeParent;
+}
+
 JSObject*
 TCPServerSocket::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return TCPServerSocketBinding::Wrap(aCx, this, aGivenProto);
 }
--- a/dom/network/TCPServerSocket.h
+++ b/dom/network/TCPServerSocket.h
@@ -11,16 +11,19 @@
 
 namespace mozilla {
 class ErrorResult;
 namespace dom {
 
 struct ServerSocketOptions;
 class GlobalObject;
 class TCPSocket;
+class TCPSocketChild;
+class TCPServerSocketChild;
+class TCPServerSocketParent;
 
 class TCPServerSocket final : public DOMEventTargetHelper
                             , public nsIServerSocketListener
 {
 public:
   TCPServerSocket(nsIGlobalObject* aGlobal, uint16_t aPort, bool aUseArrayBuffers,
                   uint16_t aBacklog);
 
@@ -30,37 +33,49 @@ public:
 
   nsPIDOMWindow* GetParentObject() const
   {
     return GetOwner();
   }
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
+  nsresult Init();
+
   uint16_t LocalPort();
   void Close();
 
   static already_AddRefed<TCPServerSocket>
   Constructor(const GlobalObject& aGlobal,
               uint16_t aPort,
               const ServerSocketOptions& aOptions,
               uint16_t aBacklog,
               mozilla::ErrorResult& aRv);
 
   IMPL_EVENT_HANDLER(connect);
   IMPL_EVENT_HANDLER(error);
 
+  // Relay an accepted socket notification from the parent process and
+  // initialize this object with an existing child actor for the new socket.
+  nsresult AcceptChildSocket(TCPSocketChild* aSocketChild);
+  // Associate this object with an IPC actor in the parent process to relay
+  // notifications to content processes.
+  void SetServerBridgeParent(TCPServerSocketParent* aBridgeParent);
+
 private:
   ~TCPServerSocket();
-  nsresult Init();
   // Dispatch a TCPServerSocketEvent event of a given type at this object.
   void FireEvent(const nsAString& aType, TCPSocket* aSocket);
 
   // The server socket associated with this object.
   nsCOMPtr<nsIServerSocket> mServerSocket;
+  // The IPC actor in the content process.
+  nsRefPtr<TCPServerSocketChild> mServerBridgeChild;
+  // The IPC actor in the parent process.
+  nsRefPtr<TCPServerSocketParent> mServerBridgeParent;
   int32_t mPort;
   uint16_t mBacklog;
   // True if any accepted sockets should use array buffers for received messages.
   bool mUseArrayBuffers;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/network/TCPServerSocketChild.cpp
+++ b/dom/network/TCPServerSocketChild.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TCPServerSocketChild.h"
 #include "TCPSocketChild.h"
+#include "TCPServerSocket.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/dom/PBrowserChild.h"
 #include "mozilla/dom/TabChild.h"
 #include "nsIDOMTCPSocket.h"
 #include "nsJSUtils.h"
 #include "jsfriendapi.h"
 
 using mozilla::net::gNeckoChild;
@@ -18,17 +19,16 @@ using mozilla::net::gNeckoChild;
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION(TCPServerSocketChildBase, mServerSocket)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPServerSocketChildBase)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPServerSocketChildBase)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPServerSocketChildBase)
-  NS_INTERFACE_MAP_ENTRY(nsITCPServerSocketChild)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 TCPServerSocketChildBase::TCPServerSocketChildBase()
 : mIPCOpen(false)
 {
 }
 
@@ -41,28 +41,22 @@ NS_IMETHODIMP_(MozExternalRefCountType) 
   nsrefcnt refcnt = TCPServerSocketChildBase::Release();
   if (refcnt == 1 && mIPCOpen) {
     PTCPServerSocketChild::SendRequestDelete();
     return 1;
   }
   return refcnt;
 }
 
-TCPServerSocketChild::TCPServerSocketChild()
-{
-}
-
-NS_IMETHODIMP
-TCPServerSocketChild::Listen(nsITCPServerSocketInternal* aServerSocket, uint16_t aLocalPort,
-                             uint16_t aBacklog, const nsAString & aBinaryType, JSContext* aCx)
+TCPServerSocketChild::TCPServerSocketChild(TCPServerSocket* aServerSocket, uint16_t aLocalPort,
+                                           uint16_t aBacklog, bool aUseArrayBuffers)
 {
   mServerSocket = aServerSocket;
   AddIPDLReference();
-  gNeckoChild->SendPTCPServerSocketConstructor(this, aLocalPort, aBacklog, nsString(aBinaryType));
-  return NS_OK;
+  gNeckoChild->SendPTCPServerSocketConstructor(this, aLocalPort, aBacklog, aUseArrayBuffers);
 }
 
 void
 TCPServerSocketChildBase::ReleaseIPDLReference()
 {
   MOZ_ASSERT(mIPCOpen);
   mIPCOpen = false;
   this->Release();
@@ -78,40 +72,22 @@ TCPServerSocketChildBase::AddIPDLReferen
 
 TCPServerSocketChild::~TCPServerSocketChild()
 {
 }
 
 bool
 TCPServerSocketChild::RecvCallbackAccept(PTCPSocketChild *psocket)
 {
-  TCPSocketChild* socket = static_cast<TCPSocketChild*>(psocket);
-
-  nsresult rv = mServerSocket->CallListenerAccept(static_cast<nsITCPSocketChild*>(socket));
-  if (NS_FAILED(rv)) {
-    NS_WARNING("CallListenerAccept threw exception.");
-  }
+  nsRefPtr<TCPSocketChild> socket = static_cast<TCPSocketChild*>(psocket);
+  nsresult rv = mServerSocket->AcceptChildSocket(socket);
+  NS_ENSURE_SUCCESS(rv, true);
   return true;
 }
 
-bool
-TCPServerSocketChild::RecvCallbackError(const nsString& aMessage,
-                                        const nsString& aFilename,
-                                        const uint32_t& aLineNumber,
-                                        const uint32_t& aColumnNumber)
-{
-  nsresult rv = mServerSocket->CallListenerError(aMessage, aFilename,
-                                                 aLineNumber, aColumnNumber);
-  if (NS_FAILED(rv)) {
-    NS_WARNING("CallListenerError threw exception.");
-  }
-  return true;
-}
-
-NS_IMETHODIMP
+void
 TCPServerSocketChild::Close()
 {
   SendClose();
-  return NS_OK;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/network/TCPServerSocketChild.h
+++ b/dom/network/TCPServerSocketChild.h
@@ -1,54 +1,58 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#ifndef mozilla_dom_TCPServerSocketChild_h
+#define mozilla_dom_TCPServerSocketChild_h
+
 #include "mozilla/net/PTCPServerSocketChild.h"
-#include "nsITCPServerSocketChild.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsCOMPtr.h"
 
 #define TCPSERVERSOCKETCHILD_CID \
   { 0x41a77ec8, 0xfd86, 0x409e, { 0xae, 0xa9, 0xaf, 0x2c, 0xa4, 0x07, 0xef, 0x8e } }
 
 class nsITCPServerSocketInternal;
 
 namespace mozilla {
 namespace dom {
 
-class TCPServerSocketChildBase : public nsITCPServerSocketChild {
+class TCPServerSocket;
+
+class TCPServerSocketChildBase : public nsISupports {
 public:
   NS_DECL_CYCLE_COLLECTION_CLASS(TCPServerSocketChildBase)
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   void AddIPDLReference();
   void ReleaseIPDLReference();
 
 protected:
   TCPServerSocketChildBase();
   virtual ~TCPServerSocketChildBase();
 
-  nsCOMPtr<nsITCPServerSocketInternal> mServerSocket;
+  nsRefPtr<TCPServerSocket> mServerSocket;
   bool mIPCOpen;
 };
 
 class TCPServerSocketChild : public mozilla::net::PTCPServerSocketChild
                            , public TCPServerSocketChildBase
 {
 public:
-  NS_DECL_NSITCPSERVERSOCKETCHILD
   NS_IMETHOD_(MozExternalRefCountType) Release() override;
 
-  TCPServerSocketChild();
+  TCPServerSocketChild(TCPServerSocket* aServerSocket, uint16_t aLocalPort,
+                       uint16_t aBacklog, bool aUseArrayBuffers);
   ~TCPServerSocketChild();
 
+  void Close();
+
   virtual bool RecvCallbackAccept(PTCPSocketChild *socket)  override;
-  virtual bool RecvCallbackError(const nsString& aMessage,
-                                 const nsString& aFilename,
-                                 const uint32_t& aLineNumber,
-                                 const uint32_t& aColumnNumber) override;
 };
 
 } // namespace dom
 } // namespace mozilla
+
+#endif // mozilla_dom_TCPServerSocketChild_h
--- a/dom/network/TCPServerSocketParent.cpp
+++ b/dom/network/TCPServerSocketParent.cpp
@@ -1,41 +1,32 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIScriptSecurityManager.h"
+#include "TCPServerSocket.h"
 #include "TCPServerSocketParent.h"
 #include "nsJSUtils.h"
 #include "TCPSocketParent.h"
 #include "mozilla/unused.h"
 #include "mozilla/AppProcessChecker.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/TabParent.h"
 
 namespace mozilla {
 namespace dom {
 
-static void
-FireInteralError(mozilla::net::PTCPServerSocketParent* aActor,
-                 uint32_t aLineNo)
-{
-  mozilla::unused <<
-      aActor->SendCallbackError(NS_LITERAL_STRING("Internal error"),
-                          NS_LITERAL_STRING(__FILE__), aLineNo, 0);
-}
-
-NS_IMPL_CYCLE_COLLECTION(TCPServerSocketParent, mServerSocket, mIntermediary)
+NS_IMPL_CYCLE_COLLECTION(TCPServerSocketParent, mServerSocket)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPServerSocketParent)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPServerSocketParent)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPServerSocketParent)
-  NS_INTERFACE_MAP_ENTRY(nsITCPServerSocketParent)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 void
 TCPServerSocketParent::ReleaseIPDLReference()
 {
   MOZ_ASSERT(mIPCOpen);
   mIPCOpen = false;
@@ -45,36 +36,35 @@ TCPServerSocketParent::ReleaseIPDLRefere
 void
 TCPServerSocketParent::AddIPDLReference()
 {
   MOZ_ASSERT(!mIPCOpen);
   mIPCOpen = true;
   this->AddRef();
 }
 
-bool
-TCPServerSocketParent::Init(PNeckoParent* neckoParent, const uint16_t& aLocalPort,
-                            const uint16_t& aBacklog, const nsString& aBinaryType)
+TCPServerSocketParent::TCPServerSocketParent(PNeckoParent* neckoParent,
+                                             uint16_t aLocalPort,
+                                             uint16_t aBacklog,
+                                             bool aUseArrayBuffers)
+: mNeckoParent(neckoParent)
+, mIPCOpen(false)
 {
-  mNeckoParent = neckoParent;
+  mServerSocket = new TCPServerSocket(nullptr, aLocalPort, aUseArrayBuffers, aBacklog);
+  mServerSocket->SetServerBridgeParent(this);
+}
 
-  nsresult rv;
-  mIntermediary = do_CreateInstance("@mozilla.org/tcp-socket-intermediary;1", &rv);
-  if (NS_FAILED(rv)) {
-    FireInteralError(this, __LINE__);
-    return true;
-  }
+TCPServerSocketParent::~TCPServerSocketParent()
+{
+}
 
-  rv = mIntermediary->Listen(this, aLocalPort, aBacklog, aBinaryType, GetAppId(),
-                             GetInBrowser(), getter_AddRefs(mServerSocket));
-  if (NS_FAILED(rv) || !mServerSocket) {
-    FireInteralError(this, __LINE__);
-    return true;
-  }
-  return true;
+void
+TCPServerSocketParent::Init()
+{
+  NS_ENSURE_SUCCESS_VOID(mServerSocket->Init());
 }
 
 uint32_t
 TCPServerSocketParent::GetAppId()
 {
   uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
   const PContentParent *content = Manager()->Manager();
   const InfallibleTArray<PBrowserParent*>& browsers = content->ManagedPBrowserParent();
@@ -93,23 +83,20 @@ TCPServerSocketParent::GetInBrowser()
   const InfallibleTArray<PBrowserParent*>& browsers = content->ManagedPBrowserParent();
   if (browsers.Length() > 0) {
     TabParent *tab = TabParent::GetFrom(browsers[0]);
     inBrowser = tab->IsBrowserElement();
   }
   return inBrowser;
 }
 
-NS_IMETHODIMP
-TCPServerSocketParent::SendCallbackAccept(nsITCPSocketParent *socket)
+nsresult
+TCPServerSocketParent::SendCallbackAccept(TCPSocketParent *socket)
 {
-  TCPSocketParent* _socket = static_cast<TCPSocketParent*>(socket);
-  PTCPSocketParent* _psocket = static_cast<PTCPSocketParent*>(_socket);
-
-  _socket->AddIPDLReference();
+  socket->AddIPDLReference();
 
   nsresult rv;
 
   nsString host;
   rv = socket->GetHost(host);
   if (NS_FAILED(rv)) {
     NS_ERROR("Failed to get host from nsITCPSocketParent");
     return NS_ERROR_FAILURE;
@@ -118,61 +105,62 @@ TCPServerSocketParent::SendCallbackAccep
   uint16_t port;
   rv = socket->GetPort(&port);
   if (NS_FAILED(rv)) {
     NS_ERROR("Failed to get port from nsITCPSocketParent");
     return NS_ERROR_FAILURE;
   }
 
   if (mNeckoParent) {
-    if (mNeckoParent->SendPTCPSocketConstructor(_psocket, host, port)) {
-      mozilla::unused << PTCPServerSocketParent::SendCallbackAccept(_psocket);
+    if (mNeckoParent->SendPTCPSocketConstructor(socket, host, port)) {
+      mozilla::unused << PTCPServerSocketParent::SendCallbackAccept(socket);
     }
     else {
       NS_ERROR("Sending data from PTCPSocketParent was failed.");
     };
   }
   else {
     NS_ERROR("The member value for NeckoParent is wrong.");
   }
   return NS_OK;
 }
 
-NS_IMETHODIMP
-TCPServerSocketParent::SendCallbackError(const nsAString& message,
-                                         const nsAString& filename,
-                                         uint32_t lineNumber,
-                                         uint32_t columnNumber)
-{
-  mozilla::unused <<
-    PTCPServerSocketParent::SendCallbackError(nsString(message), nsString(filename),
-                                              lineNumber, columnNumber);
-  return NS_OK;
-}
-
 bool
 TCPServerSocketParent::RecvClose()
 {
   NS_ENSURE_TRUE(mServerSocket, true);
   mServerSocket->Close();
   return true;
 }
 
 void
 TCPServerSocketParent::ActorDestroy(ActorDestroyReason why)
 {
   if (mServerSocket) {
     mServerSocket->Close();
     mServerSocket = nullptr;
   }
   mNeckoParent = nullptr;
-  mIntermediary = nullptr;
 }
 
 bool
 TCPServerSocketParent::RecvRequestDelete()
 {
   mozilla::unused << Send__delete__(this);
   return true;
 }
 
+void
+TCPServerSocketParent::OnConnect(TCPServerSocketEvent* event)
+{
+  nsRefPtr<TCPSocket> socket = event->Socket();
+  socket->SetAppIdAndBrowser(GetAppId(), GetInBrowser());
+
+  nsRefPtr<TCPSocketParent> socketParent = new TCPSocketParent();
+  socketParent->SetSocket(socket);
+
+  socket->SetSocketBridgeParent(socketParent);
+
+  SendCallbackAccept(socketParent);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/network/TCPServerSocketParent.h
+++ b/dom/network/TCPServerSocketParent.h
@@ -1,52 +1,60 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#ifndef mozilla_dom_TCPServerSocketParent_h
+#define mozilla_dom_TCPServerSocketParent_h
+
 #include "mozilla/net/PNeckoParent.h"
 #include "mozilla/net/PTCPServerSocketParent.h"
-#include "nsITCPSocketParent.h"
-#include "nsITCPServerSocketParent.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsCOMPtr.h"
-#include "nsIDOMTCPSocket.h"
 
 namespace mozilla {
 namespace dom {
 
+class TCPServerSocket;
+class TCPServerSocketEvent;
+class TCPSocketParent;
+
 class TCPServerSocketParent : public mozilla::net::PTCPServerSocketParent
-                            , public nsITCPServerSocketParent
+                            , public nsISupports
 {
 public:
   NS_DECL_CYCLE_COLLECTION_CLASS(TCPServerSocketParent)
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_NSITCPSERVERSOCKETPARENT
 
-  TCPServerSocketParent() : mNeckoParent(nullptr), mIPCOpen(false) {}
+  TCPServerSocketParent(PNeckoParent* neckoParent, uint16_t aLocalPort,
+                        uint16_t aBacklog, bool aUseArrayBuffers);
 
-  bool Init(PNeckoParent* neckoParent, const uint16_t& aLocalPort, const uint16_t& aBacklog,
-            const nsString& aBinaryType);
+  void Init();
 
   virtual bool RecvClose() override;
   virtual bool RecvRequestDelete() override;
 
   uint32_t GetAppId();
   bool GetInBrowser();
 
   void AddIPDLReference();
   void ReleaseIPDLReference();
 
+  void OnConnect(TCPServerSocketEvent* event);
+
 private:
-  ~TCPServerSocketParent() {}
+  ~TCPServerSocketParent();
+
+  nsresult SendCallbackAccept(TCPSocketParent *socket);
 
   virtual void ActorDestroy(ActorDestroyReason why) override;
 
   PNeckoParent* mNeckoParent;
-  nsCOMPtr<nsITCPSocketIntermediary> mIntermediary;
-  nsCOMPtr<nsIDOMTCPServerSocket> mServerSocket;
+  nsRefPtr<TCPServerSocket> mServerSocket;
   bool mIPCOpen;
 };
 
 } // namespace dom
 } // namespace mozilla
+
+#endif // mozilla_dom_TCPServerSocketParent_h
--- a/dom/network/TCPSocket.cpp
+++ b/dom/network/TCPSocket.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ErrorResult.h"
 #include "TCPSocket.h"
 #include "TCPServerSocket.h"
+#include "TCPSocketChild.h"
 #include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/TCPSocketBinding.h"
 #include "mozilla/dom/TCPSocketErrorEvent.h"
 #include "mozilla/dom/TCPSocketErrorEventBinding.h"
 #include "mozilla/dom/TCPSocketEvent.h"
 #include "mozilla/dom/TCPSocketEventBinding.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "nsIArrayBufferInputStream.h"
@@ -108,29 +109,33 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSocketInputStream)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSocketOutputStream)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputStreamPump)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputStreamScriptable)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputStreamBinary)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMultiplexStream)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMultiplexStreamCopier)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingDataAfterStartTLS)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSocketBridgeChild)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSocketBridgeParent)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TCPSocket,
                                                 DOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mTransport)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSocketInputStream)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSocketOutputStream)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mInputStreamPump)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mInputStreamScriptable)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mInputStreamBinary)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMultiplexStream)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMultiplexStreamCopier)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingDataAfterStartTLS)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSocketBridgeChild)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSocketBridgeParent)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_ADDREF_INHERITED(TCPSocket, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(TCPSocket, DOMEventTargetHelper)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TCPSocket)
   NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
@@ -146,17 +151,19 @@ TCPSocket::TCPSocket(nsIGlobalObject* aG
   , mReadyState(TCPReadyState::Closed)
   , mUseArrayBuffers(aUseArrayBuffers)
   , mHost(aHost)
   , mPort(aPort)
   , mSsl(aSsl)
   , mAsyncCopierActive(false)
   , mWaitingForDrain(false)
   , mInnerWindowID(0)
+  , mBufferedAmount(0)
   , mSuspendCount(0)
+  , mTrackingNumber(0)
   , mWaitingForStartTLS(false)
 #ifdef MOZ_WIDGET_GONK
   , mTxBytes(0)
   , mRxBytes(0)
   , mAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID)
   , mInBrowser(false)
 #endif
 {
@@ -232,16 +239,22 @@ TCPSocket::Init()
 {
   nsCOMPtr<nsIObserverService> obs = do_GetService("@mozilla.org/observer-service;1");
   if (obs) {
     obs->AddObserver(this, "inner-window-destroyed", true);
   }
 
   mReadyState = TCPReadyState::Connecting;
 
+  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+    mSocketBridgeChild = new TCPSocketChild(mHost, mPort);
+    mSocketBridgeChild->SendOpen(this, mSsl, mUseArrayBuffers);
+    return NS_OK;
+  }
+
   nsCOMPtr<nsISocketTransportService> sts =
     do_GetService("@mozilla.org/network/socket-transport-service;1");
 
   const char* socketTypes[1];
   if (mSsl) {
     socketTypes[0] = "ssl";
   } else {
     socketTypes[0] = "starttls";
@@ -256,16 +269,26 @@ TCPSocket::Init()
   mTransport->SetEventSink(this, mainThread);
 
   rv = CreateStream();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
+void
+TCPSocket::InitWithSocketChild(TCPSocketChild* aSocketBridge)
+{
+  mSocketBridgeChild = aSocketBridge;
+  mReadyState = TCPReadyState::Open;
+  mSocketBridgeChild->SetSocket(this);
+  mSocketBridgeChild->GetHost(mHost);
+  mSocketBridgeChild->GetPort(&mPort);
+}
+
 nsresult
 TCPSocket::InitWithTransport(nsISocketTransport* aTransport)
 {
   mTransport = aTransport;
   nsresult rv = CreateStream();
   NS_ENSURE_SUCCESS(rv, rv);
 
   mReadyState = TCPReadyState::Open;
@@ -298,16 +321,21 @@ TCPSocket::UpgradeToSecure(mozilla::Erro
   }
 
   if (mSsl) {
     return;
   }
 
   mSsl = true;
 
+  if (mSocketBridgeChild) {
+    mSocketBridgeChild->SendStartTLS();
+    return;
+  }
+
   uint32_t count = 0;
   mMultiplexStream->GetCount(&count);
   if (!count) {
     ActivateTLS();
   } else {
     mWaitingForStartTLS = true;
   }
 }
@@ -353,16 +381,21 @@ TCPSocket::EnsureCopying()
   return mMultiplexStreamCopier->AsyncCopy(callbacks, nullptr);
 }
 
 void
 TCPSocket::NotifyCopyComplete(nsresult aStatus)
 {
   mAsyncCopierActive = false;
   mMultiplexStream->RemoveStream(0);
+  if (mSocketBridgeParent) {
+    mozilla::unused << mSocketBridgeParent->SendUpdateBufferedAmount(BufferedAmount(),
+                                                                     mTrackingNumber);
+  }
+
   if (NS_FAILED(aStatus)) {
     MaybeReportErrorAndCloseIfOpen(aStatus);
     return;
   }
 
   uint32_t count;
   nsresult rv = mMultiplexStream->GetCount(&count);
   NS_ENSURE_SUCCESS_VOID(rv);
@@ -385,17 +418,19 @@ TCPSocket::NotifyCopyComplete(nsresult a
         mMultiplexStream->AppendStream(stream);
         mPendingDataAfterStartTLS.RemoveElementAt(0);
       }
       EnsureCopying();
       return;
     }
   }
 
-  if (mWaitingForDrain) {
+  // If we have a connected child, we let the child decide whether
+  // ondrain should be dispatched.
+  if (mWaitingForDrain && !mSocketBridgeParent) {
     mWaitingForDrain = false;
     FireEvent(NS_LITERAL_STRING("drain"));
   }
 
   if (mReadyState == TCPReadyState::Closing) {
     mSocketOutputStream->Close();
     mReadyState = TCPReadyState::Closed;
     FireEvent(NS_LITERAL_STRING("close"));
@@ -411,43 +446,55 @@ TCPSocket::ActivateTLS()
   if (socketControl) {
     socketControl->StartTLS();
   }
 }
 
 void
 TCPSocket::FireErrorEvent(const nsAString& aName, const nsAString& aType)
 {
+  if (mSocketBridgeParent) {
+    mSocketBridgeParent->FireErrorEvent(aName, aType, mReadyState);
+    return;
+  }
+
   TCPSocketErrorEventInit init;
   init.mBubbles = false;
   init.mCancelable = false;
   init.mName = aName;
   init.mMessage = aType;
 
   nsRefPtr<TCPSocketErrorEvent> event =
     TCPSocketErrorEvent::Constructor(this, NS_LITERAL_STRING("error"), init);
   event->SetTrusted(true);
   bool dummy;
   DispatchEvent(event, &dummy);
 }
 
 void
 TCPSocket::FireEvent(const nsAString& aType)
 {
+  if (mSocketBridgeParent) {
+    mSocketBridgeParent->FireEvent(aType, mReadyState);
+    return;
+  }
+
   AutoJSAPI api;
   if (NS_WARN_IF(!api.Init(GetOwner()))) {
     return;
   }
   JS::Rooted<JS::Value> val(api.cx());
   FireDataEvent(api.cx(), aType, val);
 }
 
 void
 TCPSocket::FireDataEvent(JSContext* aCx, const nsAString& aType, JS::Handle<JS::Value> aData)
 {
+  MOZ_ASSERT(!mSocketBridgeParent);
+
   RootedDictionary<TCPSocketEventInit> init(aCx);
   init.mBubbles = false;
   init.mCancelable = false;
   init.mData = aData;
 
   nsRefPtr<TCPSocketEvent> event =
     TCPSocketEvent::Constructor(this, aType, init);
   event->SetTrusted(true);
@@ -477,36 +524,47 @@ bool
 TCPSocket::Ssl()
 {
   return mSsl;
 }
 
 uint64_t
 TCPSocket::BufferedAmount()
 {
+  if (mSocketBridgeChild) {
+    return mBufferedAmount;
+  }
   if (mMultiplexStream) {
     uint64_t available = 0;
     mMultiplexStream->Available(&available);
     return available;
   }
   return 0;
 }
 
 void
 TCPSocket::Suspend()
 {
+  if (mSocketBridgeChild) {
+    mSocketBridgeChild->SendSuspend();
+    return;
+  }
   if (mInputStreamPump) {
     mInputStreamPump->Suspend();
   }
   mSuspendCount++;
 }
 
 void
 TCPSocket::Resume(mozilla::ErrorResult& aRv)
 {
+  if (mSocketBridgeChild) {
+    mSocketBridgeChild->SendResume();
+    return;
+  }
   if (!mSuspendCount) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   if (mInputStreamPump) {
     mInputStreamPump->Resume();
   }
@@ -640,91 +698,140 @@ void
 TCPSocket::Close()
 {
   if (mReadyState == TCPReadyState::Closed || mReadyState == TCPReadyState::Closing) {
     return;
   }
 
   mReadyState = TCPReadyState::Closing;
 
+  if (mSocketBridgeChild) {
+    mSocketBridgeChild->SendClose();
+    return;
+  }
+
   uint32_t count = 0;
   mMultiplexStream->GetCount(&count);
   if (!count) {
     mSocketOutputStream->Close();
   }
   mSocketInputStream->Close();
 }
 
+void
+TCPSocket::SendWithTrackingNumber(const nsACString& aData,
+                                  const uint32_t& aTrackingNumber,
+                                  mozilla::ErrorResult& aRv)
+{
+  MOZ_ASSERT(mSocketBridgeParent);
+  mTrackingNumber = aTrackingNumber;
+  // The JSContext isn't necessary for string values; it's a codegen limitation.
+  Send(nullptr, aData, aRv);
+}
+
 bool
-TCPSocket::Send(const nsACString& aData, mozilla::ErrorResult& aRv)
+TCPSocket::Send(JSContext* aCx, const nsACString& aData, mozilla::ErrorResult& aRv)
 {
   if (mReadyState != TCPReadyState::Open) {
     aRv.Throw(NS_ERROR_FAILURE);
     return false;
   }
 
+  uint64_t byteLength;
   nsCOMPtr<nsIInputStream> stream;
-  nsresult rv = NS_NewCStringInputStream(getter_AddRefs(stream), aData);
-  if (NS_FAILED(rv)) {
-    aRv.Throw(rv);
-    return false;
-  }
-  uint64_t byteLength;
-  rv = stream->Available(&byteLength);
-  if (NS_FAILED(rv)) {
-    aRv.Throw(rv);
-    return false;
+  if (mSocketBridgeChild) {
+    mSocketBridgeChild->SendSend(aData, ++mTrackingNumber);
+    byteLength = aData.Length();
+  } else {
+    nsresult rv = NS_NewCStringInputStream(getter_AddRefs(stream), aData);
+    if (NS_FAILED(rv)) {
+      aRv.Throw(rv);
+      return false;
+    }
+    rv = stream->Available(&byteLength);
+    if (NS_FAILED(rv)) {
+      aRv.Throw(rv);
+      return false;
+    }
   }
   return Send(stream, byteLength);
 }
 
+void
+TCPSocket::SendWithTrackingNumber(JSContext* aCx,
+                                  const ArrayBuffer& aData,
+                                  uint32_t aByteOffset,
+                                  const Optional<uint32_t>& aByteLength,
+                                  const uint32_t& aTrackingNumber,
+                                  mozilla::ErrorResult& aRv)
+{
+  MOZ_ASSERT(mSocketBridgeParent);
+  mTrackingNumber = aTrackingNumber;
+  Send(aCx, aData, aByteOffset, aByteLength, aRv);
+}
+
 bool
-TCPSocket::Send(const ArrayBuffer& aData,
+TCPSocket::Send(JSContext* aCx,
+                const ArrayBuffer& aData,
                 uint32_t aByteOffset,
                 const Optional<uint32_t>& aByteLength,
                 mozilla::ErrorResult& aRv)
 {
-  AutoJSAPI api;
-  if (!api.Init(GetOwner()) ||
-      mReadyState != TCPReadyState::Open) {
+  if (mReadyState != TCPReadyState::Open) {
     aRv.Throw(NS_ERROR_FAILURE);
     return false;
   }
 
+  nsCOMPtr<nsIArrayBufferInputStream> stream;
+
   aData.ComputeLengthAndData();
   uint32_t byteLength = aByteLength.WasPassed() ? aByteLength.Value() : aData.Length();
 
-  JS::Rooted<JSObject*> obj(api.cx(), aData.Obj());
-  JSAutoCompartment ac(api.cx(), obj);
-  JS::Rooted<JS::Value> value(api.cx(), JS::ObjectValue(*obj));
+  if (mSocketBridgeChild) {
+    nsresult rv = mSocketBridgeChild->SendSend(aData, aByteOffset, byteLength, ++mTrackingNumber);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      aRv.Throw(rv);
+      return false;
+    }
+  } else {
+    JS::Rooted<JSObject*> obj(aCx, aData.Obj());
+    JSAutoCompartment ac(aCx, obj);
+    JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*obj));
 
-  nsCOMPtr<nsIArrayBufferInputStream> stream =
-      do_CreateInstance("@mozilla.org/io/arraybuffer-input-stream;1");
-  nsresult rv = stream->SetData(value, aByteOffset, byteLength, api.cx());
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(rv);
-    return false;
+    stream = do_CreateInstance("@mozilla.org/io/arraybuffer-input-stream;1");
+    nsresult rv = stream->SetData(value, aByteOffset, byteLength, aCx);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      aRv.Throw(rv);
+      return false;
+    }
   }
-
   return Send(stream, byteLength);
 }
 
 bool
 TCPSocket::Send(nsIInputStream* aStream, uint32_t aByteLength)
 {
-  bool bufferFull = BufferedAmount() + aByteLength > BUFFER_SIZE;
+  uint64_t newBufferedAmount = BufferedAmount() + aByteLength;
+  bool bufferFull = newBufferedAmount > BUFFER_SIZE;
   if (bufferFull) {
     // If we buffered more than some arbitrary amount of data,
     // (65535 right now) we should tell the caller so they can
     // wait until ondrain is called if they so desire. Once all the
     // buffered data has been written to the socket, ondrain is
     // called.
     mWaitingForDrain = true;
   }
 
+  if (mSocketBridgeChild) {
+    // In the child, we just add the buffer length to our bufferedAmount and let
+    // the parent update our bufferedAmount when the data have been sent.
+    mBufferedAmount = newBufferedAmount;
+    return !bufferFull;
+  }
+
   if (mWaitingForStartTLS) {
     // When we are waiting for starttls, newStream is added to pendingData
     // and will be appended to multiplexStream after tls had been set up.
     mPendingDataAfterStartTLS.AppendElement(aStream);
   } else {
     mMultiplexStream->AppendStream(aStream);
   }
 
@@ -762,16 +869,26 @@ TCPSocket::CreateAcceptedSocket(nsIGloba
 {
   nsRefPtr<TCPSocket> socket = new TCPSocket(aGlobal, EmptyString(), 0, false, aUseArrayBuffers);
   nsresult rv = socket->InitWithTransport(aTransport);
   NS_ENSURE_SUCCESS(rv, nullptr);
   return socket.forget();
 }
 
 already_AddRefed<TCPSocket>
+TCPSocket::CreateAcceptedSocket(nsIGlobalObject* aGlobal,
+                                TCPSocketChild* aBridge,
+                                bool aUseArrayBuffers)
+{
+  nsRefPtr<TCPSocket> socket = new TCPSocket(aGlobal, EmptyString(), 0, false, aUseArrayBuffers);
+  socket->InitWithSocketChild(aBridge);
+  return socket.forget();
+}
+
+already_AddRefed<TCPSocket>
 TCPSocket::Constructor(const GlobalObject& aGlobal,
                        const nsAString& aHost,
                        uint16_t aPort,
                        const SocketOptions& aOptions,
                        mozilla::ErrorResult& aRv)
 {
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   nsRefPtr<TCPSocket> socket =
@@ -840,53 +957,71 @@ TCPSocket::OnStartRequest(nsIRequest* aR
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TCPSocket::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, nsIInputStream* aStream,
                            uint64_t aOffset, uint32_t aCount)
 {
-  AutoJSAPI api;
-  if (!api.Init(GetOwner())) {
-    return NS_ERROR_FAILURE;
-  }
-  JSContext* cx = api.cx();
+#ifdef MOZ_WIDGET_GONK
+  // Collect received amount for network statistics.
+  mRxBytes += aCount;
+  SaveNetworkStats(false);
+#endif
 
   if (mUseArrayBuffers) {
     nsTArray<uint8_t> buffer;
     buffer.SetCapacity(aCount);
     uint32_t actual;
     nsresult rv = aStream->Read(reinterpret_cast<char*>(buffer.Elements()), aCount, &actual);
     NS_ENSURE_SUCCESS(rv, rv);
     MOZ_ASSERT(actual == aCount);
     buffer.SetLength(actual);
 
+    if (mSocketBridgeParent) {
+      mSocketBridgeParent->FireArrayBufferDataEvent(buffer, mReadyState);
+      return NS_OK;
+    }
+
+    AutoJSAPI api;
+    if (!api.Init(GetOwner())) {
+      return NS_ERROR_FAILURE;
+    }
+    JSContext* cx = api.cx();
+
     JS::Rooted<JS::Value> value(cx);
     if (!ToJSValue(cx, TypedArrayCreator<Uint8Array>(buffer), &value)) {
       return NS_ERROR_FAILURE;
     }
     FireDataEvent(cx, NS_LITERAL_STRING("data"), value);
-  } else {
-    nsCString data;
-    nsresult rv = mInputStreamScriptable->ReadBytes(aCount, data);
-    NS_ENSURE_SUCCESS(rv, rv);
+    return NS_OK;
+  }
 
-    JS::Rooted<JS::Value> value(cx);
-    if (!ToJSValue(cx, NS_ConvertASCIItoUTF16(data), &value)) {
-      return NS_ERROR_FAILURE;
-    }
-    FireDataEvent(cx, NS_LITERAL_STRING("data"), value);
+  nsCString data;
+  nsresult rv = mInputStreamScriptable->ReadBytes(aCount, data);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (mSocketBridgeParent) {
+    mSocketBridgeParent->FireStringDataEvent(data, mReadyState);
+    return NS_OK;
   }
 
-#ifdef MOZ_WIDGET_GONK
-  // Collect received amount for network statistics.
-  mRxBytes += aCount;
-  SaveNetworkStats(false);
-#endif
+  AutoJSAPI api;
+  if (!api.Init(GetOwner())) {
+    return NS_ERROR_FAILURE;
+  }
+  JSContext* cx = api.cx();
+
+  JS::Rooted<JS::Value> value(cx);
+  if (!ToJSValue(cx, NS_ConvertASCIItoUTF16(data), &value)) {
+    return NS_ERROR_FAILURE;
+  }
+  FireDataEvent(cx, NS_LITERAL_STRING("data"), value);
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TCPSocket::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, nsresult aStatus)
 {
   uint32_t count;
   nsresult rv = mMultiplexStream->GetCount(&count);
@@ -904,16 +1039,53 @@ TCPSocket::OnStopRequest(nsIRequest* aRe
     return NS_OK;
   }
 
   // We call this even if there is no error.
   MaybeReportErrorAndCloseIfOpen(aStatus);
   return NS_OK;
 }
 
+void
+TCPSocket::SetSocketBridgeParent(TCPSocketParent* aBridgeParent)
+{
+  mSocketBridgeParent = aBridgeParent;
+}
+
+void
+TCPSocket::SetAppIdAndBrowser(uint32_t aAppId, bool aInBrowser)
+{
+#ifdef MOZ_WIDGET_GONK
+  mAppId = aAppId;
+  mInBrowser = aInBrowser;
+#endif
+}
+
+void
+TCPSocket::UpdateReadyState(uint32_t aReadyState)
+{
+  MOZ_ASSERT(mSocketBridgeChild);
+  mReadyState = static_cast<TCPReadyState>(aReadyState);
+}
+
+void
+TCPSocket::UpdateBufferedAmount(uint32_t aBufferedAmount, uint32_t aTrackingNumber)
+{
+  if (aTrackingNumber != mTrackingNumber) {
+    return;
+  }
+  mBufferedAmount = aBufferedAmount;
+  if (!mBufferedAmount) {
+    if (mWaitingForDrain) {
+      mWaitingForDrain = false;
+      FireEvent(NS_LITERAL_STRING("drain"));
+    }
+  }
+}
+
 #ifdef MOZ_WIDGET_GONK
 void
 TCPSocket::SaveNetworkStats(bool aEnforce)
 {
   if (!mTxBytes && !mRxBytes) {
     // There is no traffic at all. No need to save statistics.
     return;
   }
--- a/dom/network/TCPSocket.h
+++ b/dom/network/TCPSocket.h
@@ -27,17 +27,18 @@ class nsINetworkInfo;
 
 namespace mozilla {
 class ErrorResult;
 namespace dom {
 
 class DOMError;
 struct ServerSocketOptions;
 class TCPServerSocket;
-class USVStringOrArrayBuffer;
+class TCPSocketChild;
+class TCPSocketParent;
 
 // This interface is only used for legacy navigator.mozTCPSocket API compatibility.
 class LegacyMozTCPSocket : public nsISupports
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(LegacyMozTCPSocket)
 
@@ -93,87 +94,121 @@ public:
 
   void GetHost(nsAString& aHost);
   uint32_t Port();
   bool Ssl();
   uint64_t BufferedAmount();
   void Suspend();
   void Resume(ErrorResult& aRv);
   void Close();
-  bool Send(const nsCString& aData, ErrorResult& aRv);
-  bool Send(const ArrayBuffer& aData,
+  bool Send(JSContext* aCx, const nsACString& aData, ErrorResult& aRv);
+  bool Send(JSContext* aCx,
+            const ArrayBuffer& aData,
             uint32_t aByteOffset,
             const Optional<uint32_t>& aByteLength,
             ErrorResult& aRv);
   TCPReadyState ReadyState();
   TCPSocketBinaryType BinaryType();
   void UpgradeToSecure(ErrorResult& aRv);
 
   static already_AddRefed<TCPSocket>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aHost,
               uint16_t aPort,
               const SocketOptions& aOptions,
               ErrorResult& aRv);
 
+  // Perform a send operation that's asssociated with a sequence number. Used in
+  // IPC scenarios to track the number of bytes buffered at any given time.
+  void SendWithTrackingNumber(const nsACString& aData,
+                              const uint32_t& aTrackingNumber,
+                              ErrorResult& aRv);
+  void SendWithTrackingNumber(JSContext* aCx,
+                              const ArrayBuffer& aData,
+                              uint32_t aByteOffset,
+                              const Optional<uint32_t>& aByteLength,
+                              const uint32_t& aTrackingNumber,
+                              ErrorResult& aRv);
   // Create a TCPSocket object from an existing low-level socket connection.
   // Used by the TCPServerSocket implementation when a new connection is accepted.
   static already_AddRefed<TCPSocket>
   CreateAcceptedSocket(nsIGlobalObject* aGlobal, nsISocketTransport* aTransport, bool aUseArrayBuffers);
+  // Create a TCPSocket object from an existing child-side IPC actor.
+  // Used by the TCPServerSocketChild implementation when a new connection is accepted.
+  static already_AddRefed<TCPSocket>
+  CreateAcceptedSocket(nsIGlobalObject* aGlobal, TCPSocketChild* aSocketBridge, bool aUseArrayBuffers);
+
+  // Initialize this socket's associated app and browser information.
+  void SetAppIdAndBrowser(uint32_t aAppId, bool aInBrowser);
+  // Initialize this socket's associated IPC actor in the parent process.
+  void SetSocketBridgeParent(TCPSocketParent* aBridgeParent);
 
   static bool SocketEnabled();
 
   IMPL_EVENT_HANDLER(open);
   IMPL_EVENT_HANDLER(drain);
   IMPL_EVENT_HANDLER(data);
   IMPL_EVENT_HANDLER(error);
   IMPL_EVENT_HANDLER(close);
 
   nsresult Init();
 
   // Inform this socket that a buffered send() has completed sending.
   void NotifyCopyComplete(nsresult aStatus);
 
+  // Set this child socket's number of buffered bytes, based on the count from the parent
+  // process associated with the given sequence id.
+  void UpdateBufferedAmount(uint32_t aAmount, uint32_t aTrackingNumber);
+  // Set this child socket's ready state, based on the state in the parent process.
+  void UpdateReadyState(uint32_t aReadyState);
+  // Dispatch an "error" event at this object.
+  void FireErrorEvent(const nsAString& aName, const nsAString& aMessage);
+  // Dispatch an event of the given type at this object.
+  void FireEvent(const nsAString& aType);
+  // Dispatch a "data" event at this object.
+  void FireDataEvent(JSContext* aCx, const nsAString& aType, JS::Handle<JS::Value> aData);
+
 private:
   ~TCPSocket();
 
+  // Initialize this socket with an existing IPC actor.
+  void InitWithSocketChild(TCPSocketChild* aBridge);
   // Initialize this socket from an existing low-level connection.
   nsresult InitWithTransport(nsISocketTransport* aTransport);
   // Initialize the input/output streams for this socket object.
   nsresult CreateStream();
   // Initialize the asynchronous read operation from this socket's input stream.
   nsresult CreateInputStreamPump();
   // Send the contents of the provided input stream, which is assumed to be the given length
   // for reporting and buffering purposes.
   bool Send(nsIInputStream* aStream, uint32_t aByteLength);
   // Begin an asynchronous copy operation if one is not already in progress.
   nsresult EnsureCopying();
   // Enable TLS on this socket.
   void ActivateTLS();
-  // Dispatch an "error" event at this object.
-  void FireErrorEvent(const nsAString& aName, const nsAString& aMessage);
-  // Dispatch an event of the given type at this object.
-  void FireEvent(const nsAString& aType);
-  // Dispatch a "data" event at this object.
-  void FireDataEvent(JSContext* aCx, const nsAString& aType, JS::Handle<JS::Value> aData);
   // Dispatch an error event if necessary, then dispatch a "close" event.
   nsresult MaybeReportErrorAndCloseIfOpen(nsresult status);
 #ifdef MOZ_WIDGET_GONK
   // Store and reset any saved network stats for this socket.
   void SaveNetworkStats(bool aEnforce);
 #endif
 
   TCPReadyState mReadyState;
   // Whether to use strings or array buffers for the "data" event.
   bool mUseArrayBuffers;
   nsString mHost;
   uint16_t mPort;
   // Whether this socket is using a secure transport.
   bool mSsl;
 
+  // The associated IPC actor in a child process.
+  nsRefPtr<TCPSocketChild> mSocketBridgeChild;
+  // The associated IPC actor in a parent process.
+  nsRefPtr<TCPSocketParent> mSocketBridgeParent;
+
   // Raw socket streams
   nsCOMPtr<nsISocketTransport> mTransport;
   nsCOMPtr<nsIInputStream> mSocketInputStream;
   nsCOMPtr<nsIOutputStream> mSocketOutputStream;
 
   // Input stream machinery
   nsCOMPtr<nsIInputStreamPump> mInputStreamPump;
   nsCOMPtr<nsIScriptableInputStream> mInputStreamScriptable;
@@ -186,19 +221,27 @@ private:
   // Is there an async copy operation in progress?
   bool mAsyncCopierActive;
   // True if the buffer is full and a "drain" event is expected by the client.
   bool mWaitingForDrain;
 
   // The id of the window that created this socket.
   uint64_t mInnerWindowID;
 
+  // The current number of buffered bytes. Only used in content processes when IPC is enabled.
+  uint64_t mBufferedAmount;
+
   // The number of times this socket has had `Suspend` called without a corresponding `Resume`.
   uint32_t mSuspendCount;
 
+  // The current sequence number (ie. number of send operations) that have been processed.
+  // This is used in the IPC scenario by the child process to filter out outdated notifications
+  // about the amount of buffered data present in the parent process.
+  uint32_t mTrackingNumber;
+
   // True if this socket has been upgraded to secure after the initial connection,
   // but the actual upgrade is waiting for an in-progress copy operation to complete.
   bool mWaitingForStartTLS;
   // The buffered data awaiting the TLS upgrade to finish.
   nsTArray<nsCOMPtr<nsIInputStream>> mPendingDataAfterStartTLS;
 
 #ifdef MOZ_WIDGET_GONK
   // Number of bytes sent.
--- a/dom/network/TCPSocketChild.cpp
+++ b/dom/network/TCPSocketChild.cpp
@@ -6,35 +6,30 @@
 
 #include <algorithm>
 #include "TCPSocketChild.h"
 #include "mozilla/unused.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/dom/PBrowserChild.h"
 #include "mozilla/dom/TabChild.h"
-#include "nsIDOMTCPSocket.h"
-#include "nsJSUtils.h"
+#include "TCPSocket.h"
 #include "nsContentUtils.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
-#include "jswrapper.h"
 
 using mozilla::net::gNeckoChild;
 
 namespace IPC {
 
 bool
-DeserializeArrayBuffer(JS::Handle<JSObject*> aObj,
+DeserializeArrayBuffer(JSContext* cx,
                        const InfallibleTArray<uint8_t>& aBuffer,
                        JS::MutableHandle<JS::Value> aVal)
 {
-  mozilla::AutoSafeJSContext cx;
-  JSAutoCompartment ac(cx, aObj);
-
   mozilla::UniquePtr<uint8_t[], JS::FreePolicy> data(js_pod_malloc<uint8_t>(aBuffer.Length()));
   if (!data)
       return false;
   memcpy(data.get(), aBuffer.Elements(), aBuffer.Length());
 
   JSObject* obj = JS_NewArrayBufferWithContents(cx, aBuffer.Length(), data.get());
   if (!obj)
       return false;
@@ -52,29 +47,26 @@ namespace dom {
 NS_IMPL_CYCLE_COLLECTION_CLASS(TCPSocketChildBase)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TCPSocketChildBase)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSocket)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(TCPSocketChildBase)
-  tmp->mWindowObj = nullptr;
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSocket)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(TCPSocketChildBase)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mWindowObj)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPSocketChildBase)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPSocketChildBase)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPSocketChildBase)
-  NS_INTERFACE_MAP_ENTRY(nsITCPSocketChild)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 TCPSocketChildBase::TCPSocketChildBase()
 : mIPCOpen(false)
 {
   mozilla::HoldJSObjects(this);
 }
@@ -89,46 +81,30 @@ NS_IMETHODIMP_(MozExternalRefCountType) 
   nsrefcnt refcnt = TCPSocketChildBase::Release();
   if (refcnt == 1 && mIPCOpen) {
     PTCPSocketChild::SendRequestDelete();
     return 1;
   }
   return refcnt;
 }
 
-TCPSocketChild::TCPSocketChild()
-: mHost()
-, mPort(0)
+TCPSocketChild::TCPSocketChild(const nsAString& aHost, const uint16_t& aPort)
+: mHost(aHost)
+, mPort(aPort)
 {
 }
 
-void TCPSocketChild::Init(const nsString& aHost, const uint16_t& aPort) {
-  mHost = aHost;
-  mPort = aPort;
-}
-
-NS_IMETHODIMP
-TCPSocketChild::SendOpen(nsITCPSocketInternal* aSocket,
-                         const nsAString& aHost, uint16_t aPort,
-                         bool aUseSSL, const nsAString& aBinaryType,
-                         nsIDOMWindow* aWindow, JS::Handle<JS::Value> aWindowObj,
-                         JSContext* aCx)
+void
+TCPSocketChild::SendOpen(TCPSocket* aSocket, bool aUseSSL, bool aUseArrayBuffers)
 {
   mSocket = aSocket;
 
-  MOZ_ASSERT(aWindowObj.isObject());
-  mWindowObj = js::CheckedUnwrap(&aWindowObj.toObject());
-  if (!mWindowObj) {
-    return NS_ERROR_FAILURE;
-  }
   AddIPDLReference();
-  gNeckoChild->SendPTCPSocketConstructor(this, nsString(aHost), aPort);
-  PTCPSocketChild::SendOpen(nsString(aHost), aPort,
-                            aUseSSL, nsString(aBinaryType));
-  return NS_OK;
+  gNeckoChild->SendPTCPSocketConstructor(this, mHost, mPort);
+  PTCPSocketChild::SendOpen(mHost, mPort, aUseSSL, aUseArrayBuffers);
 }
 
 void
 TCPSocketChildBase::ReleaseIPDLReference()
 {
   MOZ_ASSERT(mIPCOpen);
   mIPCOpen = false;
   this->Release();
@@ -145,157 +121,105 @@ TCPSocketChildBase::AddIPDLReference()
 TCPSocketChild::~TCPSocketChild()
 {
 }
 
 bool
 TCPSocketChild::RecvUpdateBufferedAmount(const uint32_t& aBuffered,
                                          const uint32_t& aTrackingNumber)
 {
-  if (NS_FAILED(mSocket->UpdateBufferedAmount(aBuffered, aTrackingNumber))) {
-    NS_ERROR("Shouldn't fail!");
-  }
+  mSocket->UpdateBufferedAmount(aBuffered, aTrackingNumber);
   return true;
 }
 
 bool
 TCPSocketChild::RecvCallback(const nsString& aType,
                              const CallbackData& aData,
-                             const nsString& aReadyState)
+                             const uint32_t& aReadyState)
 {
-  if (NS_FAILED(mSocket->UpdateReadyState(aReadyState)))
-    NS_ERROR("Shouldn't fail!");
+  mSocket->UpdateReadyState(aReadyState);
 
-  nsresult rv = NS_ERROR_FAILURE;
   if (aData.type() == CallbackData::Tvoid_t) {
-    rv = mSocket->CallListenerVoid(aType);
+    mSocket->FireEvent(aType);
 
   } else if (aData.type() == CallbackData::TTCPError) {
     const TCPError& err(aData.get_TCPError());
-    rv = mSocket->CallListenerError(aType, err.name());
+    mSocket->FireErrorEvent(err.name(), err.message());
 
   } else if (aData.type() == CallbackData::TSendableData) {
     const SendableData& data = aData.get_SendableData();
 
+    AutoJSAPI api;
+    if (NS_WARN_IF(!api.Init(mSocket->GetOwner()))) {
+      return true;
+    }
+    JSContext* cx = api.cx();
+    JS::Rooted<JS::Value> val(cx);
+
     if (data.type() == SendableData::TArrayOfuint8_t) {
-      JSContext* cx = nsContentUtils::GetSafeJSContext();
-      JSAutoRequest ar(cx);
-      JS::Rooted<JS::Value> val(cx);
-      JS::Rooted<JSObject*> window(cx, mWindowObj);
-      bool ok = IPC::DeserializeArrayBuffer(window, data.get_ArrayOfuint8_t(), &val);
+      bool ok = IPC::DeserializeArrayBuffer(cx, data.get_ArrayOfuint8_t(), &val);
       NS_ENSURE_TRUE(ok, true);
-      rv = mSocket->CallListenerArrayBuffer(aType, val);
 
-    } else if (data.type() == SendableData::TnsString) {
-      rv = mSocket->CallListenerData(aType, data.get_nsString());
+    } else if (data.type() == SendableData::TnsCString) {
+      bool ok = ToJSValue(cx, NS_ConvertASCIItoUTF16(data.get_nsCString()), &val);
+      NS_ENSURE_TRUE(ok, true);
 
     } else {
       MOZ_CRASH("Invalid callback data type!");
     }
+    mSocket->FireDataEvent(cx, aType, val);
 
   } else {
     MOZ_CRASH("Invalid callback type!");
   }
-  NS_ENSURE_SUCCESS(rv, true);
   return true;
 }
 
-NS_IMETHODIMP
-TCPSocketChild::SendStartTLS()
+void
+TCPSocketChild::SendSend(const nsACString& aData, uint32_t aTrackingNumber)
 {
-  PTCPSocketChild::SendStartTLS();
-  return NS_OK;
+  SendData(nsCString(aData), aTrackingNumber);
 }
 
-NS_IMETHODIMP
-TCPSocketChild::SendSuspend()
+nsresult
+TCPSocketChild::SendSend(const ArrayBuffer& aData,
+                         uint32_t aByteOffset,
+                         uint32_t aByteLength,
+                         uint32_t aTrackingNumber)
 {
-  PTCPSocketChild::SendSuspend();
-  return NS_OK;
-}
+  uint32_t buflen = aData.Length();
+  uint32_t offset = std::min(buflen, aByteOffset);
+  uint32_t nbytes = std::min(buflen - aByteOffset, aByteLength);
+  FallibleTArray<uint8_t> fallibleArr;
+  if (!fallibleArr.InsertElementsAt(0, aData.Data() + offset, nbytes, fallible)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
 
-NS_IMETHODIMP
-TCPSocketChild::SendResume()
-{
-  PTCPSocketChild::SendResume();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-TCPSocketChild::SendClose()
-{
-  PTCPSocketChild::SendClose();
+  InfallibleTArray<uint8_t> arr;
+  arr.SwapElements(fallibleArr);
+  SendData(arr, aTrackingNumber);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-TCPSocketChild::SendSend(JS::Handle<JS::Value> aData,
-                         uint32_t aByteOffset,
-                         uint32_t aByteLength,
-                         uint32_t aTrackingNumber,
-                         JSContext* aCx)
+void
+TCPSocketChild::SetSocket(TCPSocket* aSocket)
 {
-  if (aData.isString()) {
-    JSString* jsstr = aData.toString();
-    nsAutoJSString str;
-    bool ok = str.init(aCx, jsstr);
-    NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
-    SendData(str, aTrackingNumber);
-  } else {
-    NS_ENSURE_TRUE(aData.isObject(), NS_ERROR_FAILURE);
-    JS::Rooted<JSObject*> obj(aCx, &aData.toObject());
-    NS_ENSURE_TRUE(JS_IsArrayBufferObject(obj), NS_ERROR_FAILURE);
-    uint32_t buflen = JS_GetArrayBufferByteLength(obj);
-    aByteOffset = std::min(buflen, aByteOffset);
-    uint32_t nbytes = std::min(buflen - aByteOffset, aByteLength);
-    FallibleTArray<uint8_t> fallibleArr;
-    {
-        JS::AutoCheckCannotGC nogc;
-        uint8_t* data = JS_GetArrayBufferData(obj, nogc);
-        if (!data) {
-            return NS_ERROR_OUT_OF_MEMORY;
-        }
-        if (!fallibleArr.InsertElementsAt(0, data + aByteOffset, nbytes,
-                                          fallible)) {
-            return NS_ERROR_OUT_OF_MEMORY;
-        }
-    }
-    InfallibleTArray<uint8_t> arr;
-    arr.SwapElements(fallibleArr);
-    SendData(arr, aTrackingNumber);
-  }
-  return NS_OK;
+  mSocket = aSocket;
 }
 
-NS_IMETHODIMP
-TCPSocketChild::SetSocketAndWindow(nsITCPSocketInternal *aSocket,
-                                   JS::Handle<JS::Value> aWindowObj,
-                                   JSContext* aCx)
-{
-  mSocket = aSocket;
-  MOZ_ASSERT(aWindowObj.isObject());
-  mWindowObj = js::CheckedUnwrap(&aWindowObj.toObject());
-  if (!mWindowObj) {
-    return NS_ERROR_FAILURE;
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
+void
 TCPSocketChild::GetHost(nsAString& aHost)
 {
   aHost = mHost;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
+void
 TCPSocketChild::GetPort(uint16_t* aPort)
 {
   *aPort = mPort;
-  return NS_OK;
 }
 
 bool
 TCPSocketChild::RecvRequestDelete()
 {
   mozilla::unused << Send__delete__(this);
   return true;
 }
--- a/dom/network/TCPSocketChild.h
+++ b/dom/network/TCPSocketChild.h
@@ -3,61 +3,64 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_TCPSocketChild_h
 #define mozilla_dom_TCPSocketChild_h
 
 #include "mozilla/net/PTCPSocketChild.h"
-#include "nsITCPSocketChild.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsCOMPtr.h"
 #include "js/TypeDecls.h"
 
-#define TCPSOCKETCHILD_CID \
-  { 0xa589d96f, 0x7e09, 0x4edf, { 0xa0, 0x1a, 0xeb, 0x49, 0x51, 0xf4, 0x2f, 0x37 } }
-
-class nsITCPSocketInternal;
-
 namespace mozilla {
 namespace dom {
 
-class TCPSocketChildBase : public nsITCPSocketChild {
+class TCPSocket;
+
+class TCPSocketChildBase : public nsISupports {
 public:
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TCPSocketChildBase)
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   void AddIPDLReference();
   void ReleaseIPDLReference();
 
 protected:
   TCPSocketChildBase();
   virtual ~TCPSocketChildBase();
 
-  nsCOMPtr<nsITCPSocketInternal> mSocket;
-  JS::Heap<JSObject*> mWindowObj;
+  nsRefPtr<TCPSocket> mSocket;
   bool mIPCOpen;
 };
 
 class TCPSocketChild : public mozilla::net::PTCPSocketChild
                      , public TCPSocketChildBase
 {
 public:
-  NS_DECL_NSITCPSOCKETCHILD
   NS_IMETHOD_(MozExternalRefCountType) Release() override;
 
-  TCPSocketChild();
+  TCPSocketChild(const nsAString& aHost, const uint16_t& aPort);
   ~TCPSocketChild();
 
-  void Init(const nsString& aHost, const uint16_t& aPort);
+  void SendOpen(TCPSocket* aSocket, bool aUseSSL, bool aUseArrayBuffers);
+  void SendSend(const nsACString& aData, uint32_t aTrackingNumber);
+  nsresult SendSend(const ArrayBuffer& aData,
+                    uint32_t aByteOffset,
+                    uint32_t aByteLength,
+                    uint32_t aTrackingNumber);
+  void SetSocket(TCPSocket* aSocket);
+
+  void GetHost(nsAString& aHost);
+  void GetPort(uint16_t* aPort);
 
   virtual bool RecvCallback(const nsString& aType,
                             const CallbackData& aData,
-                            const nsString& aReadyState) override;
+                            const uint32_t& aReadyState) override;
   virtual bool RecvRequestDelete() override;
   virtual bool RecvUpdateBufferedAmount(const uint32_t& aBufferred,
                                         const uint32_t& aTrackingNumber) override;
 private:
   nsString mHost;
   uint16_t mPort;
 };
 
--- a/dom/network/TCPSocketParent.cpp
+++ b/dom/network/TCPSocketParent.cpp
@@ -19,73 +19,53 @@
 #include "mozilla/HoldDropJSObjects.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsNetUtil.h"
 
 namespace IPC {
 
 //Defined in TCPSocketChild.cpp
 extern bool
-DeserializeArrayBuffer(JS::Handle<JSObject*> aObj,
+DeserializeArrayBuffer(JSContext* aCx,
                        const InfallibleTArray<uint8_t>& aBuffer,
                        JS::MutableHandle<JS::Value> aVal);
 
 } // namespace IPC
 
 namespace mozilla {
 namespace dom {
 
 static void
 FireInteralError(mozilla::net::PTCPSocketParent* aActor, uint32_t aLineNo)
 {
   mozilla::unused <<
       aActor->SendCallback(NS_LITERAL_STRING("onerror"),
-                           TCPError(NS_LITERAL_STRING("InvalidStateError")),
-                           NS_LITERAL_STRING("connecting"));
+                           TCPError(NS_LITERAL_STRING("InvalidStateError"), NS_LITERAL_STRING("Internal error")),
+                           static_cast<uint32_t>(TCPReadyState::Connecting));
 }
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(TCPSocketParentBase)
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TCPSocketParentBase)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSocket)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIntermediary)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(TCPSocketParentBase)
-  tmp->mIntermediaryObj = nullptr;
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSocket)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntermediary)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(TCPSocketParentBase)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mIntermediaryObj)
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPSocketParentBase)
-  NS_INTERFACE_MAP_ENTRY(nsITCPSocketParent)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
+NS_IMPL_CYCLE_COLLECTION(TCPSocketParentBase, mSocket)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPSocketParentBase)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPSocketParentBase)
 
 TCPSocketParentBase::TCPSocketParentBase()
 : mIPCOpen(false)
 {
   mObserver = new mozilla::net::OfflineObserver(this);
-  mozilla::HoldJSObjects(this);
 }
 
 TCPSocketParentBase::~TCPSocketParentBase()
 {
   if (mObserver) {
     mObserver->RemoveObserver();
   }
-  mozilla::DropJSObjects(this);
 }
 
 uint32_t
 TCPSocketParent::GetAppId()
 {
   uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
   const PContentParent *content = Manager()->Manager();
   const InfallibleTArray<PBrowserParent*>& browsers = content->ManagedPBrowserParent();
@@ -125,18 +105,16 @@ TCPSocketParent::OfflineNotification(nsI
   if (appId != targetAppId) {
     return NS_OK;
   }
 
   // If the app is offline, close the socket
   if (mSocket && NS_IsAppOffline(appId)) {
     mSocket->Close();
     mSocket = nullptr;
-    mIntermediaryObj = nullptr;
-    mIntermediary = nullptr;
   }
 
   return NS_OK;
 }
 
 
 void
 TCPSocketParentBase::ReleaseIPDLReference()
@@ -161,17 +139,17 @@ NS_IMETHODIMP_(MozExternalRefCountType) 
     mozilla::unused << PTCPSocketParent::SendRequestDelete();
     return 1;
   }
   return refcnt;
 }
 
 bool
 TCPSocketParent::RecvOpen(const nsString& aHost, const uint16_t& aPort, const bool& aUseSSL,
-                          const nsString& aBinaryType)
+                          const bool& aUseArrayBuffers)
 {
   // We don't have browser actors in xpcshell, and hence can't run automated
   // tests without this loophole.
   if (net::UsingNeckoIPCSecurity() &&
       !AssertAppProcessPermission(Manager()->Manager(), "tcp-socket")) {
     FireInteralError(this, __LINE__);
     return true;
   }
@@ -181,230 +159,160 @@ TCPSocketParent::RecvOpen(const nsString
   bool     inBrowser = GetInBrowser();
 
   if (NS_IsAppOffline(appId)) {
     NS_ERROR("Can't open socket because app is offline");
     FireInteralError(this, __LINE__);
     return true;
   }
 
-  nsresult rv;
-  mIntermediary = do_CreateInstance("@mozilla.org/tcp-socket-intermediary;1", &rv);
-  if (NS_FAILED(rv)) {
-    FireInteralError(this, __LINE__);
-    return true;
-  }
-
-  rv = mIntermediary->Open(this, aHost, aPort, aUseSSL, aBinaryType, appId,
-                           inBrowser, getter_AddRefs(mSocket));
-  if (NS_FAILED(rv) || !mSocket) {
-    FireInteralError(this, __LINE__);
-    return true;
-  }
-
+  mSocket = new TCPSocket(nullptr, aHost, aPort, aUseSSL, aUseArrayBuffers);
+  mSocket->SetAppIdAndBrowser(appId, inBrowser);
+  mSocket->SetSocketBridgeParent(this);
+  NS_ENSURE_SUCCESS(mSocket->Init(), true);
   return true;
 }
 
-NS_IMETHODIMP
-TCPSocketParent::InitJS(JS::Handle<JS::Value> aIntermediary, JSContext* aCx)
-{
-  MOZ_ASSERT(aIntermediary.isObject());
-  mIntermediaryObj = &aIntermediary.toObject();
-  return NS_OK;
-}
-
 bool
 TCPSocketParent::RecvStartTLS()
 {
   NS_ENSURE_TRUE(mSocket, true);
-  nsresult rv = mSocket->UpgradeToSecure();
-  NS_ENSURE_SUCCESS(rv, true);
+  ErrorResult rv;
+  mSocket->UpgradeToSecure(rv);
+  NS_ENSURE_FALSE(rv.Failed(), true);
   return true;
 }
 
 bool
 TCPSocketParent::RecvSuspend()
 {
   NS_ENSURE_TRUE(mSocket, true);
-  nsresult rv = mSocket->Suspend();
-  NS_ENSURE_SUCCESS(rv, true);
+  mSocket->Suspend();
   return true;
 }
 
 bool
 TCPSocketParent::RecvResume()
 {
   NS_ENSURE_TRUE(mSocket, true);
-  nsresult rv = mSocket->Resume();
-  NS_ENSURE_SUCCESS(rv, true);
+  ErrorResult rv;
+  mSocket->Resume(rv);
+  NS_ENSURE_FALSE(rv.Failed(), true);
   return true;
 }
 
 bool
 TCPSocketParent::RecvData(const SendableData& aData,
                           const uint32_t& aTrackingNumber)
 {
-  NS_ENSURE_TRUE(mIntermediary, true);
-
-  nsresult rv;
+  ErrorResult rv;
   switch (aData.type()) {
     case SendableData::TArrayOfuint8_t: {
-      AutoSafeJSContext cx;
-      JSAutoRequest ar(cx);
-      JS::Rooted<JS::Value> val(cx);
-      JS::Rooted<JSObject*> obj(cx, mIntermediaryObj);
-      IPC::DeserializeArrayBuffer(obj, aData.get_ArrayOfuint8_t(), &val);
-      rv = mIntermediary->OnRecvSendArrayBuffer(val, aTrackingNumber);
-      NS_ENSURE_SUCCESS(rv, true);
+      AutoSafeJSContext autoCx;
+      JS::Rooted<JS::Value> val(autoCx);
+      const nsTArray<uint8_t>& buffer = aData.get_ArrayOfuint8_t();
+      bool ok = IPC::DeserializeArrayBuffer(autoCx, buffer, &val);
+      NS_ENSURE_TRUE(ok, true);
+      RootedTypedArray<ArrayBuffer> data(autoCx);
+      data.Init(&val.toObject());
+      Optional<uint32_t> byteLength(buffer.Length());
+      mSocket->SendWithTrackingNumber(autoCx, data, 0, byteLength, aTrackingNumber, rv);
       break;
     }
 
-    case SendableData::TnsString:
-      rv = mIntermediary->OnRecvSendString(aData.get_nsString(), aTrackingNumber);
-      NS_ENSURE_SUCCESS(rv, true);
+    case SendableData::TnsCString: {
+      const nsCString& strData = aData.get_nsCString();
+      mSocket->SendWithTrackingNumber(strData, aTrackingNumber, rv);
       break;
+    }
 
     default:
       MOZ_CRASH("unexpected SendableData type");
   }
+  NS_ENSURE_FALSE(rv.Failed(), true);
   return true;
 }
 
 bool
 TCPSocketParent::RecvClose()
 {
   NS_ENSURE_TRUE(mSocket, true);
-  nsresult rv = mSocket->Close();
-  NS_ENSURE_SUCCESS(rv, true);
+  mSocket->Close();
   return true;
 }
 
-NS_IMETHODIMP
-TCPSocketParent::SendEvent(const nsAString& aType, JS::Handle<JS::Value> aDataVal,
-                           const nsAString& aReadyState, JSContext* aCx)
+void
+TCPSocketParent::FireErrorEvent(const nsAString& aName, const nsAString& aType, TCPReadyState aReadyState)
 {
-  if (!mIPCOpen) {
-    NS_WARNING("Dropping callback due to no IPC connection");
-    return NS_OK;
-  }
-
-  CallbackData data;
-  if (aDataVal.isString()) {
-    JSString* jsstr = aDataVal.toString();
-    nsAutoJSString str;
-    if (!str.init(aCx, jsstr)) {
-      FireInteralError(this, __LINE__);
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-    data = SendableData(str);
-
-  } else if (aDataVal.isUndefined() || aDataVal.isNull()) {
-    data = mozilla::void_t();
+  SendEvent(NS_LITERAL_STRING("error"), TCPError(nsString(aName), nsString(aType)), aReadyState);
+}
 
-  } else if (aDataVal.isObject()) {
-    JS::Rooted<JSObject *> obj(aCx, &aDataVal.toObject());
-    if (JS_IsArrayBufferObject(obj)) {
-      FallibleTArray<uint8_t> fallibleArr;
-      uint32_t errLine = 0;
-      do {
-          JS::AutoCheckCannotGC nogc;
-          uint32_t nbytes = JS_GetArrayBufferByteLength(obj);
-          uint8_t* buffer = JS_GetArrayBufferData(obj, nogc);
-          if (!buffer) {
-              errLine = __LINE__;
-              break;
-          }
-          if (!fallibleArr.InsertElementsAt(0, buffer, nbytes, fallible)) {
-              errLine = __LINE__;
-              break;
-          }
-      } while (false);
-
-      if (errLine) {
-          FireInteralError(this, errLine);
-          return NS_ERROR_OUT_OF_MEMORY;
-      }
+void
+TCPSocketParent::FireEvent(const nsAString& aType, TCPReadyState aReadyState)
+{
+  return SendEvent(aType, mozilla::void_t(), aReadyState);
+}
 
-      InfallibleTArray<uint8_t> arr;
-      arr.SwapElements(fallibleArr);
-      data = SendableData(arr);
-
-    } else {
-      nsAutoJSString name;
-
-      JS::Rooted<JS::Value> val(aCx);
-      if (!JS_GetProperty(aCx, obj, "name", &val)) {
-        NS_ERROR("No name property on supposed error object");
-      } else if (val.isString()) {
-        if (!name.init(aCx, val.toString())) {
-          NS_WARNING("couldn't initialize string");
-        }
-      }
-
-      data = TCPError(name);
-    }
-  } else {
-    NS_ERROR("Unexpected JS value encountered");
-    FireInteralError(this, __LINE__);
-    return NS_ERROR_FAILURE;
-  }
-  mozilla::unused <<
-      PTCPSocketParent::SendCallback(nsString(aType), data,
-                                     nsString(aReadyState));
-  return NS_OK;
+void
+TCPSocketParent::FireArrayBufferDataEvent(nsTArray<uint8_t>& aBuffer, TCPReadyState aReadyState)
+{
+  InfallibleTArray<uint8_t> arr;
+  arr.SwapElements(aBuffer);
+  SendableData data(arr);
+  SendEvent(NS_LITERAL_STRING("data"), data, aReadyState);
 }
 
-NS_IMETHODIMP
-TCPSocketParent::SetSocketAndIntermediary(nsIDOMTCPSocket *socket,
-                                          nsITCPSocketIntermediary *intermediary,
-                                          JSContext* cx)
+void
+TCPSocketParent::FireStringDataEvent(const nsACString& aData, TCPReadyState aReadyState)
 {
-  mSocket = socket;
-  mIntermediary = intermediary;
-  return NS_OK;
+  SendEvent(NS_LITERAL_STRING("data"), SendableData(nsCString(aData)), aReadyState);
 }
 
-NS_IMETHODIMP
-TCPSocketParent::SendUpdateBufferedAmount(uint32_t aBufferedAmount,
-                                          uint32_t aTrackingNumber)
+void
+TCPSocketParent::SendEvent(const nsAString& aType, CallbackData aData, TCPReadyState aReadyState)
 {
-  mozilla::unused << PTCPSocketParent::SendUpdateBufferedAmount(aBufferedAmount,
-                                                                aTrackingNumber);
-  return NS_OK;
+  mozilla::unused << PTCPSocketParent::SendCallback(nsString(aType), aData,
+                                                    static_cast<uint32_t>(aReadyState));
 }
 
-NS_IMETHODIMP
+void
+TCPSocketParent::SetSocket(TCPSocket *socket)
+{
+  mSocket = socket;
+}
+
+nsresult
 TCPSocketParent::GetHost(nsAString& aHost)
 {
   if (!mSocket) {
     NS_ERROR("No internal socket instance mSocket!");
     return NS_ERROR_FAILURE;
   }
-  return mSocket->GetHost(aHost);
+  mSocket->GetHost(aHost);
+  return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 TCPSocketParent::GetPort(uint16_t* aPort)
 {
   if (!mSocket) {
     NS_ERROR("No internal socket instance mSocket!");
     return NS_ERROR_FAILURE;
   }
-  return mSocket->GetPort(aPort);
+  *aPort = mSocket->Port();
+  return NS_OK;
 }
 
 void
 TCPSocketParent::ActorDestroy(ActorDestroyReason why)
 {
   if (mSocket) {
     mSocket->Close();
   }
   mSocket = nullptr;
-  mIntermediaryObj = nullptr;
-  mIntermediary = nullptr;
 }
 
 bool
 TCPSocketParent::RecvRequestDelete()
 {
   mozilla::unused << Send__delete__(this);
   return true;
 }
--- a/dom/network/TCPSocketParent.h
+++ b/dom/network/TCPSocketParent.h
@@ -2,74 +2,84 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_TCPSocketParent_h
 #define mozilla_dom_TCPSocketParent_h
 
+#include "mozilla/dom/TCPSocketBinding.h"
 #include "mozilla/net/PTCPSocketParent.h"
 #include "nsITCPSocketParent.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsCOMPtr.h"
 #include "nsIDOMTCPSocket.h"
 #include "js/TypeDecls.h"
 #include "mozilla/net/OfflineObserver.h"
 
 #define TCPSOCKETPARENT_CID \
   { 0x4e7246c6, 0xa8b3, 0x426d, { 0x9c, 0x17, 0x76, 0xda, 0xb1, 0xe1, 0xe1, 0x4a } }
 
 namespace mozilla {
 namespace dom {
 
-class TCPSocketParentBase : public nsITCPSocketParent
+class TCPSocket;
+
+class TCPSocketParentBase : public nsISupports
                           , public mozilla::net::DisconnectableParent
 {
 public:
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TCPSocketParentBase)
+  NS_DECL_CYCLE_COLLECTION_CLASS(TCPSocketParentBase)
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   void AddIPDLReference();
   void ReleaseIPDLReference();
 
 protected:
   TCPSocketParentBase();
   virtual ~TCPSocketParentBase();
 
-  JS::Heap<JSObject*> mIntermediaryObj;
-  nsCOMPtr<nsITCPSocketIntermediary> mIntermediary;
-  nsCOMPtr<nsIDOMTCPSocket> mSocket;
+  nsRefPtr<TCPSocket> mSocket;
   nsRefPtr<mozilla::net::OfflineObserver> mObserver;
   bool mIPCOpen;
 };
 
 class TCPSocketParent : public mozilla::net::PTCPSocketParent
                       , public TCPSocketParentBase
 {
 public:
-  NS_DECL_NSITCPSOCKETPARENT
   NS_IMETHOD_(MozExternalRefCountType) Release() override;
 
   TCPSocketParent() {}
 
   virtual bool RecvOpen(const nsString& aHost, const uint16_t& aPort,
-                        const bool& useSSL, const nsString& aBinaryType) override;
+                        const bool& useSSL, const bool& aUseArrayBuffers) override;
 
   virtual bool RecvStartTLS() override;
   virtual bool RecvSuspend() override;
   virtual bool RecvResume() override;
   virtual bool RecvClose() override;
   virtual bool RecvData(const SendableData& aData,
                         const uint32_t& aTrackingNumber) override;
   virtual bool RecvRequestDelete() override;
   virtual nsresult OfflineNotification(nsISupports *) override;
   virtual uint32_t GetAppId() override;
   bool GetInBrowser();
 
+  void FireErrorEvent(const nsAString& aName, const nsAString& aType, TCPReadyState aReadyState);
+  void FireEvent(const nsAString& aType, TCPReadyState aReadyState);
+  void FireArrayBufferDataEvent(nsTArray<uint8_t>& aBuffer, TCPReadyState aReadyState);
+  void FireStringDataEvent(const nsACString& aData, TCPReadyState aReadyState);
+
+  void SetSocket(TCPSocket *socket);
+  nsresult GetHost(nsAString& aHost);
+  nsresult GetPort(uint16_t* aPort);
+
 private:
   virtual void ActorDestroy(ActorDestroyReason why) override;
+  void SendEvent(const nsAString& aType, CallbackData aData, TCPReadyState aReadyState);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
--- a/dom/network/moz.build
+++ b/dom/network/moz.build
@@ -1,21 +1,16 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += ['interfaces']
 
-XPCSHELL_TESTS_MANIFESTS += [
-    'tests/unit/xpcshell.ini',
-    'tests/unit_ipc/xpcshell.ini',
-]
-
 if CONFIG['MOZ_B2G_RIL']:
     XPCSHELL_TESTS_MANIFESTS += ['tests/unit_stats/xpcshell.ini']
 
 MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
 
 EXPORTS.mozilla.dom += [
     'TCPServerSocket.h',
     'TCPSocket.h',
deleted file mode 100644
--- a/dom/network/tests/unit/test_tcpsocket.js
+++ /dev/null
@@ -1,371 +0,0 @@
-/**
- * Test TCPSocket.js by creating an XPCOM-style server socket, then sending
- * data in both directions and making sure each side receives their data
- * correctly and with the proper events.
- *
- * This test is derived from netwerk/test/unit/test_socks.js, except we don't
- * involve a subprocess.
- *
- * Future work:
- * - SSL.  see https://bugzilla.mozilla.org/show_bug.cgi?id=466524
- *             https://bugzilla.mozilla.org/show_bug.cgi?id=662180
- *   Alternatively, mochitests could be used.
- * - Testing overflow logic.
- *
- **/
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cr = Components.results;
-const Cu = Components.utils;
-const CC = Components.Constructor;
-
-/**
- *
- * Constants
- *
- */
-
-// Some binary data to send.
-const DATA_ARRAY = [0, 255, 254, 0, 1, 2, 3, 0, 255, 255, 254, 0],
-      DATA_ARRAY_BUFFER = new ArrayBuffer(DATA_ARRAY.length),
-      TYPED_DATA_ARRAY = new Uint8Array(DATA_ARRAY_BUFFER),
-      HELLO_WORLD = "hlo wrld. ",
-      BIG_ARRAY = new Array(65539),
-      BIG_ARRAY_2 = new Array(65539);
-
-TYPED_DATA_ARRAY.set(DATA_ARRAY, 0);
-
-for (var i_big = 0; i_big < BIG_ARRAY.length; i_big++) {
-  BIG_ARRAY[i_big] = Math.floor(Math.random() * 256);
-  BIG_ARRAY_2[i_big] = Math.floor(Math.random() * 256);
-}
-
-const BIG_ARRAY_BUFFER = new ArrayBuffer(BIG_ARRAY.length),
-      BIG_ARRAY_BUFFER_2 = new ArrayBuffer(BIG_ARRAY_2.length);
-const BIG_TYPED_ARRAY = new Uint8Array(BIG_ARRAY_BUFFER),
-      BIG_TYPED_ARRAY_2 = new Uint8Array(BIG_ARRAY_BUFFER_2);
-BIG_TYPED_ARRAY.set(BIG_ARRAY);
-BIG_TYPED_ARRAY_2.set(BIG_ARRAY_2);
-
-const ServerSocket = CC("@mozilla.org/network/server-socket;1",
-                        "nsIServerSocket",
-                        "init"),
-      InputStreamPump = CC("@mozilla.org/network/input-stream-pump;1",
-                           "nsIInputStreamPump",
-                           "init"),
-      BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
-                             "nsIBinaryInputStream",
-                             "setInputStream"),
-      BinaryOutputStream = CC("@mozilla.org/binaryoutputstream;1",
-                              "nsIBinaryOutputStream",
-                              "setOutputStream"),
-      TCPSocket = new (CC("@mozilla.org/tcp-socket;1",
-                     "nsIDOMTCPSocket"))();
-
-const gInChild = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
-                  .processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-/**
- *
- * Helper functions
- *
- */
-
-function is_content() {
-  return this._inChild = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
-                            .processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
-}
-
-/**
- * Spin up a listening socket and associate at most one live, accepted socket
- * with ourselves.
- */
-function TestServer() {
-  this.listener = ServerSocket(-1, true, -1);
-  do_print('server: listening on ' + this.listener.port);
-  this.listener.asyncListen(this);
-
-  this.binaryInput = null;
-  this.input = null;
-  this.binaryOutput = null;
-  this.output = null;
-
-  this.onconnect = null;
-  this.ondata = null;
-  this.onclose = null;
-}
-
-TestServer.prototype = {
-  onSocketAccepted: function(socket, trans) {
-    if (this.input)
-      do_throw("More than one live connection!?");
-
-    do_print('server: got client connection');
-    this.input = trans.openInputStream(0, 0, 0);
-    this.binaryInput = new BinaryInputStream(this.input);
-    this.output = trans.openOutputStream(0, 0, 0);
-    this.binaryOutput = new BinaryOutputStream(this.output);
-
-    new InputStreamPump(this.input, -1, -1, 0, 0, false).asyncRead(this, null);
-
-    if (this.onconnect)
-      this.onconnect();
-    else
-      do_throw("Received unexpected connection!");
-  },
-
-  onStopListening: function(socket) {
-  },
-
-  onDataAvailable: function(request, context, inputStream, offset, count) {
-    var readData = this.binaryInput.readByteArray(count);
-    if (this.ondata) {
-      try {
-        this.ondata(readData);
-      } catch(ex) {
-        // re-throw if this is from do_throw
-        if (ex === Cr.NS_ERROR_ABORT)
-          throw ex;
-        // log if there was a test problem
-        do_print('Caught exception: ' + ex + '\n' + ex.stack);
-        do_throw('test is broken; bad ondata handler; see above');
-      }
-    } else {
-      do_throw('Received ' + count + ' bytes of unexpected data!');
-    }
-  },
-
-  onStartRequest: function(request, context) {
-  },
-
-  onStopRequest: function(request, context, status) {
-    if (this.onclose)
-      this.onclose();
-    else
-      do_throw("Received unexpected close!");
-  },
-
-  close: function() {
-    this.binaryInput.close();
-    this.binaryOutput.close();
-  },
-
-  /**
-   * Forget about the socket we knew about before.
-   */
-  reset: function() {
-    this.binaryInput = null;
-    this.input = null;
-    this.binaryOutput = null;
-    this.output = null;
-  },
-};
-
-function makeSuccessCase(name) {
-  return function() {
-    do_print('got expected: ' + name);
-    run_next_test();
-  };
-}
-
-function makeJointSuccess(names) {
-  let funcs = {}, successCount = 0;
-  names.forEach(function(name) {
-    funcs[name] = function() {
-      do_print('got expected: ' + name);
-      if (++successCount === names.length)
-        run_next_test();
-    };
-  });
-  return funcs;
-}
-
-function makeFailureCase(name) {
-  return function() {
-    let argstr;
-    if (arguments.length) {
-      argstr = '(args: ' +
-        Array.map(arguments, function(x) { return x.data + ""; }).join(" ") + ')';
-    }
-    else {
-      argstr = '(no arguments)';
-    }
-    do_throw('got unexpected: ' + name + ' ' + argstr);
-  };
-}
-
-function makeExpectData(name, expectedData, fromEvent, callback) {
-  let dataBuffer = fromEvent ? null : [], done = false;
-  let dataBufferView = null;
-  return function(receivedData) {
-    if (receivedData.data) {
-      receivedData = receivedData.data;
-    }
-    let recvLength = receivedData.byteLength !== undefined ?
-        receivedData.byteLength : receivedData.length;
-
-    if (fromEvent) {
-      if (dataBuffer) {
-        let newBuffer = new ArrayBuffer(dataBuffer.byteLength + recvLength);
-        let newBufferView = new Uint8Array(newBuffer);
-        newBufferView.set(dataBufferView, 0);
-        newBufferView.set(receivedData, dataBuffer.byteLength);
-        dataBuffer = newBuffer;
-        dataBufferView = newBufferView;
-      }
-      else {
-        dataBuffer = receivedData;
-        dataBufferView = new Uint8Array(dataBuffer);
-      }
-    }
-    else {
-      dataBuffer = dataBuffer.concat(receivedData);
-    }
-    do_print(name + ' received ' + recvLength + ' bytes');
-
-    if (done)
-      do_throw(name + ' Received data event when already done!');
-
-    let dataView = dataBuffer.byteLength !== undefined ? new Uint8Array(dataBuffer) : dataBuffer;
-    if (dataView.length >= expectedData.length) {
-      // check the bytes are equivalent
-      for (let i = 0; i < expectedData.length; i++) {
-        if (dataView[i] !== expectedData[i]) {
-          do_throw(name + ' Received mismatched character at position ' + i);
-        }
-      }
-      if (dataView.length > expectedData.length)
-        do_throw(name + ' Received ' + dataView.length + ' bytes but only expected ' +
-                 expectedData.length + ' bytes.');
-
-      done = true;
-      if (callback) {
-        callback();
-      } else {
-        run_next_test();
-      }
-    }
-  };
-}
-
-var server = null, sock = null, failure_drain = null;
-
-/**
- *
- * Test functions
- *
- */
-
-/**
- * Connect the socket to the server. This test is added as the first
- * test, and is also added after every test which results in the socket
- * being closed.
- */
-
-function connectSock() {
-  server.reset();
-  var yayFuncs = makeJointSuccess(['serveropen', 'clientopen']);
-
-  sock = TCPSocket.open(
-    '127.0.0.1', server.listener.port,
-    { binaryType: 'arraybuffer' });
-
-  sock.onopen = yayFuncs.clientopen;
-  sock.ondrain = null;
-  sock.ondata = makeFailureCase('data');
-  sock.onerror = makeFailureCase('error');
-  sock.onclose = makeFailureCase('close');
-
-  server.onconnect = yayFuncs.serveropen;
-  server.ondata = makeFailureCase('serverdata');
-  server.onclose = makeFailureCase('serverclose');
-}
-
-function cleanup() {
-  do_print("Cleaning up");
-  sock.close();
-  if (!gInChild)
-    Services.prefs.clearUserPref('dom.mozTCPSocket.enabled');
-  run_next_test();
-}
-
-// Test child behavior when child thinks it's buffering but parent doesn't
-// buffer.
-// 1. set bufferedAmount of content socket to a value that will make next
-//    send() call return false.
-// 2. send a small data to make send() return false, but it won't make
-//    parent buffer.
-// 3. we should get a ondrain.
-function childbuffered() {
-  let yays = makeJointSuccess(['ondrain', 'serverdata',
-                               'clientclose', 'serverclose']);
-  sock.ondrain = function() {
-    yays.ondrain();
-    sock.close();
-  };
-
-  server.ondata = makeExpectData(
-    'ondata', DATA_ARRAY, false, yays.serverdata);
-
-  let internalSocket = sock.QueryInterface(Ci.nsITCPSocketInternal);
-  internalSocket.updateBufferedAmount(65535, // almost reach buffering threshold
-                                      0);
-  if (sock.send(DATA_ARRAY_BUFFER)) {
-    do_throw("expected sock.send to return false.");
-  }
-
-  sock.onclose = yays.clientclose;
-  server.onclose = yays.serverclose;
-}
-
-// Test child's behavior when send() of child return true but parent buffers
-// data.
-// 1. send BIG_ARRAY to make parent buffer. This would make child wait for
-//    drain as well.
-// 2. set child's bufferedAmount to zero, so child will no longer wait for
-//    drain but parent will dispatch a drain event.
-// 3. wait for 1 second, to make sure there's no ondrain event dispatched in
-//    child.
-function childnotbuffered() {
-  let yays = makeJointSuccess(['serverdata', 'clientclose', 'serverclose']);
-  server.ondata = makeExpectData('ondata', BIG_ARRAY, false, yays.serverdata);
-  if (sock.send(BIG_ARRAY_BUFFER)) {
-    do_throw("sock.send(BIG_TYPED_ARRAY) did not return false to indicate buffering");
-  }
-  let internalSocket = sock.QueryInterface(Ci.nsITCPSocketInternal);
-  internalSocket.updateBufferedAmount(0, // setting zero will clear waitForDrain in sock.
-                                      1);
-
-  // shouldn't get ondrain, even after parent have cleared its buffer.
-  sock.ondrain = makeFailureCase('drain');
-  sock.onclose = yays.clientclose;
-  server.onclose = yays.serverclose;
-  do_timeout(1000, function() {
-    sock.close();
-  });
-};
-
-if (is_content()) {
-  add_test(connectSock);
-  add_test(childnotbuffered);
-
-  add_test(connectSock);
-  add_test(childbuffered);
-
-  // clean up
-  add_test(cleanup);
-} else {
-  do_check_true(true, 'non-content process wants to pretend to one test');
-}
-
-function run_test() {
-  if (!gInChild)
-    Services.prefs.setBoolPref('dom.mozTCPSocket.enabled', true);
-
-  server = new TestServer();
-
-  run_next_test();
-}
deleted file mode 100644
--- a/dom/network/tests/unit/xpcshell.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[DEFAULT]
-head =
-tail =
-skip-if = toolkit == 'gonk'
-
-[test_tcpsocket.js]
deleted file mode 100644
--- a/dom/network/tests/unit_ipc/test_tcpsocket_ipc.js
+++ /dev/null
@@ -1,9 +0,0 @@
-Components.utils.import("resource://gre/modules/Services.jsm");
-
-function run_test() {
-  Services.prefs.setBoolPref('dom.mozTCPSocket.enabled', true);
-  run_test_in_child("../unit/test_tcpsocket.js", function() {
-    Services.prefs.clearUserPref('dom.mozTCPSocket.enabled');
-    do_test_finished();
-  });
-}
\ No newline at end of file
deleted file mode 100644
--- a/dom/network/tests/unit_ipc/xpcshell.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[DEFAULT]
-head =
-tail =
-skip-if = toolkit == 'android' || toolkit == 'gonk'
-
-[test_tcpsocket_ipc.js]
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -80,19 +80,16 @@
 #include "nsDOMScriptObjectFactory.h"
 #include "DOMStorageManager.h"
 #include "nsJSON.h"
 #include "nsZipArchive.h"
 #include "mozIApplicationClearPrivateDataParams.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/DOMException.h"
 #include "mozilla/dom/DOMRequest.h"
-#include "mozilla/dom/network/TCPSocketChild.h"
-#include "mozilla/dom/network/TCPSocketParent.h"
-#include "mozilla/dom/network/TCPServerSocketChild.h"
 #include "mozilla/dom/network/UDPSocketChild.h"
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "mozilla/dom/workers/ServiceWorkerManager.h"
 #include "mozilla/dom/workers/ServiceWorkerPeriodicUpdater.h"
 #include "mozilla/dom/workers/WorkerDebuggerManager.h"
 #include "mozilla/OSFileConstants.h"
 #include "mozilla/Services.h"
 
@@ -270,19 +267,16 @@ static void Shutdown();
 using namespace mozilla;
 using namespace mozilla::dom;
 using mozilla::dom::alarm::AlarmHalService;
 using mozilla::dom::power::PowerManagerService;
 using mozilla::dom::quota::QuotaManager;
 using mozilla::dom::workers::ServiceWorkerManager;
 using mozilla::dom::workers::ServiceWorkerPeriodicUpdater;
 using mozilla::dom::workers::WorkerDebuggerManager;
-using mozilla::dom::TCPSocketChild;
-using mozilla::dom::TCPSocketParent;
-using mozilla::dom::TCPServerSocketChild;
 using mozilla::dom::UDPSocketChild;
 using mozilla::dom::time::TimeService;
 using mozilla::net::StreamingProtocolControllerService;
 using mozilla::gmp::GeckoMediaPluginService;
 
 // Transformiix
 /* 5d5d92cd-6bf8-11d9-bf4a-000a95dc234c */
 #define TRANSFORMIIX_NODESET_CID \
@@ -660,19 +654,16 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMixedCo
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsPrincipal)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSystemPrincipal,
     nsScriptSecurityManager::SystemPrincipalSingletonConstructor)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsNullPrincipal, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsStructuredCloneContainer)
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(OSFileConstantsService)
-NS_GENERIC_FACTORY_CONSTRUCTOR(TCPSocketChild)
-NS_GENERIC_FACTORY_CONSTRUCTOR(TCPSocketParent)
-NS_GENERIC_FACTORY_CONSTRUCTOR(TCPServerSocketChild)
 NS_GENERIC_FACTORY_CONSTRUCTOR(UDPSocketChild)
 
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(GeckoMediaPluginService, GeckoMediaPluginService::GetGeckoMediaPluginService)
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 
   MAKE_CTOR(CreateA11yService, nsIAccessibilityService, NS_GetAccessibilityService)
@@ -832,19 +823,16 @@ NS_DEFINE_NAMED_CID(NS_MOBILE_CONNECTION
 NS_DEFINE_NAMED_CID(SMS_SERVICE_CID);
 NS_DEFINE_NAMED_CID(ICC_SERVICE_CID);
 NS_DEFINE_NAMED_CID(MMS_SERVICE_CID);
 NS_DEFINE_NAMED_CID(MOBILE_MESSAGE_SERVICE_CID);
 NS_DEFINE_NAMED_CID(MOBILE_MESSAGE_DATABASE_SERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_POWERMANAGERSERVICE_CID);
 NS_DEFINE_NAMED_CID(OSFILECONSTANTSSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_ALARMHALSERVICE_CID);
-NS_DEFINE_NAMED_CID(TCPSOCKETCHILD_CID);
-NS_DEFINE_NAMED_CID(TCPSOCKETPARENT_CID);
-NS_DEFINE_NAMED_CID(TCPSERVERSOCKETCHILD_CID);
 NS_DEFINE_NAMED_CID(UDPSOCKETCHILD_CID);
 NS_DEFINE_NAMED_CID(NS_TIMESERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_MEDIASTREAMCONTROLLERSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_MEDIAMANAGERSERVICE_CID);
 #ifdef MOZ_GAMEPAD
 NS_DEFINE_NAMED_CID(NS_GAMEPAD_TEST_CID);
 #endif
 #ifdef MOZ_WEBSPEECH_TEST_BACKEND
@@ -1142,19 +1130,16 @@ static const mozilla::Module::CIDEntry k
   { &kSMS_SERVICE_CID, false, nullptr, nsISmsServiceConstructor },
   { &kICC_SERVICE_CID, false, nullptr, nsIIccServiceConstructor },
   { &kMMS_SERVICE_CID, false, nullptr, nsIMmsServiceConstructor },
   { &kMOBILE_MESSAGE_SERVICE_CID, false, nullptr, nsIMobileMessageServiceConstructor },
   { &kMOBILE_MESSAGE_DATABASE_SERVICE_CID, false, nullptr, nsIMobileMessageDatabaseServiceConstructor },
   { &kNS_POWERMANAGERSERVICE_CID, false, nullptr, nsIPowerManagerServiceConstructor },
   { &kOSFILECONSTANTSSERVICE_CID, true, nullptr, OSFileConstantsServiceConstructor },
   { &kNS_ALARMHALSERVICE_CID, false, nullptr, nsIAlarmHalServiceConstructor },
-  { &kTCPSOCKETCHILD_CID, false, nullptr, TCPSocketChildConstructor },
-  { &kTCPSOCKETPARENT_CID, false, nullptr, TCPSocketParentConstructor },
-  { &kTCPSERVERSOCKETCHILD_CID, false, nullptr, TCPServerSocketChildConstructor },
   { &kUDPSOCKETCHILD_CID, false, nullptr, UDPSocketChildConstructor },
   { &kGECKO_MEDIA_PLUGIN_SERVICE_CID, true, nullptr, GeckoMediaPluginServiceConstructor },
   { &kNS_TIMESERVICE_CID, false, nullptr, nsITimeServiceConstructor },
   { &kNS_MEDIASTREAMCONTROLLERSERVICE_CID, false, nullptr, nsIStreamingProtocolControllerServiceConstructor },
 #if defined(MOZ_WIDGET_GONK) && !defined(DISABLE_MOZ_RIL_GEOLOC)
   { &kGONK_GPS_GEOLOCATION_PROVIDER_CID, false, nullptr, nsIGeolocationProviderConstructor },
 #endif
   { &kNS_MEDIAMANAGERSERVICE_CID, false, nullptr, nsIMediaManagerServiceConstructor },
@@ -1313,19 +1298,16 @@ static const mozilla::Module::ContractID
   { SMS_SERVICE_CONTRACTID, &kSMS_SERVICE_CID },
   { ICC_SERVICE_CONTRACTID, &kICC_SERVICE_CID },
   { MMS_SERVICE_CONTRACTID, &kMMS_SERVICE_CID },
   { MOBILE_MESSAGE_SERVICE_CONTRACTID, &kMOBILE_MESSAGE_SERVICE_CID },
   { MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID, &kMOBILE_MESSAGE_DATABASE_SERVICE_CID },
   { POWERMANAGERSERVICE_CONTRACTID, &kNS_POWERMANAGERSERVICE_CID },
   { OSFILECONSTANTSSERVICE_CONTRACTID, &kOSFILECONSTANTSSERVICE_CID },
   { ALARMHALSERVICE_CONTRACTID, &kNS_ALARMHALSERVICE_CID },
-  { "@mozilla.org/tcp-socket-child;1", &kTCPSOCKETCHILD_CID },
-  { "@mozilla.org/tcp-socket-parent;1", &kTCPSOCKETPARENT_CID },
-  { "@mozilla.org/tcp-server-socket-child;1", &kTCPSERVERSOCKETCHILD_CID },
   { "@mozilla.org/udp-socket-child;1", &kUDPSOCKETCHILD_CID },
   { TIMESERVICE_CONTRACTID, &kNS_TIMESERVICE_CID },
   { MEDIASTREAMCONTROLLERSERVICE_CONTRACTID, &kNS_MEDIASTREAMCONTROLLERSERVICE_CID },
 #if defined(MOZ_WIDGET_GONK) && !defined(DISABLE_MOZ_RIL_GEOLOC)
   { GONK_GPS_GEOLOCATION_PROVIDER_CONTRACTID, &kGONK_GPS_GEOLOCATION_PROVIDER_CID },
 #endif
 #ifdef MOZ_GAMEPAD
   { NS_GAMEPAD_TEST_CONTRACTID, &kNS_GAMEPAD_TEST_CID },
--- a/netwerk/ipc/NeckoChild.cpp
+++ b/netwerk/ipc/NeckoChild.cpp
@@ -205,34 +205,33 @@ NeckoChild::DeallocPRtspChannelChild(PRt
 #endif
   return true;
 }
 
 PTCPSocketChild*
 NeckoChild::AllocPTCPSocketChild(const nsString& host,
                                  const uint16_t& port)
 {
-  TCPSocketChild* p = new TCPSocketChild();
-  p->Init(host, port);
+  TCPSocketChild* p = new TCPSocketChild(host, port);
   p->AddIPDLReference();
   return p;
 }
 
 bool
 NeckoChild::DeallocPTCPSocketChild(PTCPSocketChild* child)
 {
   TCPSocketChild* p = static_cast<TCPSocketChild*>(child);
   p->ReleaseIPDLReference();
   return true;
 }
 
 PTCPServerSocketChild*
 NeckoChild::AllocPTCPServerSocketChild(const uint16_t& aLocalPort,
                                   const uint16_t& aBacklog,
-                                  const nsString& aBinaryType)
+                                  const bool& aUseArrayBuffers)
 {
   NS_NOTREACHED("AllocPTCPServerSocket should not be called");
   return nullptr;
 }
 
 bool
 NeckoChild::DeallocPTCPServerSocketChild(PTCPServerSocketChild* child)
 {
--- a/netwerk/ipc/NeckoChild.h
+++ b/netwerk/ipc/NeckoChild.h
@@ -43,17 +43,17 @@ protected:
                          const SerializedLoadContext&) override;
   virtual bool DeallocPWebSocketChild(PWebSocketChild*) override;
   virtual PTCPSocketChild* AllocPTCPSocketChild(const nsString& host,
                                                 const uint16_t& port) override;
   virtual bool DeallocPTCPSocketChild(PTCPSocketChild*) override;
   virtual PTCPServerSocketChild*
     AllocPTCPServerSocketChild(const uint16_t& aLocalPort,
                                const uint16_t& aBacklog,
-                               const nsString& aBinaryType) override;
+                               const bool& aUseArrayBuffers) override;
   virtual bool DeallocPTCPServerSocketChild(PTCPServerSocketChild*) override;
   virtual PUDPSocketChild* AllocPUDPSocketChild(const Principal& aPrincipal,
                                                 const nsCString& aFilter) override;
   virtual bool DeallocPUDPSocketChild(PUDPSocketChild*) override;
   virtual PDNSRequestChild* AllocPDNSRequestChild(const nsCString& aHost,
                                                   const uint32_t& aFlags,
                                                   const nsCString& aNetworkInterface) override;
   virtual bool DeallocPDNSRequestChild(PDNSRequestChild*) override;
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -452,32 +452,32 @@ NeckoParent::DeallocPTCPSocketParent(PTC
 {
   TCPSocketParent* p = static_cast<TCPSocketParent*>(actor);
   p->ReleaseIPDLReference();
   return true;
 }
 
 PTCPServerSocketParent*
 NeckoParent::AllocPTCPServerSocketParent(const uint16_t& aLocalPort,
-                                   const uint16_t& aBacklog,
-                                   const nsString& aBinaryType)
+                                         const uint16_t& aBacklog,
+                                         const bool& aUseArrayBuffers)
 {
-  TCPServerSocketParent* p = new TCPServerSocketParent();
+  TCPServerSocketParent* p = new TCPServerSocketParent(this, aLocalPort, aBacklog, aUseArrayBuffers);
   p->AddIPDLReference();
   return p;
 }
 
 bool
 NeckoParent::RecvPTCPServerSocketConstructor(PTCPServerSocketParent* aActor,
                                              const uint16_t& aLocalPort,
                                              const uint16_t& aBacklog,
-                                             const nsString& aBinaryType)
+                                             const bool& aUseArrayBuffers)
 {
-  return static_cast<TCPServerSocketParent*>(aActor)->
-      Init(this, aLocalPort, aBacklog, aBinaryType);
+  static_cast<TCPServerSocketParent*>(aActor)->Init();
+  return true;
 }
 
 bool
 NeckoParent::DeallocPTCPServerSocketParent(PTCPServerSocketParent* actor)
 {
   TCPServerSocketParent* p = static_cast<TCPServerSocketParent*>(actor);
    p->ReleaseIPDLReference();
   return true;
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -141,21 +141,21 @@ protected:
                                    override;
   virtual bool DeallocPRemoteOpenFileParent(PRemoteOpenFileParent* aActor)
                                             override;
 
   virtual bool DeallocPTCPSocketParent(PTCPSocketParent*) override;
   virtual PTCPServerSocketParent*
     AllocPTCPServerSocketParent(const uint16_t& aLocalPort,
                                 const uint16_t& aBacklog,
-                                const nsString& aBinaryType) override;
+                                const bool& aUseArrayBuffers) override;
   virtual bool RecvPTCPServerSocketConstructor(PTCPServerSocketParent*,
                                                const uint16_t& aLocalPort,
                                                const uint16_t& aBacklog,
-                                               const nsString& aBinaryType) override;
+                                               const bool& aUseArrayBuffers) override;
   virtual bool DeallocPTCPServerSocketParent(PTCPServerSocketParent*) override;
   virtual PUDPSocketParent* AllocPUDPSocketParent(const Principal& aPrincipal,
                                                   const nsCString& aFilter) override;
   virtual bool RecvPUDPSocketConstructor(PUDPSocketParent*,
                                          const Principal& aPrincipal,
                                          const nsCString& aFilter) override;
   virtual bool DeallocPUDPSocketParent(PUDPSocketParent*) override;
   virtual PDNSRequestParent* AllocPDNSRequestParent(const nsCString& aHost,
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -62,17 +62,17 @@ parent:
   PHttpChannel(PBrowserOrId browser,
                SerializedLoadContext loadContext,
                HttpChannelCreationArgs args);
   PWyciwygChannel();
   PFTPChannel(PBrowserOrId browser, SerializedLoadContext loadContext,
               FTPChannelCreationArgs args);
 
   PWebSocket(PBrowserOrId browser, SerializedLoadContext loadContext);
-  PTCPServerSocket(uint16_t localPort, uint16_t backlog, nsString binaryType);
+  PTCPServerSocket(uint16_t localPort, uint16_t backlog, bool useArrayBuffers);
   PUDPSocket(Principal principal, nsCString filter);
 
   PDNSRequest(nsCString hostName, uint32_t flags, nsCString networkInterface);
 
 
   /* Predictor Methods */
   PredPredict(OptionalURIParams targetURI, OptionalURIParams sourceURI,
               uint32_t reason, SerializedLoadContext loadContext,