1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/protocol/websocket/WebSocketChannelChild.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,580 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set sw=2 ts=8 et tw=80 : */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "WebSocketLog.h" 1.11 +#include "base/compiler_specific.h" 1.12 +#include "mozilla/dom/TabChild.h" 1.13 +#include "mozilla/net/NeckoChild.h" 1.14 +#include "WebSocketChannelChild.h" 1.15 +#include "nsITabChild.h" 1.16 +#include "nsNetUtil.h" 1.17 +#include "mozilla/ipc/InputStreamUtils.h" 1.18 +#include "mozilla/ipc/URIUtils.h" 1.19 +#include "mozilla/net/ChannelEventQueue.h" 1.20 +#include "SerializedLoadContext.h" 1.21 + 1.22 +using namespace mozilla::ipc; 1.23 + 1.24 +namespace mozilla { 1.25 +namespace net { 1.26 + 1.27 +NS_IMPL_ADDREF(WebSocketChannelChild) 1.28 + 1.29 +NS_IMETHODIMP_(MozExternalRefCountType) WebSocketChannelChild::Release() 1.30 +{ 1.31 + NS_PRECONDITION(0 != mRefCnt, "dup release"); 1.32 + NS_ASSERT_OWNINGTHREAD(WebSocketChannelChild); 1.33 + --mRefCnt; 1.34 + NS_LOG_RELEASE(this, mRefCnt, "WebSocketChannelChild"); 1.35 + 1.36 + if (mRefCnt == 1 && mIPCOpen) { 1.37 + SendDeleteSelf(); 1.38 + return mRefCnt; 1.39 + } 1.40 + 1.41 + if (mRefCnt == 0) { 1.42 + mRefCnt = 1; /* stabilize */ 1.43 + delete this; 1.44 + return 0; 1.45 + } 1.46 + return mRefCnt; 1.47 +} 1.48 + 1.49 +NS_INTERFACE_MAP_BEGIN(WebSocketChannelChild) 1.50 + NS_INTERFACE_MAP_ENTRY(nsIWebSocketChannel) 1.51 + NS_INTERFACE_MAP_ENTRY(nsIProtocolHandler) 1.52 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebSocketChannel) 1.53 + NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableRequest) 1.54 +NS_INTERFACE_MAP_END 1.55 + 1.56 +WebSocketChannelChild::WebSocketChannelChild(bool aSecure) 1.57 + : mIPCOpen(false) 1.58 +{ 1.59 + NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread"); 1.60 + 1.61 + LOG(("WebSocketChannelChild::WebSocketChannelChild() %p\n", this)); 1.62 + BaseWebSocketChannel::mEncrypted = aSecure; 1.63 + mEventQ = new ChannelEventQueue(static_cast<nsIWebSocketChannel*>(this)); 1.64 +} 1.65 + 1.66 +WebSocketChannelChild::~WebSocketChannelChild() 1.67 +{ 1.68 + LOG(("WebSocketChannelChild::~WebSocketChannelChild() %p\n", this)); 1.69 +} 1.70 + 1.71 +void 1.72 +WebSocketChannelChild::AddIPDLReference() 1.73 +{ 1.74 + NS_ABORT_IF_FALSE(!mIPCOpen, "Attempt to retain more than one IPDL reference"); 1.75 + mIPCOpen = true; 1.76 + AddRef(); 1.77 +} 1.78 + 1.79 +void 1.80 +WebSocketChannelChild::ReleaseIPDLReference() 1.81 +{ 1.82 + NS_ABORT_IF_FALSE(mIPCOpen, "Attempt to release nonexistent IPDL reference"); 1.83 + mIPCOpen = false; 1.84 + Release(); 1.85 +} 1.86 + 1.87 +class WrappedChannelEvent : public nsRunnable 1.88 +{ 1.89 +public: 1.90 + WrappedChannelEvent(ChannelEvent *aChannelEvent) 1.91 + : mChannelEvent(aChannelEvent) 1.92 + { 1.93 + MOZ_RELEASE_ASSERT(aChannelEvent); 1.94 + } 1.95 + NS_IMETHOD Run() 1.96 + { 1.97 + mChannelEvent->Run(); 1.98 + return NS_OK; 1.99 + } 1.100 +private: 1.101 + nsAutoPtr<ChannelEvent> mChannelEvent; 1.102 +}; 1.103 + 1.104 +void 1.105 +WebSocketChannelChild::DispatchToTargetThread(ChannelEvent *aChannelEvent) 1.106 +{ 1.107 + MOZ_RELEASE_ASSERT(NS_IsMainThread()); 1.108 + MOZ_RELEASE_ASSERT(mTargetThread); 1.109 + MOZ_RELEASE_ASSERT(aChannelEvent); 1.110 + 1.111 + mTargetThread->Dispatch(new WrappedChannelEvent(aChannelEvent), 1.112 + NS_DISPATCH_NORMAL); 1.113 +} 1.114 + 1.115 +class StartEvent : public ChannelEvent 1.116 +{ 1.117 + public: 1.118 + StartEvent(WebSocketChannelChild* aChild, 1.119 + const nsCString& aProtocol, 1.120 + const nsCString& aExtensions) 1.121 + : mChild(aChild) 1.122 + , mProtocol(aProtocol) 1.123 + , mExtensions(aExtensions) 1.124 + {} 1.125 + 1.126 + void Run() 1.127 + { 1.128 + mChild->OnStart(mProtocol, mExtensions); 1.129 + } 1.130 + private: 1.131 + WebSocketChannelChild* mChild; 1.132 + nsCString mProtocol; 1.133 + nsCString mExtensions; 1.134 +}; 1.135 + 1.136 +bool 1.137 +WebSocketChannelChild::RecvOnStart(const nsCString& aProtocol, 1.138 + const nsCString& aExtensions) 1.139 +{ 1.140 + if (mEventQ->ShouldEnqueue()) { 1.141 + mEventQ->Enqueue(new StartEvent(this, aProtocol, aExtensions)); 1.142 + } else if (mTargetThread) { 1.143 + DispatchToTargetThread(new StartEvent(this, aProtocol, aExtensions)); 1.144 + } else { 1.145 + OnStart(aProtocol, aExtensions); 1.146 + } 1.147 + return true; 1.148 +} 1.149 + 1.150 +void 1.151 +WebSocketChannelChild::OnStart(const nsCString& aProtocol, 1.152 + const nsCString& aExtensions) 1.153 +{ 1.154 + LOG(("WebSocketChannelChild::RecvOnStart() %p\n", this)); 1.155 + SetProtocol(aProtocol); 1.156 + mNegotiatedExtensions = aExtensions; 1.157 + 1.158 + if (mListener) { 1.159 + AutoEventEnqueuer ensureSerialDispatch(mEventQ);; 1.160 + mListener->OnStart(mContext); 1.161 + } 1.162 +} 1.163 + 1.164 +class StopEvent : public ChannelEvent 1.165 +{ 1.166 + public: 1.167 + StopEvent(WebSocketChannelChild* aChild, 1.168 + const nsresult& aStatusCode) 1.169 + : mChild(aChild) 1.170 + , mStatusCode(aStatusCode) 1.171 + {} 1.172 + 1.173 + void Run() 1.174 + { 1.175 + mChild->OnStop(mStatusCode); 1.176 + } 1.177 + private: 1.178 + WebSocketChannelChild* mChild; 1.179 + nsresult mStatusCode; 1.180 +}; 1.181 + 1.182 +bool 1.183 +WebSocketChannelChild::RecvOnStop(const nsresult& aStatusCode) 1.184 +{ 1.185 + if (mEventQ->ShouldEnqueue()) { 1.186 + mEventQ->Enqueue(new StopEvent(this, aStatusCode)); 1.187 + } else if (mTargetThread) { 1.188 + DispatchToTargetThread(new StopEvent(this, aStatusCode)); 1.189 + } else { 1.190 + OnStop(aStatusCode); 1.191 + } 1.192 + return true; 1.193 +} 1.194 + 1.195 +void 1.196 +WebSocketChannelChild::OnStop(const nsresult& aStatusCode) 1.197 +{ 1.198 + LOG(("WebSocketChannelChild::RecvOnStop() %p\n", this)); 1.199 + if (mListener) { 1.200 + AutoEventEnqueuer ensureSerialDispatch(mEventQ);; 1.201 + mListener->OnStop(mContext, aStatusCode); 1.202 + } 1.203 +} 1.204 + 1.205 +class MessageEvent : public ChannelEvent 1.206 +{ 1.207 + public: 1.208 + MessageEvent(WebSocketChannelChild* aChild, 1.209 + const nsCString& aMessage, 1.210 + bool aBinary) 1.211 + : mChild(aChild) 1.212 + , mMessage(aMessage) 1.213 + , mBinary(aBinary) 1.214 + {} 1.215 + 1.216 + void Run() 1.217 + { 1.218 + if (!mBinary) { 1.219 + mChild->OnMessageAvailable(mMessage); 1.220 + } else { 1.221 + mChild->OnBinaryMessageAvailable(mMessage); 1.222 + } 1.223 + } 1.224 + private: 1.225 + WebSocketChannelChild* mChild; 1.226 + nsCString mMessage; 1.227 + bool mBinary; 1.228 +}; 1.229 + 1.230 +bool 1.231 +WebSocketChannelChild::RecvOnMessageAvailable(const nsCString& aMsg) 1.232 +{ 1.233 + if (mEventQ->ShouldEnqueue()) { 1.234 + mEventQ->Enqueue(new MessageEvent(this, aMsg, false)); 1.235 + } else if (mTargetThread) { 1.236 + DispatchToTargetThread(new MessageEvent(this, aMsg, false)); 1.237 + } else { 1.238 + OnMessageAvailable(aMsg); 1.239 + } 1.240 + return true; 1.241 +} 1.242 + 1.243 +void 1.244 +WebSocketChannelChild::OnMessageAvailable(const nsCString& aMsg) 1.245 +{ 1.246 + LOG(("WebSocketChannelChild::RecvOnMessageAvailable() %p\n", this)); 1.247 + if (mListener) { 1.248 + AutoEventEnqueuer ensureSerialDispatch(mEventQ);; 1.249 + mListener->OnMessageAvailable(mContext, aMsg); 1.250 + } 1.251 +} 1.252 + 1.253 +bool 1.254 +WebSocketChannelChild::RecvOnBinaryMessageAvailable(const nsCString& aMsg) 1.255 +{ 1.256 + if (mEventQ->ShouldEnqueue()) { 1.257 + mEventQ->Enqueue(new MessageEvent(this, aMsg, true)); 1.258 + } else if (mTargetThread) { 1.259 + DispatchToTargetThread(new MessageEvent(this, aMsg, true)); 1.260 + } else { 1.261 + OnBinaryMessageAvailable(aMsg); 1.262 + } 1.263 + return true; 1.264 +} 1.265 + 1.266 +void 1.267 +WebSocketChannelChild::OnBinaryMessageAvailable(const nsCString& aMsg) 1.268 +{ 1.269 + LOG(("WebSocketChannelChild::RecvOnBinaryMessageAvailable() %p\n", this)); 1.270 + if (mListener) { 1.271 + AutoEventEnqueuer ensureSerialDispatch(mEventQ);; 1.272 + mListener->OnBinaryMessageAvailable(mContext, aMsg); 1.273 + } 1.274 +} 1.275 + 1.276 +class AcknowledgeEvent : public ChannelEvent 1.277 +{ 1.278 + public: 1.279 + AcknowledgeEvent(WebSocketChannelChild* aChild, 1.280 + const uint32_t& aSize) 1.281 + : mChild(aChild) 1.282 + , mSize(aSize) 1.283 + {} 1.284 + 1.285 + void Run() 1.286 + { 1.287 + mChild->OnAcknowledge(mSize); 1.288 + } 1.289 + private: 1.290 + WebSocketChannelChild* mChild; 1.291 + uint32_t mSize; 1.292 +}; 1.293 + 1.294 +bool 1.295 +WebSocketChannelChild::RecvOnAcknowledge(const uint32_t& aSize) 1.296 +{ 1.297 + if (mEventQ->ShouldEnqueue()) { 1.298 + mEventQ->Enqueue(new AcknowledgeEvent(this, aSize)); 1.299 + } else if (mTargetThread) { 1.300 + DispatchToTargetThread(new AcknowledgeEvent(this, aSize)); 1.301 + } else { 1.302 + OnAcknowledge(aSize); 1.303 + } 1.304 + return true; 1.305 +} 1.306 + 1.307 +void 1.308 +WebSocketChannelChild::OnAcknowledge(const uint32_t& aSize) 1.309 +{ 1.310 + LOG(("WebSocketChannelChild::RecvOnAcknowledge() %p\n", this)); 1.311 + if (mListener) { 1.312 + AutoEventEnqueuer ensureSerialDispatch(mEventQ);; 1.313 + mListener->OnAcknowledge(mContext, aSize); 1.314 + } 1.315 +} 1.316 + 1.317 +class ServerCloseEvent : public ChannelEvent 1.318 +{ 1.319 + public: 1.320 + ServerCloseEvent(WebSocketChannelChild* aChild, 1.321 + const uint16_t aCode, 1.322 + const nsCString &aReason) 1.323 + : mChild(aChild) 1.324 + , mCode(aCode) 1.325 + , mReason(aReason) 1.326 + {} 1.327 + 1.328 + void Run() 1.329 + { 1.330 + mChild->OnServerClose(mCode, mReason); 1.331 + } 1.332 + private: 1.333 + WebSocketChannelChild* mChild; 1.334 + uint16_t mCode; 1.335 + nsCString mReason; 1.336 +}; 1.337 + 1.338 +bool 1.339 +WebSocketChannelChild::RecvOnServerClose(const uint16_t& aCode, 1.340 + const nsCString& aReason) 1.341 +{ 1.342 + if (mEventQ->ShouldEnqueue()) { 1.343 + mEventQ->Enqueue(new ServerCloseEvent(this, aCode, aReason)); 1.344 + } else if (mTargetThread) { 1.345 + DispatchToTargetThread(new ServerCloseEvent(this, aCode, aReason)); 1.346 + } else { 1.347 + OnServerClose(aCode, aReason); 1.348 + } 1.349 + return true; 1.350 +} 1.351 + 1.352 +void 1.353 +WebSocketChannelChild::OnServerClose(const uint16_t& aCode, 1.354 + const nsCString& aReason) 1.355 +{ 1.356 + LOG(("WebSocketChannelChild::RecvOnServerClose() %p\n", this)); 1.357 + if (mListener) { 1.358 + AutoEventEnqueuer ensureSerialDispatch(mEventQ);; 1.359 + mListener->OnServerClose(mContext, aCode, aReason); 1.360 + } 1.361 +} 1.362 + 1.363 +NS_IMETHODIMP 1.364 +WebSocketChannelChild::AsyncOpen(nsIURI *aURI, 1.365 + const nsACString &aOrigin, 1.366 + nsIWebSocketListener *aListener, 1.367 + nsISupports *aContext) 1.368 +{ 1.369 + LOG(("WebSocketChannelChild::AsyncOpen() %p\n", this)); 1.370 + 1.371 + NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread"); 1.372 + NS_ABORT_IF_FALSE(aURI && aListener && !mListener, 1.373 + "Invalid state for WebSocketChannelChild::AsyncOpen"); 1.374 + 1.375 + mozilla::dom::TabChild* tabChild = nullptr; 1.376 + nsCOMPtr<nsITabChild> iTabChild; 1.377 + NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, 1.378 + NS_GET_IID(nsITabChild), 1.379 + getter_AddRefs(iTabChild)); 1.380 + if (iTabChild) { 1.381 + tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get()); 1.382 + } 1.383 + if (MissingRequiredTabChild(tabChild, "websocket")) { 1.384 + return NS_ERROR_ILLEGAL_VALUE; 1.385 + } 1.386 + 1.387 + URIParams uri; 1.388 + SerializeURI(aURI, uri); 1.389 + 1.390 + // Corresponding release in DeallocPWebSocket 1.391 + AddIPDLReference(); 1.392 + 1.393 + gNeckoChild->SendPWebSocketConstructor(this, tabChild, 1.394 + IPC::SerializedLoadContext(this)); 1.395 + if (!SendAsyncOpen(uri, nsCString(aOrigin), mProtocol, mEncrypted, 1.396 + mPingInterval, mClientSetPingInterval, 1.397 + mPingResponseTimeout, mClientSetPingTimeout)) 1.398 + return NS_ERROR_UNEXPECTED; 1.399 + 1.400 + mOriginalURI = aURI; 1.401 + mURI = mOriginalURI; 1.402 + mListener = aListener; 1.403 + mContext = aContext; 1.404 + mOrigin = aOrigin; 1.405 + mWasOpened = 1; 1.406 + 1.407 + return NS_OK; 1.408 +} 1.409 + 1.410 +class CloseEvent : public nsRunnable 1.411 +{ 1.412 +public: 1.413 + CloseEvent(WebSocketChannelChild *aChild, 1.414 + uint16_t aCode, 1.415 + const nsACString& aReason) 1.416 + : mChild(aChild) 1.417 + , mCode(aCode) 1.418 + , mReason(aReason) 1.419 + { 1.420 + MOZ_RELEASE_ASSERT(!NS_IsMainThread()); 1.421 + MOZ_ASSERT(aChild); 1.422 + } 1.423 + NS_IMETHOD Run() 1.424 + { 1.425 + MOZ_RELEASE_ASSERT(NS_IsMainThread()); 1.426 + mChild->Close(mCode, mReason); 1.427 + return NS_OK; 1.428 + } 1.429 +private: 1.430 + nsRefPtr<WebSocketChannelChild> mChild; 1.431 + uint16_t mCode; 1.432 + nsCString mReason; 1.433 +}; 1.434 + 1.435 +NS_IMETHODIMP 1.436 +WebSocketChannelChild::Close(uint16_t code, const nsACString & reason) 1.437 +{ 1.438 + if (!NS_IsMainThread()) { 1.439 + MOZ_RELEASE_ASSERT(NS_GetCurrentThread() == mTargetThread); 1.440 + return NS_DispatchToMainThread(new CloseEvent(this, code, reason)); 1.441 + } 1.442 + LOG(("WebSocketChannelChild::Close() %p\n", this)); 1.443 + 1.444 + if (!mIPCOpen || !SendClose(code, nsCString(reason))) 1.445 + return NS_ERROR_UNEXPECTED; 1.446 + return NS_OK; 1.447 +} 1.448 + 1.449 +class MsgEvent : public nsRunnable 1.450 +{ 1.451 +public: 1.452 + MsgEvent(WebSocketChannelChild *aChild, 1.453 + const nsACString &aMsg, 1.454 + bool aBinaryMsg) 1.455 + : mChild(aChild) 1.456 + , mMsg(aMsg) 1.457 + , mBinaryMsg(aBinaryMsg) 1.458 + { 1.459 + MOZ_RELEASE_ASSERT(!NS_IsMainThread()); 1.460 + MOZ_ASSERT(aChild); 1.461 + } 1.462 + NS_IMETHOD Run() 1.463 + { 1.464 + MOZ_RELEASE_ASSERT(NS_IsMainThread()); 1.465 + if (mBinaryMsg) { 1.466 + mChild->SendBinaryMsg(mMsg); 1.467 + } else { 1.468 + mChild->SendMsg(mMsg); 1.469 + } 1.470 + return NS_OK; 1.471 + } 1.472 +private: 1.473 + nsRefPtr<WebSocketChannelChild> mChild; 1.474 + nsCString mMsg; 1.475 + bool mBinaryMsg; 1.476 +}; 1.477 + 1.478 +NS_IMETHODIMP 1.479 +WebSocketChannelChild::SendMsg(const nsACString &aMsg) 1.480 +{ 1.481 + if (!NS_IsMainThread()) { 1.482 + MOZ_RELEASE_ASSERT(NS_GetCurrentThread() == mTargetThread); 1.483 + return NS_DispatchToMainThread(new MsgEvent(this, aMsg, false)); 1.484 + } 1.485 + LOG(("WebSocketChannelChild::SendMsg() %p\n", this)); 1.486 + 1.487 + if (!mIPCOpen || !SendSendMsg(nsCString(aMsg))) 1.488 + return NS_ERROR_UNEXPECTED; 1.489 + return NS_OK; 1.490 +} 1.491 + 1.492 +NS_IMETHODIMP 1.493 +WebSocketChannelChild::SendBinaryMsg(const nsACString &aMsg) 1.494 +{ 1.495 + if (!NS_IsMainThread()) { 1.496 + MOZ_RELEASE_ASSERT(NS_GetCurrentThread() == mTargetThread); 1.497 + return NS_DispatchToMainThread(new MsgEvent(this, aMsg, true)); 1.498 + } 1.499 + LOG(("WebSocketChannelChild::SendBinaryMsg() %p\n", this)); 1.500 + 1.501 + if (!mIPCOpen || !SendSendBinaryMsg(nsCString(aMsg))) 1.502 + return NS_ERROR_UNEXPECTED; 1.503 + return NS_OK; 1.504 +} 1.505 + 1.506 +class BinaryStreamEvent : public nsRunnable 1.507 +{ 1.508 +public: 1.509 + BinaryStreamEvent(WebSocketChannelChild *aChild, 1.510 + OptionalInputStreamParams *aStream, 1.511 + uint32_t aLength) 1.512 + : mChild(aChild) 1.513 + , mStream(aStream) 1.514 + , mLength(aLength) 1.515 + { 1.516 + MOZ_RELEASE_ASSERT(!NS_IsMainThread()); 1.517 + MOZ_ASSERT(aChild); 1.518 + } 1.519 + NS_IMETHOD Run() 1.520 + { 1.521 + MOZ_ASSERT(NS_IsMainThread()); 1.522 + mChild->SendBinaryStream(mStream, mLength); 1.523 + return NS_OK; 1.524 + } 1.525 +private: 1.526 + nsRefPtr<WebSocketChannelChild> mChild; 1.527 + nsAutoPtr<OptionalInputStreamParams> mStream; 1.528 + uint32_t mLength; 1.529 +}; 1.530 + 1.531 +NS_IMETHODIMP 1.532 +WebSocketChannelChild::SendBinaryStream(nsIInputStream *aStream, 1.533 + uint32_t aLength) 1.534 +{ 1.535 + OptionalInputStreamParams *stream = new OptionalInputStreamParams(); 1.536 + nsTArray<mozilla::ipc::FileDescriptor> fds; 1.537 + SerializeInputStream(aStream, *stream, fds); 1.538 + 1.539 + MOZ_ASSERT(fds.IsEmpty()); 1.540 + 1.541 + if (!NS_IsMainThread()) { 1.542 + MOZ_RELEASE_ASSERT(NS_GetCurrentThread() == mTargetThread); 1.543 + return NS_DispatchToMainThread(new BinaryStreamEvent(this, stream, aLength), 1.544 + NS_DISPATCH_NORMAL); 1.545 + } 1.546 + return SendBinaryStream(stream, aLength); 1.547 +} 1.548 + 1.549 +nsresult 1.550 +WebSocketChannelChild::SendBinaryStream(OptionalInputStreamParams *aStream, 1.551 + uint32_t aLength) 1.552 +{ 1.553 + LOG(("WebSocketChannelChild::SendBinaryStream() %p\n", this)); 1.554 + 1.555 + nsAutoPtr<OptionalInputStreamParams> stream(aStream); 1.556 + 1.557 + if (!mIPCOpen || !SendSendBinaryStream(*stream, aLength)) 1.558 + return NS_ERROR_UNEXPECTED; 1.559 + return NS_OK; 1.560 +} 1.561 + 1.562 +NS_IMETHODIMP 1.563 +WebSocketChannelChild::GetSecurityInfo(nsISupports **aSecurityInfo) 1.564 +{ 1.565 + LOG(("WebSocketChannelChild::GetSecurityInfo() %p\n", this)); 1.566 + return NS_ERROR_NOT_AVAILABLE; 1.567 +} 1.568 + 1.569 +//----------------------------------------------------------------------------- 1.570 +// WebSocketChannelChild::nsIThreadRetargetableRequest 1.571 +//----------------------------------------------------------------------------- 1.572 + 1.573 +NS_IMETHODIMP 1.574 +WebSocketChannelChild::RetargetDeliveryTo(nsIEventTarget* aTargetThread) 1.575 +{ 1.576 + nsresult rv = BaseWebSocketChannel::RetargetDeliveryTo(aTargetThread); 1.577 + MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); 1.578 + 1.579 + return mEventQ->RetargetDeliveryTo(aTargetThread); 1.580 +} 1.581 + 1.582 +} // namespace net 1.583 +} // namespace mozilla