Bug 1497249 - P2: ipdl for nsIWebSocketConnection r=michal

Differential Revision: https://phabricator.services.mozilla.com/D30624
This commit is contained in:
Kershaw Chang 2020-07-16 13:34:58 +00:00
parent 1e225df236
commit 682f8a9a04
17 changed files with 700 additions and 22 deletions

View File

@ -555,6 +555,12 @@ WebrtcTCPSocket::OnTransportAvailable(nsISocketTransport* aTransport,
return NS_OK;
}
NS_IMETHODIMP
WebrtcTCPSocket::OnWebSocketConnectionAvailable(
nsIWebSocketConnection* aConnection) {
return NS_OK;
}
void WebrtcTCPSocket::FinishOpen() {
MOZ_ASSERT(OnSocketThread());
// mTransport, mSocketIn, and mSocketOut are all set. We may have set them in

View File

@ -11,6 +11,7 @@
#include "HttpTransactionChild.h"
#include "AltSvcTransactionChild.h"
#include "EventTokenBucket.h"
#include "mozilla/net/WebSocketConnectionChild.h"
#include "nsHttpConnectionInfo.h"
#include "nsHttpConnectionMgr.h"
#include "nsHttpHandler.h"
@ -177,5 +178,25 @@ mozilla::ipc::IPCResult HttpConnectionMgrChild::RecvSpeculativeConnect(
return IPC_OK();
}
already_AddRefed<PWebSocketConnectionChild>
HttpConnectionMgrChild::AllocPWebSocketConnectionChild(
PHttpTransactionChild* aTransWithStickyConn) {
RefPtr<WebSocketConnectionChild> actor = new WebSocketConnectionChild();
return actor.forget();
}
mozilla::ipc::IPCResult
HttpConnectionMgrChild::RecvPWebSocketConnectionConstructor(
PWebSocketConnectionChild* aActor,
PHttpTransactionChild* aTransWithStickyConn) {
RefPtr<WebSocketConnectionChild> child =
static_cast<WebSocketConnectionChild*>(aActor);
nsCOMPtr<nsIHttpUpgradeListener> listener =
static_cast<nsIHttpUpgradeListener*>(child.get());
Unused << mConnMgr->CompleteUpgrade(
ToRealHttpTransaction(aTransWithStickyConn), listener);
return IPC_OK();
}
} // namespace net
} // namespace mozilla

View File

@ -41,6 +41,12 @@ class HttpConnectionMgrChild final : public PHttpConnectionMgrChild {
Maybe<SpeculativeConnectionOverriderArgs> aOverriderArgs, uint32_t aCaps,
Maybe<PAltSvcTransactionChild*> aTrans);
already_AddRefed<PWebSocketConnectionChild> AllocPWebSocketConnectionChild(
PHttpTransactionChild* aTransWithStickyConn);
mozilla::ipc::IPCResult RecvPWebSocketConnectionConstructor(
PWebSocketConnectionChild* aActor,
PHttpTransactionChild* aTransWithStickyConn) override;
private:
virtual ~HttpConnectionMgrChild();

View File

@ -10,6 +10,7 @@
#include "HttpConnectionMgrParent.h"
#include "AltSvcTransactionParent.h"
#include "mozilla/net/HttpTransactionParent.h"
#include "mozilla/net/WebSocketConnectionParent.h"
#include "nsHttpConnectionInfo.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsISpeculativeConnect.h"
@ -252,8 +253,13 @@ nsresult HttpConnectionMgrParent::ClearConnectionHistory() {
nsresult HttpConnectionMgrParent::CompleteUpgrade(
HttpTransactionShell* aTrans, nsIHttpUpgradeListener* aUpgradeListener) {
// TODO: fix this in bug 1497249
return NS_ERROR_NOT_IMPLEMENTED;
MOZ_ASSERT(aTrans->AsHttpTransactionParent());
RefPtr<WebSocketConnectionParent> wsConnParent =
new WebSocketConnectionParent(aUpgradeListener);
Unused << SendPWebSocketConnectionConstructor(
wsConnParent, aTrans->AsHttpTransactionParent());
return NS_OK;
}
nsHttpConnectionMgr* HttpConnectionMgrParent::AsHttpConnectionMgr() {

View File

@ -8,6 +8,7 @@
include protocol PAltSvcTransaction;
include protocol PSocketProcess;
include protocol PHttpTransaction;
include protocol PWebSocketConnection;
include NeckoChannelParams;
@ -17,6 +18,7 @@ namespace net {
async refcounted protocol PHttpConnectionMgr
{
manager PSocketProcess;
manages PWebSocketConnection;
child:
async __delete__();
@ -33,6 +35,7 @@ child:
async SpeculativeConnect(HttpConnectionInfoCloneArgs aConnInfo,
SpeculativeConnectionOverriderArgs? aOverriderArgs,
uint32_t aCaps, PAltSvcTransaction? aTrans);
async PWebSocketConnection(PHttpTransaction aTransWithStickyConn);
};
} // namespace net

View File

@ -7942,6 +7942,13 @@ nsresult nsHttpChannel::ContinueOnStopRequestAfterAuthRetry(
mResponseHead->Status() == 200;
if (upgradeWebsocket || upgradeConnect) {
// TODO: Support connection upgrade for socket process in bug 1632809.
if (nsIOService::UseSocketProcess() && upgradeConnect) {
Unused << mUpgradeProtocolCallback->OnUpgradeFailed(
NS_ERROR_NOT_IMPLEMENTED);
return ContinueOnStopRequest(aStatus, aIsFromNet, aContentComplete);
}
nsresult rv = gHttpHandler->CompleteUpgrade(aTransWithStickyConn,
mUpgradeProtocolCallback);
if (NS_FAILED(rv)) {

View File

@ -27,6 +27,7 @@ interface nsIProxyInfo;
interface nsISecurityConsoleMessage;
interface nsISocketTransport;
interface nsIURI;
interface nsIWebSocketConnection;
/**
* The callback interface for nsIHttpChannelInternal::HTTPUpgrade()
@ -40,6 +41,8 @@ interface nsIHttpUpgradeListener : nsISupports
in nsIAsyncOutputStream aSocketOut);
[must_use] void onUpgradeFailed(in nsresult aErrorCode);
[must_use] void onWebSocketConnectionAvailable(in nsIWebSocketConnection aConnection);
};
/**

View File

@ -48,6 +48,12 @@ TransportProviderParent::OnTransportAvailable(
return NS_OK;
}
NS_IMETHODIMP
TransportProviderParent::OnWebSocketConnectionAvailable(
nsIWebSocketConnection* aConnection) {
return NS_OK;
}
NS_IMETHODIMP
TransportProviderParent::OnUpgradeFailed(nsresult aErrorCode) { return NS_OK; }

View File

@ -0,0 +1,33 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
/* 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 protocol PHttpConnectionMgr;
namespace mozilla {
namespace net {
async refcounted protocol PWebSocketConnection
{
manager PHttpConnectionMgr;
parent:
async OnTransportAvailable(nsCString securityInfoSerialization);
async OnError(nsresult aStatus);
async OnTCPClosed();
async OnDataReceived(uint8_t[] aData);
async OnUpgradeFailed(nsresult aReason);
child:
async EnqueueOutgoingData(uint8_t[] aHeader, uint8_t[] aPayload);
async StartReading();
async DrainSocketData();
async __delete__();
};
} //namespace net
} //namespace mozilla

View File

@ -3527,7 +3527,31 @@ WebSocketChannel::OnTransportAvailable(nsISocketTransport* aTransport,
MOZ_ASSERT(!mRecvdHttpUpgradeTransport, "OTA duplicated");
MOZ_ASSERT(aSocketIn, "OTA with invalid socketIn");
mConnection = new nsWebSocketConnection(aTransport, aSocketIn, aSocketOut);
return OnWebSocketConnectionAvailable(
new nsWebSocketConnection(aTransport, aSocketIn, aSocketOut));
}
NS_IMETHODIMP
WebSocketChannel::OnWebSocketConnectionAvailable(
nsIWebSocketConnection* aConnection) {
LOG(
("WebSocketChannel::OnWebSocketConnectionAvailable %p [%p] "
"rcvdonstart=%d\n",
this, aConnection, mGotUpgradeOK));
MOZ_ASSERT(NS_IsMainThread(), "not main thread");
MOZ_ASSERT(!mRecvdHttpUpgradeTransport,
"OnWebSocketConnectionAvailable duplicated");
MOZ_ASSERT(aConnection,
"OnWebSocketConnectionAvailable with invalid connection");
if (mStopped) {
LOG(("WebSocketChannel::OnWebSocketConnectionAvailable: Already stopped"));
aConnection->Close();
return NS_OK;
}
mConnection = aConnection;
nsresult rv = mConnection->Init(this, mSocketThread);
if (NS_FAILED(rv)) return rv;

View File

@ -0,0 +1,186 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* 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 "WebSocketLog.h"
#include "WebSocketConnectionChild.h"
#include "nsISerializable.h"
#include "nsSerializationHelper.h"
#include "nsThreadUtils.h"
#include "nsWebSocketConnection.h"
namespace mozilla {
namespace net {
NS_IMPL_ISUPPORTS(WebSocketConnectionChild, nsIWebSocketConnectionListener,
nsIHttpUpgradeListener)
WebSocketConnectionChild::WebSocketConnectionChild() {
LOG(("WebSocketConnectionChild ctor %p\n", this));
}
WebSocketConnectionChild::~WebSocketConnectionChild() {
LOG(("WebSocketConnectionChild dtor %p\n", this));
}
// nsIHttpUpgradeListener
NS_IMETHODIMP
WebSocketConnectionChild::OnTransportAvailable(
nsISocketTransport* aTransport, nsIAsyncInputStream* aSocketIn,
nsIAsyncOutputStream* aSocketOut) {
if (!NS_IsMainThread()) {
nsCOMPtr<nsISocketTransport> transport = aTransport;
nsCOMPtr<nsIAsyncInputStream> inputStream = aSocketIn;
nsCOMPtr<nsIAsyncOutputStream> outputStream = aSocketOut;
RefPtr<WebSocketConnectionChild> self = this;
return NS_DispatchToMainThread(
NS_NewRunnableFunction("WebSocketConnectionChild::OnTransportAvailable",
[self, transport, inputStream, outputStream]() {
Unused << self->OnTransportAvailable(
transport, inputStream, outputStream);
}),
NS_DISPATCH_NORMAL);
}
LOG(("WebSocketConnectionChild::OnTransportAvailable %p\n", this));
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mConnection, "already called");
MOZ_ASSERT(aTransport);
nsAutoCString serializedSecurityInfo;
nsCOMPtr<nsISupports> secInfoSupp;
aTransport->GetSecurityInfo(getter_AddRefs(secInfoSupp));
if (secInfoSupp) {
nsCOMPtr<nsISerializable> secInfoSer = do_QueryInterface(secInfoSupp);
if (secInfoSer) {
NS_SerializeToString(secInfoSer, serializedSecurityInfo);
}
}
mConnection = new nsWebSocketConnection(aTransport, aSocketIn, aSocketOut);
nsresult rv = mConnection->Init(this, GetCurrentEventTarget());
if (NS_FAILED(rv)) {
Unused << SendOnError(rv);
return NS_OK;
}
Unused << SendOnTransportAvailable(serializedSecurityInfo);
return NS_OK;
}
NS_IMETHODIMP
WebSocketConnectionChild::OnWebSocketConnectionAvailable(
nsIWebSocketConnection* aConnection) {
return NS_OK;
}
NS_IMETHODIMP
WebSocketConnectionChild::OnUpgradeFailed(nsresult aReason) {
if (!NS_IsMainThread()) {
return NS_DispatchToMainThread(NewRunnableMethod<nsresult>(
"WebSocketConnectionChild::OnUpgradeFailed", this,
&WebSocketConnectionChild::OnUpgradeFailed, aReason));
}
if (CanSend()) {
Unused << SendOnUpgradeFailed(aReason);
}
return NS_OK;
}
mozilla::ipc::IPCResult WebSocketConnectionChild::RecvEnqueueOutgoingData(
nsTArray<uint8_t>&& aHeader, nsTArray<uint8_t>&& aPayload) {
LOG(("WebSocketConnectionChild::RecvEnqueueOutgoingData %p\n", this));
if (!mConnection) {
MOZ_ASSERT(false);
return IPC_FAIL(this, "Connection is not available");
}
mConnection->EnqueueOutputData(std::move(aHeader), std::move(aPayload));
return IPC_OK();
}
mozilla::ipc::IPCResult WebSocketConnectionChild::RecvStartReading() {
LOG(("WebSocketConnectionChild::RecvStartReading %p\n", this));
if (!mConnection) {
MOZ_ASSERT(false);
return IPC_FAIL(this, "Connection is not available");
}
mConnection->StartReading();
return IPC_OK();
}
mozilla::ipc::IPCResult WebSocketConnectionChild::RecvDrainSocketData() {
LOG(("WebSocketConnectionChild::RecvDrainSocketData %p\n", this));
if (!mConnection) {
MOZ_ASSERT(false);
return IPC_FAIL(this, "Connection is not available");
}
mConnection->DrainSocketData();
return IPC_OK();
}
mozilla::ipc::IPCResult WebSocketConnectionChild::Recv__delete__() {
LOG(("WebSocketConnectionChild::Recv__delete__ %p\n", this));
if (!mConnection) {
return IPC_OK();
}
mConnection->Close();
mConnection = nullptr;
return IPC_OK();
}
NS_IMETHODIMP
WebSocketConnectionChild::OnError(nsresult aStatus) {
LOG(("WebSocketConnectionChild::OnError %p\n", this));
if (CanSend()) {
Unused << SendOnError(aStatus);
}
return NS_OK;
}
NS_IMETHODIMP
WebSocketConnectionChild::OnTCPClosed() {
LOG(("WebSocketConnectionChild::OnTCPClosed %p\n", this));
if (CanSend()) {
Unused << SendOnTCPClosed();
}
return NS_OK;
}
NS_IMETHODIMP
WebSocketConnectionChild::OnDataReceived(uint8_t* aData, uint32_t aCount) {
LOG(("WebSocketConnectionChild::OnDataReceived %p\n", this));
if (CanSend()) {
nsTArray<uint8_t> data;
data.AppendElements(aData, aCount);
Unused << SendOnDataReceived(std::move(data));
}
return NS_OK;
}
void WebSocketConnectionChild::ActorDestroy(ActorDestroyReason aWhy) {
LOG(("WebSocketConnectionChild::ActorDestroy %p\n", this));
if (mConnection) {
mConnection->Close();
mConnection = nullptr;
}
}
} // namespace net
} // namespace mozilla

View File

@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* 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_net_WebSocketConnectionChild_h
#define mozilla_net_WebSocketConnectionChild_h
#include "mozilla/net/PWebSocketConnectionChild.h"
#include "nsIHttpChannelInternal.h"
#include "nsISupportsImpl.h"
#include "nsIWebSocketConnection.h"
namespace mozilla {
namespace net {
class nsWebSocketConnection;
// WebSocketConnectionChild only lives in socket process and uses
// nsWebSocketConnection to send/read data from socket. Only IPDL holds a strong
// reference to WebSocketConnectionChild, so the life time of
// WebSocketConnectionChild is bound to the IPC actor.
class WebSocketConnectionChild final : public PWebSocketConnectionChild,
public nsIHttpUpgradeListener,
public nsIWebSocketConnectionListener {
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIHTTPUPGRADELISTENER
NS_DECL_NSIWEBSOCKETCONNECTIONLISTENER
WebSocketConnectionChild();
mozilla::ipc::IPCResult RecvEnqueueOutgoingData(nsTArray<uint8_t>&& aHeader,
nsTArray<uint8_t>&& aPayload);
mozilla::ipc::IPCResult RecvStartReading();
mozilla::ipc::IPCResult RecvDrainSocketData();
mozilla::ipc::IPCResult Recv__delete__() override;
void ActorDestroy(ActorDestroyReason aWhy) override;
private:
virtual ~WebSocketConnectionChild();
RefPtr<nsWebSocketConnection> mConnection;
};
} // namespace net
} // namespace mozilla
#endif // mozilla_net_WebSocketConnectionChild_h

View File

@ -0,0 +1,246 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* 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 "WebSocketLog.h"
#include "WebSocketConnectionParent.h"
#include "nsIHttpChannelInternal.h"
#include "nsSerializationHelper.h"
#include "nsThreadUtils.h"
namespace mozilla {
namespace net {
NS_IMPL_ADDREF(WebSocketConnectionParent)
NS_IMPL_RELEASE(WebSocketConnectionParent)
NS_INTERFACE_MAP_BEGIN(WebSocketConnectionParent)
NS_INTERFACE_MAP_ENTRY(nsIWebSocketConnection)
NS_INTERFACE_MAP_ENTRY_CONCRETE(WebSocketConnectionParent)
NS_INTERFACE_MAP_END
WebSocketConnectionParent::WebSocketConnectionParent(
nsIHttpUpgradeListener* aListener)
: mUpgradeListener(aListener), mClosed(false) {
LOG(("WebSocketConnectionParent ctor %p\n", this));
MOZ_ASSERT(mUpgradeListener);
}
WebSocketConnectionParent::~WebSocketConnectionParent() {
LOG(("WebSocketConnectionParent dtor %p\n", this));
}
mozilla::ipc::IPCResult WebSocketConnectionParent::RecvOnTransportAvailable(
const nsCString& aSecurityInfoSerialization) {
LOG(("WebSocketConnectionParent::RecvOnTransportAvailable %p\n", this));
if (!aSecurityInfoSerialization.IsEmpty()) {
nsresult rv = NS_DeserializeObject(aSecurityInfoSerialization,
getter_AddRefs(mSecurityInfo));
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
"Deserializing security info should not fail");
Unused << rv; // So we don't get an unused error in release builds.
}
if (mUpgradeListener) {
Unused << mUpgradeListener->OnWebSocketConnectionAvailable(this);
mUpgradeListener = nullptr;
}
return IPC_OK();
}
static inline void DispatchHelper(nsIEventTarget* aTarget, const char* aName,
std::function<void()>&& aTask) {
if (aTarget->IsOnCurrentThread()) {
aTask();
} else {
aTarget->Dispatch(NS_NewRunnableFunction(aName, std::move(aTask)),
NS_DISPATCH_NORMAL);
}
}
mozilla::ipc::IPCResult WebSocketConnectionParent::RecvOnError(
const nsresult& aStatus) {
LOG(("WebSocketConnectionParent::RecvOnError %p\n", this));
MOZ_ASSERT(mEventTarget);
RefPtr<WebSocketConnectionParent> self = this;
auto task = [self{std::move(self)}, aStatus]() {
if (self->mListener) {
self->mListener->OnError(aStatus);
}
};
DispatchHelper(mEventTarget, "WebSocketConnectionParent::RecvOnError",
std::move(task));
return IPC_OK();
}
mozilla::ipc::IPCResult WebSocketConnectionParent::RecvOnUpgradeFailed(
const nsresult& aReason) {
RefPtr<WebSocketConnectionParent> self = this;
auto task = [self{std::move(self)}, aReason]() {
if (self->mUpgradeListener) {
Unused << self->mUpgradeListener->OnUpgradeFailed(aReason);
self->mUpgradeListener = nullptr;
}
};
DispatchHelper(mEventTarget, "WebSocketConnectionParent::RecvOnUpgradeFailed",
std::move(task));
return IPC_OK();
}
mozilla::ipc::IPCResult WebSocketConnectionParent::RecvOnTCPClosed() {
LOG(("WebSocketConnectionParent::RecvOnTCPClosed %p\n", this));
MOZ_ASSERT(mEventTarget);
RefPtr<WebSocketConnectionParent> self = this;
auto task = [self{std::move(self)}]() {
if (self->mListener) {
self->mListener->OnTCPClosed();
}
};
DispatchHelper(mEventTarget, "WebSocketConnectionParent::RecvOnTCPClosed",
std::move(task));
return IPC_OK();
}
mozilla::ipc::IPCResult WebSocketConnectionParent::RecvOnDataReceived(
nsTArray<uint8_t>&& aData) {
LOG(("WebSocketConnectionParent::RecvOnDataReceived %p\n", this));
MOZ_ASSERT(mEventTarget);
RefPtr<WebSocketConnectionParent> self = this;
auto task = [self{std::move(self)},
data = CopyableTArray{std::move(aData)}]() {
if (self->mListener) {
uint8_t* buffer = const_cast<uint8_t*>(data.Elements());
nsresult rv = self->mListener->OnDataReceived(buffer, data.Length());
if (NS_FAILED(rv)) {
self->mListener->OnError(rv);
}
}
};
DispatchHelper(mEventTarget, "WebSocketConnectionParent::RecvOnDataReceived",
std::move(task));
return IPC_OK();
}
void WebSocketConnectionParent::ActorDestroy(ActorDestroyReason aWhy) {
LOG(("WebSocketConnectionParent::ActorDestroy %p aWhy=%d\n", this, aWhy));
if (!mClosed) {
// Treat this as an error when IPC is closed before
// WebSocketConnectionParent::Close() is called.
nsCOMPtr<nsIWebSocketConnectionListener> listener;
listener.swap(mListener);
if (listener) {
listener->OnError(NS_ERROR_FAILURE);
}
}
};
NS_IMETHODIMP
WebSocketConnectionParent::Init(nsIWebSocketConnectionListener* aListener,
nsIEventTarget* aEventTarget) {
NS_ENSURE_ARG_POINTER(aListener);
NS_ENSURE_ARG_POINTER(aEventTarget);
mListener = aListener;
mEventTarget = aEventTarget;
return NS_OK;
}
NS_IMETHODIMP
WebSocketConnectionParent::Close() {
LOG(("WebSocketConnectionParent::Close %p\n", this));
RefPtr<WebSocketConnectionParent> self = this;
auto task = [self{std::move(self)}]() {
self->mClosed = true;
if (self->CanSend()) {
Unused << self->Send__delete__(self);
self->mListener = nullptr;
}
};
DispatchHelper(GetMainThreadEventTarget(), "WebSocketConnectionParent::Close",
std::move(task));
return NS_OK;
}
NS_IMETHODIMP
WebSocketConnectionParent::EnqueueOutputData(const uint8_t* aHdrBuf,
uint32_t aHdrBufLength,
const uint8_t* aPayloadBuf,
uint32_t aPayloadBufLength) {
LOG(("WebSocketConnectionParent::EnqueueOutputData %p\n", this));
RefPtr<WebSocketConnectionParent> self = this;
nsTArray<uint8_t> header;
header.AppendElements(aHdrBuf, aHdrBufLength);
nsTArray<uint8_t> payload;
payload.AppendElements(aPayloadBuf, aPayloadBufLength);
auto task = [self{std::move(self)},
header = CopyableTArray{std::move(header)},
payload = CopyableTArray{std::move(payload)}]() mutable {
if (self->CanSend()) {
Unused << self->SendEnqueueOutgoingData(std::move(header),
std::move(payload));
}
};
DispatchHelper(GetMainThreadEventTarget(),
"WebSocketConnectionParent::EnqueOutputData", std::move(task));
return NS_OK;
}
NS_IMETHODIMP
WebSocketConnectionParent::StartReading() {
LOG(("WebSocketConnectionParent::StartReading %p\n", this));
RefPtr<WebSocketConnectionParent> self = this;
auto task = [self{std::move(self)}]() {
if (self->CanSend()) {
Unused << self->SendStartReading();
}
};
DispatchHelper(GetMainThreadEventTarget(),
"WebSocketConnectionParent::SendStartReading",
std::move(task));
return NS_OK;
}
NS_IMETHODIMP
WebSocketConnectionParent::DrainSocketData() {
LOG(("WebSocketConnectionParent::DrainSocketData %p\n", this));
RefPtr<WebSocketConnectionParent> self = this;
auto task = [self{std::move(self)}]() {
if (self->CanSend()) {
Unused << self->SendDrainSocketData();
}
};
DispatchHelper(GetMainThreadEventTarget(),
"WebSocketConnectionParent::DrainSocketData", std::move(task));
return NS_OK;
}
NS_IMETHODIMP
WebSocketConnectionParent::GetSecurityInfo(nsISupports** aSecurityInfo) {
LOG(("WebSocketConnectionParent::GetSecurityInfo() %p\n", this));
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_ARG_POINTER(aSecurityInfo);
nsCOMPtr<nsISupports> info = mSecurityInfo;
info.forget(aSecurityInfo);
return NS_OK;
}
} // namespace net
} // namespace mozilla

View File

@ -0,0 +1,67 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* 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_net_WebSocketConnectionParent_h
#define mozilla_net_WebSocketConnectionParent_h
#include "mozilla/net/PWebSocketConnectionParent.h"
#include "nsISupportsImpl.h"
#include "nsIWebSocketConnection.h"
class nsIHttpUpgradeListener;
namespace mozilla {
namespace net {
// WebSocketConnectionParent implements nsIWebSocketConnection and provides
// interface for WebSocketChannel to send/receive data. The ownership model for
// TransportProvider is that IPDL and WebSocketChannel hold strong reference of
// WebSocketConnectionParent. When nsIWebSocketConnection::Close is called, a
// __delete__ message will be sent and the IPC actor will be deallocated as
// well.
#define WEB_SOCKET_CONNECTION_PARENT_IID \
{ \
0x1cc3cb61, 0x0c09, 0x4f58, { \
0x9a, 0x64, 0x44, 0xf7, 0x92, 0x86, 0xbc, 0x00 \
} \
}
class WebSocketConnectionParent final : public PWebSocketConnectionParent,
public nsIWebSocketConnection {
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIWEBSOCKETCONNECTION
NS_DECLARE_STATIC_IID_ACCESSOR(WEB_SOCKET_CONNECTION_PARENT_IID)
explicit WebSocketConnectionParent(nsIHttpUpgradeListener* aListener);
mozilla::ipc::IPCResult RecvOnTransportAvailable(
const nsCString& aSecurityInfoSerialization);
mozilla::ipc::IPCResult RecvOnError(const nsresult& aStatus);
mozilla::ipc::IPCResult RecvOnTCPClosed();
mozilla::ipc::IPCResult RecvOnDataReceived(nsTArray<uint8_t>&& aData);
mozilla::ipc::IPCResult RecvOnUpgradeFailed(const nsresult& aReason);
void ActorDestroy(ActorDestroyReason aWhy) override;
private:
virtual ~WebSocketConnectionParent();
nsCOMPtr<nsIHttpUpgradeListener> mUpgradeListener;
nsCOMPtr<nsIWebSocketConnectionListener> mListener;
nsCOMPtr<nsIEventTarget> mEventTarget;
nsCOMPtr<nsISupports> mSecurityInfo;
bool mClosed;
};
NS_DEFINE_STATIC_IID_ACCESSOR(WebSocketConnectionParent,
WEB_SOCKET_CONNECTION_PARENT_IID)
} // namespace net
} // namespace mozilla
#endif // mozilla_net_WebSocketConnectionParent_h

View File

@ -23,6 +23,8 @@ EXPORTS.mozilla.net += [
'WebSocketChannel.h',
'WebSocketChannelChild.h',
'WebSocketChannelParent.h',
'WebSocketConnectionChild.h',
'WebSocketConnectionParent.h',
'WebSocketEventListenerChild.h',
'WebSocketEventListenerParent.h',
'WebSocketEventService.h',
@ -36,6 +38,8 @@ UNIFIED_SOURCES += [
'WebSocketChannel.cpp',
'WebSocketChannelChild.cpp',
'WebSocketChannelParent.cpp',
'WebSocketConnectionChild.cpp',
'WebSocketConnectionParent.cpp',
'WebSocketEventListenerChild.cpp',
'WebSocketEventListenerParent.cpp',
'WebSocketEventService.cpp',
@ -45,6 +49,7 @@ UNIFIED_SOURCES += [
IPDL_SOURCES += [
'PTransportProvider.ipdl',
'PWebSocket.ipdl',
'PWebSocketConnection.ipdl',
'PWebSocketEventListener.ipdl',
]

View File

@ -9,7 +9,6 @@
#include "WebSocketLog.h"
#include "nsIOService.h"
#include "nsISocketTransport.h"
#include "nsSocketTransportService2.h"
NS_IMPL_ISUPPORTS(nsWebSocketConnection, nsIWebSocketConnection,
nsIInputStreamCallback, nsIOutputStreamCallback)
@ -29,9 +28,6 @@ nsWebSocketConnection::Init(nsIWebSocketConnectionListener* aListener,
NS_ENSURE_ARG_POINTER(aListener);
NS_ENSURE_ARG_POINTER(aEventTarget);
MOZ_ASSERT_IF(nsIOService::UseSocketProcess(), XRE_IsSocketProcess());
MOZ_ASSERT_IF(!nsIOService::UseSocketProcess(), XRE_IsParentProcess());
mListener = aListener;
mEventTarget = aEventTarget;
@ -43,7 +39,7 @@ nsWebSocketConnection::Init(nsIWebSocketConnectionListener* aListener,
nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryInterface(mListener);
mTransport->SetSecurityCallbacks(callbacks);
} else {
// TODO: deal with security callbacks in bug 1512479
// NOTE: we don't use security callbacks in socket process.
mTransport->SetSecurityCallbacks(nullptr);
}
return mTransport->SetEventSink(nullptr, nullptr);
@ -74,18 +70,12 @@ nsWebSocketConnection::Close() {
return NS_OK;
}
NS_IMETHODIMP
nsWebSocketConnection::EnqueueOutputData(const uint8_t* aHdrBuf,
uint32_t aHdrBufLength,
const uint8_t* aPayloadBuf,
uint32_t aPayloadBufLength) {
LOG(("nsWebSocketConnection::EnqueueOutputData %p\n", this));
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
nsresult nsWebSocketConnection::EnqueueOutputData(
nsTArray<uint8_t>&& aHeader, nsTArray<uint8_t>&& aPayload) {
MOZ_ASSERT(mEventTarget->IsOnCurrentThread());
nsTArray<uint8_t> data;
data.AppendElements(aHdrBuf, aHdrBufLength);
data.AppendElements(aPayloadBuf, aPayloadBufLength);
mOutputQueue.emplace_back(std::move(data));
mOutputQueue.emplace_back(std::move(aHeader));
mOutputQueue.emplace_back(std::move(aPayload));
if (mSocketOut) {
mSocketOut->AsyncWait(this, 0, 0, mEventTarget);
@ -94,6 +84,20 @@ nsWebSocketConnection::EnqueueOutputData(const uint8_t* aHdrBuf,
return NS_OK;
}
NS_IMETHODIMP
nsWebSocketConnection::EnqueueOutputData(const uint8_t* aHdrBuf,
uint32_t aHdrBufLength,
const uint8_t* aPayloadBuf,
uint32_t aPayloadBufLength) {
LOG(("nsWebSocketConnection::EnqueueOutputData %p\n", this));
nsTArray<uint8_t> header;
header.AppendElements(aHdrBuf, aHdrBufLength);
nsTArray<uint8_t> payload;
payload.AppendElements(aPayloadBuf, aPayloadBufLength);
return EnqueueOutputData(std::move(header), std::move(payload));
}
NS_IMETHODIMP
nsWebSocketConnection::StartReading() {
if (!mSocketIn) {
@ -107,7 +111,7 @@ nsWebSocketConnection::StartReading() {
NS_IMETHODIMP
nsWebSocketConnection::DrainSocketData() {
MOZ_ASSERT(OnSocketThread());
MOZ_ASSERT(mEventTarget->IsOnCurrentThread());
if (!mSocketIn || !mListener) {
return NS_ERROR_NOT_AVAILABLE;
@ -148,7 +152,7 @@ nsWebSocketConnection::GetSecurityInfo(nsISupports** aSecurityInfo) {
NS_IMETHODIMP
nsWebSocketConnection::OnInputStreamReady(nsIAsyncInputStream* aStream) {
LOG(("nsWebSocketConnection::OnInputStreamReady() %p\n", this));
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
MOZ_ASSERT(mEventTarget->IsOnCurrentThread());
if (!mSocketIn) // did we we clean up the socket after scheduling InputReady?
return NS_OK;
@ -193,7 +197,7 @@ nsWebSocketConnection::OnInputStreamReady(nsIAsyncInputStream* aStream) {
NS_IMETHODIMP
nsWebSocketConnection::OnOutputStreamReady(nsIAsyncOutputStream* aStream) {
LOG(("nsWebSocketConnection::OnOutputStreamReady() %p\n", this));
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
MOZ_ASSERT(mEventTarget->IsOnCurrentThread());
if (!mListener) return NS_OK;

View File

@ -33,6 +33,9 @@ class nsWebSocketConnection : public nsIWebSocketConnection,
nsIAsyncInputStream* aInputStream,
nsIAsyncOutputStream* aOutputStream);
nsresult EnqueueOutputData(nsTArray<uint8_t>&& aHeader,
nsTArray<uint8_t>&& aPayload);
private:
virtual ~nsWebSocketConnection() = default;