WebSocketChannelChild.cpp (21324B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set sw=2 ts=8 et tw=80 : */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "WebSocketLog.h" 8 #include "mozilla/dom/BrowserChild.h" 9 #include "mozilla/net/NeckoChild.h" 10 #include "WebSocketChannelChild.h" 11 #include "nsContentUtils.h" 12 #include "nsIBrowserChild.h" 13 #include "nsNetUtil.h" 14 #include "mozilla/ipc/IPCStreamUtils.h" 15 #include "mozilla/ipc/URIUtils.h" 16 #include "mozilla/ipc/BackgroundUtils.h" 17 #include "mozilla/net/ChannelEventQueue.h" 18 #include "SerializedLoadContext.h" 19 #include "mozilla/dom/ContentChild.h" 20 #include "nsITransportProvider.h" 21 22 using namespace mozilla::ipc; 23 using mozilla::dom::ContentChild; 24 25 namespace mozilla { 26 namespace net { 27 28 NS_IMPL_ADDREF(WebSocketChannelChild) 29 30 NS_IMETHODIMP_(MozExternalRefCountType) WebSocketChannelChild::Release() { 31 MOZ_ASSERT(0 != mRefCnt, "dup release"); 32 --mRefCnt; 33 NS_LOG_RELEASE(this, mRefCnt, "WebSocketChannelChild"); 34 35 if (mRefCnt == 1) { 36 MaybeReleaseIPCObject(); 37 return mRefCnt; 38 } 39 40 if (mRefCnt == 0) { 41 mRefCnt = 1; /* stabilize */ 42 delete this; 43 return 0; 44 } 45 return mRefCnt; 46 } 47 48 NS_INTERFACE_MAP_BEGIN(WebSocketChannelChild) 49 NS_INTERFACE_MAP_ENTRY(nsIWebSocketChannel) 50 NS_INTERFACE_MAP_ENTRY(nsIProtocolHandler) 51 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebSocketChannel) 52 NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableRequest) 53 NS_INTERFACE_MAP_END 54 55 WebSocketChannelChild::WebSocketChannelChild(bool aEncrypted) 56 : NeckoTargetHolder(nullptr), 57 mIPCState(Closed), 58 mMutex("WebSocketChannelChild::mMutex") { 59 MOZ_ASSERT(NS_IsMainThread(), "not main thread"); 60 61 LOG(("WebSocketChannelChild::WebSocketChannelChild() %p\n", this)); 62 mEncrypted = aEncrypted; 63 mEventQ = new ChannelEventQueue(static_cast<nsIWebSocketChannel*>(this)); 64 } 65 66 WebSocketChannelChild::~WebSocketChannelChild() { 67 LOG(("WebSocketChannelChild::~WebSocketChannelChild() %p\n", this)); 68 mEventQ->NotifyReleasingOwner(); 69 } 70 71 void WebSocketChannelChild::AddIPDLReference() { 72 MOZ_ASSERT(NS_IsMainThread()); 73 74 { 75 MutexAutoLock lock(mMutex); 76 MOZ_ASSERT(mIPCState == Closed, 77 "Attempt to retain more than one IPDL reference"); 78 mIPCState = Opened; 79 } 80 81 AddRef(); 82 } 83 84 void WebSocketChannelChild::ReleaseIPDLReference() { 85 MOZ_ASSERT(NS_IsMainThread()); 86 87 { 88 MutexAutoLock lock(mMutex); 89 MOZ_ASSERT(mIPCState != Closed, 90 "Attempt to release nonexistent IPDL reference"); 91 mIPCState = Closed; 92 } 93 94 Release(); 95 } 96 97 void WebSocketChannelChild::MaybeReleaseIPCObject() { 98 { 99 MutexAutoLock lock(mMutex); 100 if (mIPCState != Opened) { 101 return; 102 } 103 104 mIPCState = Closing; 105 } 106 107 if (!NS_IsMainThread()) { 108 nsCOMPtr<nsIEventTarget> target = GetNeckoTarget(); 109 MOZ_ALWAYS_SUCCEEDS(target->Dispatch( 110 NewRunnableMethod("WebSocketChannelChild::MaybeReleaseIPCObject", this, 111 &WebSocketChannelChild::MaybeReleaseIPCObject), 112 NS_DISPATCH_NORMAL)); 113 return; 114 } 115 116 SendDeleteSelf(); 117 } 118 119 void WebSocketChannelChild::GetEffectiveURL(nsAString& aEffectiveURL) const { 120 aEffectiveURL = mEffectiveURL; 121 } 122 123 bool WebSocketChannelChild::IsEncrypted() const { return mEncrypted; } 124 125 class WebSocketEvent { 126 public: 127 MOZ_COUNTED_DEFAULT_CTOR(WebSocketEvent) 128 MOZ_COUNTED_DTOR_VIRTUAL(WebSocketEvent) 129 virtual void Run(WebSocketChannelChild* aChild) = 0; 130 }; 131 132 class WrappedWebSocketEvent : public Runnable { 133 public: 134 WrappedWebSocketEvent(WebSocketChannelChild* aChild, 135 UniquePtr<WebSocketEvent>&& aWebSocketEvent) 136 : Runnable("net::WrappedWebSocketEvent"), 137 mChild(aChild), 138 mWebSocketEvent(std::move(aWebSocketEvent)) { 139 MOZ_RELEASE_ASSERT(!!mWebSocketEvent); 140 } 141 NS_IMETHOD Run() override { 142 mWebSocketEvent->Run(mChild); 143 return NS_OK; 144 } 145 146 private: 147 RefPtr<WebSocketChannelChild> mChild; 148 UniquePtr<WebSocketEvent> mWebSocketEvent; 149 }; 150 151 class EventTargetDispatcher : public ChannelEvent { 152 public: 153 EventTargetDispatcher(WebSocketChannelChild* aChild, 154 WebSocketEvent* aWebSocketEvent) 155 : mChild(aChild), 156 mWebSocketEvent(aWebSocketEvent), 157 mEventTarget(mChild->GetTargetThread()) {} 158 159 void Run() override { 160 if (mEventTarget) { 161 mEventTarget->Dispatch( 162 new WrappedWebSocketEvent(mChild, std::move(mWebSocketEvent)), 163 NS_DISPATCH_NORMAL); 164 return; 165 } 166 } 167 168 already_AddRefed<nsIEventTarget> GetEventTarget() override { 169 nsCOMPtr<nsIEventTarget> target = mEventTarget; 170 if (!target) { 171 target = GetMainThreadSerialEventTarget(); 172 } 173 return target.forget(); 174 } 175 176 private: 177 // The lifetime of the child is ensured by ChannelEventQueue. 178 WebSocketChannelChild* mChild; 179 UniquePtr<WebSocketEvent> mWebSocketEvent; 180 nsCOMPtr<nsIEventTarget> mEventTarget; 181 }; 182 183 class StartEvent : public WebSocketEvent { 184 public: 185 StartEvent(const nsACString& aProtocol, const nsACString& aExtensions, 186 const nsAString& aEffectiveURL, bool aEncrypted, 187 uint64_t aHttpChannelId) 188 : mProtocol(aProtocol), 189 mExtensions(aExtensions), 190 mEffectiveURL(aEffectiveURL), 191 mEncrypted(aEncrypted), 192 mHttpChannelId(aHttpChannelId) {} 193 194 void Run(WebSocketChannelChild* aChild) override { 195 aChild->OnStart(mProtocol, mExtensions, mEffectiveURL, mEncrypted, 196 mHttpChannelId); 197 } 198 199 private: 200 nsCString mProtocol; 201 nsCString mExtensions; 202 nsString mEffectiveURL; 203 bool mEncrypted; 204 uint64_t mHttpChannelId; 205 }; 206 207 mozilla::ipc::IPCResult WebSocketChannelChild::RecvOnStart( 208 const nsACString& aProtocol, const nsACString& aExtensions, 209 const nsAString& aEffectiveURL, const bool& aEncrypted, 210 const uint64_t& aHttpChannelId) { 211 mEventQ->RunOrEnqueue(new EventTargetDispatcher( 212 this, new StartEvent(aProtocol, aExtensions, aEffectiveURL, aEncrypted, 213 aHttpChannelId))); 214 215 return IPC_OK(); 216 } 217 218 void WebSocketChannelChild::OnStart(const nsACString& aProtocol, 219 const nsACString& aExtensions, 220 const nsAString& aEffectiveURL, 221 const bool& aEncrypted, 222 const uint64_t& aHttpChannelId) { 223 LOG(("WebSocketChannelChild::RecvOnStart() %p\n", this)); 224 SetProtocol(aProtocol); 225 mNegotiatedExtensions = aExtensions; 226 mEffectiveURL = aEffectiveURL; 227 mEncrypted = aEncrypted; 228 mHttpChannelId = aHttpChannelId; 229 230 if (mListenerMT) { 231 AutoEventEnqueuer ensureSerialDispatch(mEventQ); 232 nsresult rv = mListenerMT->mListener->OnStart(mListenerMT->mContext); 233 if (NS_FAILED(rv)) { 234 LOG( 235 ("WebSocketChannelChild::OnStart " 236 "mListenerMT->mListener->OnStart() failed with error 0x%08" PRIx32, 237 static_cast<uint32_t>(rv))); 238 } 239 } 240 } 241 242 class StopEvent : public WebSocketEvent { 243 public: 244 explicit StopEvent(const nsresult& aStatusCode) : mStatusCode(aStatusCode) {} 245 246 void Run(WebSocketChannelChild* aChild) override { 247 aChild->OnStop(mStatusCode); 248 } 249 250 private: 251 nsresult mStatusCode; 252 }; 253 254 mozilla::ipc::IPCResult WebSocketChannelChild::RecvOnStop( 255 const nsresult& aStatusCode) { 256 mEventQ->RunOrEnqueue( 257 new EventTargetDispatcher(this, new StopEvent(aStatusCode))); 258 259 return IPC_OK(); 260 } 261 262 void WebSocketChannelChild::OnStop(const nsresult& aStatusCode) { 263 LOG(("WebSocketChannelChild::RecvOnStop() %p\n", this)); 264 if (mListenerMT) { 265 AutoEventEnqueuer ensureSerialDispatch(mEventQ); 266 nsresult rv = 267 mListenerMT->mListener->OnStop(mListenerMT->mContext, aStatusCode); 268 if (NS_FAILED(rv)) { 269 LOG( 270 ("WebSocketChannel::OnStop " 271 "mListenerMT->mListener->OnStop() failed with error 0x%08" PRIx32, 272 static_cast<uint32_t>(rv))); 273 } 274 } 275 } 276 277 class MessageEvent : public WebSocketEvent { 278 public: 279 MessageEvent(const nsACString& aMessage, bool aBinary) 280 : mMessage(aMessage), mBinary(aBinary) {} 281 282 void Run(WebSocketChannelChild* aChild) override { 283 if (!mBinary) { 284 aChild->OnMessageAvailable(mMessage); 285 } else { 286 aChild->OnBinaryMessageAvailable(mMessage); 287 } 288 } 289 290 private: 291 nsCString mMessage; 292 bool mBinary; 293 }; 294 295 bool WebSocketChannelChild::RecvOnMessageAvailableInternal( 296 const nsACString& aMsg, bool aMoreData, bool aBinary) { 297 if (aMoreData) { 298 return mReceivedMsgBuffer.Append(aMsg, fallible); 299 } 300 301 if (!mReceivedMsgBuffer.Append(aMsg, fallible)) { 302 return false; 303 } 304 305 mEventQ->RunOrEnqueue(new EventTargetDispatcher( 306 this, new MessageEvent(mReceivedMsgBuffer, aBinary))); 307 mReceivedMsgBuffer.Truncate(); 308 return true; 309 } 310 311 class OnErrorEvent : public WebSocketEvent { 312 public: 313 OnErrorEvent() = default; 314 315 void Run(WebSocketChannelChild* aChild) override { aChild->OnError(); } 316 }; 317 318 void WebSocketChannelChild::OnError() { 319 LOG(("WebSocketChannelChild::OnError() %p", this)); 320 if (mListenerMT) { 321 AutoEventEnqueuer ensureSerialDispatch(mEventQ); 322 (void)mListenerMT->mListener->OnError(); 323 } 324 } 325 326 mozilla::ipc::IPCResult WebSocketChannelChild::RecvOnMessageAvailable( 327 const nsACString& aMsg, const bool& aMoreData) { 328 if (!RecvOnMessageAvailableInternal(aMsg, aMoreData, false)) { 329 LOG(("WebSocketChannelChild %p append message failed", this)); 330 mEventQ->RunOrEnqueue(new EventTargetDispatcher(this, new OnErrorEvent())); 331 } 332 return IPC_OK(); 333 } 334 335 void WebSocketChannelChild::OnMessageAvailable(const nsACString& aMsg) { 336 LOG(("WebSocketChannelChild::RecvOnMessageAvailable() %p\n", this)); 337 if (mListenerMT) { 338 AutoEventEnqueuer ensureSerialDispatch(mEventQ); 339 nsresult rv = 340 mListenerMT->mListener->OnMessageAvailable(mListenerMT->mContext, aMsg); 341 if (NS_FAILED(rv)) { 342 LOG( 343 ("WebSocketChannelChild::OnMessageAvailable " 344 "mListenerMT->mListener->OnMessageAvailable() " 345 "failed with error 0x%08" PRIx32, 346 static_cast<uint32_t>(rv))); 347 } 348 } 349 } 350 351 mozilla::ipc::IPCResult WebSocketChannelChild::RecvOnBinaryMessageAvailable( 352 const nsACString& aMsg, const bool& aMoreData) { 353 if (!RecvOnMessageAvailableInternal(aMsg, aMoreData, true)) { 354 LOG(("WebSocketChannelChild %p append message failed", this)); 355 mEventQ->RunOrEnqueue(new EventTargetDispatcher(this, new OnErrorEvent())); 356 } 357 return IPC_OK(); 358 } 359 360 void WebSocketChannelChild::OnBinaryMessageAvailable(const nsACString& aMsg) { 361 LOG(("WebSocketChannelChild::RecvOnBinaryMessageAvailable() %p\n", this)); 362 if (mListenerMT) { 363 AutoEventEnqueuer ensureSerialDispatch(mEventQ); 364 nsresult rv = mListenerMT->mListener->OnBinaryMessageAvailable( 365 mListenerMT->mContext, aMsg); 366 if (NS_FAILED(rv)) { 367 LOG( 368 ("WebSocketChannelChild::OnBinaryMessageAvailable " 369 "mListenerMT->mListener->OnBinaryMessageAvailable() " 370 "failed with error 0x%08" PRIx32, 371 static_cast<uint32_t>(rv))); 372 } 373 } 374 } 375 376 class AcknowledgeEvent : public WebSocketEvent { 377 public: 378 explicit AcknowledgeEvent(const uint32_t& aSize) : mSize(aSize) {} 379 380 void Run(WebSocketChannelChild* aChild) override { 381 aChild->OnAcknowledge(mSize); 382 } 383 384 private: 385 uint32_t mSize; 386 }; 387 388 mozilla::ipc::IPCResult WebSocketChannelChild::RecvOnAcknowledge( 389 const uint32_t& aSize) { 390 mEventQ->RunOrEnqueue( 391 new EventTargetDispatcher(this, new AcknowledgeEvent(aSize))); 392 393 return IPC_OK(); 394 } 395 396 void WebSocketChannelChild::OnAcknowledge(const uint32_t& aSize) { 397 LOG(("WebSocketChannelChild::RecvOnAcknowledge() %p\n", this)); 398 if (mListenerMT) { 399 AutoEventEnqueuer ensureSerialDispatch(mEventQ); 400 nsresult rv = 401 mListenerMT->mListener->OnAcknowledge(mListenerMT->mContext, aSize); 402 if (NS_FAILED(rv)) { 403 LOG( 404 ("WebSocketChannel::OnAcknowledge " 405 "mListenerMT->mListener->OnAcknowledge() " 406 "failed with error 0x%08" PRIx32, 407 static_cast<uint32_t>(rv))); 408 } 409 } 410 } 411 412 class ServerCloseEvent : public WebSocketEvent { 413 public: 414 ServerCloseEvent(const uint16_t aCode, const nsACString& aReason) 415 : mCode(aCode), mReason(aReason) {} 416 417 void Run(WebSocketChannelChild* aChild) override { 418 aChild->OnServerClose(mCode, mReason); 419 } 420 421 private: 422 uint16_t mCode; 423 nsCString mReason; 424 }; 425 426 mozilla::ipc::IPCResult WebSocketChannelChild::RecvOnServerClose( 427 const uint16_t& aCode, const nsACString& aReason) { 428 mEventQ->RunOrEnqueue( 429 new EventTargetDispatcher(this, new ServerCloseEvent(aCode, aReason))); 430 431 return IPC_OK(); 432 } 433 434 void WebSocketChannelChild::OnServerClose(const uint16_t& aCode, 435 const nsACString& aReason) { 436 LOG(("WebSocketChannelChild::RecvOnServerClose() %p\n", this)); 437 if (mListenerMT) { 438 AutoEventEnqueuer ensureSerialDispatch(mEventQ); 439 DebugOnly<nsresult> rv = mListenerMT->mListener->OnServerClose( 440 mListenerMT->mContext, aCode, aReason); 441 MOZ_ASSERT(NS_SUCCEEDED(rv)); 442 } 443 } 444 445 void WebSocketChannelChild::SetupNeckoTarget() { 446 mNeckoTarget = GetMainThreadSerialEventTarget(); 447 } 448 449 NS_IMETHODIMP 450 WebSocketChannelChild::AsyncOpen(nsIURI* aURI, const nsACString& aOrigin, 451 JS::Handle<JS::Value> aOriginAttributes, 452 uint64_t aInnerWindowID, 453 nsIWebSocketListener* aListener, 454 nsISupports* aContext, JSContext* aCx) { 455 OriginAttributes attrs; 456 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) { 457 return NS_ERROR_INVALID_ARG; 458 } 459 return AsyncOpenNative(aURI, aOrigin, attrs, aInnerWindowID, aListener, 460 aContext); 461 } 462 463 NS_IMETHODIMP 464 WebSocketChannelChild::AsyncOpenNative( 465 nsIURI* aURI, const nsACString& aOrigin, 466 const OriginAttributes& aOriginAttributes, uint64_t aInnerWindowID, 467 nsIWebSocketListener* aListener, nsISupports* aContext) { 468 LOG(("WebSocketChannelChild::AsyncOpen() %p\n", this)); 469 470 MOZ_ASSERT(NS_IsMainThread(), "not main thread"); 471 MOZ_ASSERT((aURI && !mIsServerSide) || (!aURI && mIsServerSide), 472 "Invalid aURI for WebSocketChannelChild::AsyncOpen"); 473 MOZ_ASSERT(aListener && !mListenerMT, 474 "Invalid state for WebSocketChannelChild::AsyncOpen"); 475 476 mozilla::dom::BrowserChild* browserChild = nullptr; 477 nsCOMPtr<nsIBrowserChild> iBrowserChild; 478 NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, 479 NS_GET_IID(nsIBrowserChild), 480 getter_AddRefs(iBrowserChild)); 481 if (iBrowserChild) { 482 browserChild = 483 static_cast<mozilla::dom::BrowserChild*>(iBrowserChild.get()); 484 } 485 486 ContentChild* cc = static_cast<ContentChild*>(gNeckoChild->Manager()); 487 if (cc->IsShuttingDown()) { 488 return NS_ERROR_FAILURE; 489 } 490 491 // Corresponding release in DeallocPWebSocket 492 AddIPDLReference(); 493 494 nsCOMPtr<nsIURI> uri; 495 LoadInfoArgs loadInfoArgs; 496 Maybe<NotNull<PTransportProviderChild*>> transportProvider; 497 498 if (!mIsServerSide) { 499 uri = aURI; 500 nsresult rv = LoadInfoToLoadInfoArgs(mLoadInfo, &loadInfoArgs); 501 NS_ENSURE_SUCCESS(rv, rv); 502 503 transportProvider = Nothing(); 504 } else { 505 MOZ_ASSERT(mServerTransportProvider); 506 PTransportProviderChild* ipcChild; 507 nsresult rv = mServerTransportProvider->GetIPCChild(&ipcChild); 508 NS_ENSURE_SUCCESS(rv, rv); 509 510 transportProvider = Some(WrapNotNull(ipcChild)); 511 } 512 513 // This must be called before sending constructor message. 514 SetupNeckoTarget(); 515 516 if (!gNeckoChild->SendPWebSocketConstructor( 517 this, browserChild, IPC::SerializedLoadContext(this), mSerial)) { 518 return NS_ERROR_UNEXPECTED; 519 } 520 if (!SendAsyncOpen(uri, aOrigin, aOriginAttributes, aInnerWindowID, mProtocol, 521 mEncrypted, mPingInterval, mClientSetPingInterval, 522 mPingResponseTimeout, mClientSetPingTimeout, loadInfoArgs, 523 transportProvider, mNegotiatedExtensions)) { 524 return NS_ERROR_UNEXPECTED; 525 } 526 527 if (mIsServerSide) { 528 mServerTransportProvider = nullptr; 529 } 530 531 mOriginalURI = aURI; 532 mURI = mOriginalURI; 533 mListenerMT = new ListenerAndContextContainer(aListener, aContext); 534 mOrigin = aOrigin; 535 mWasOpened = 1; 536 537 return NS_OK; 538 } 539 540 class CloseEvent : public Runnable { 541 public: 542 CloseEvent(WebSocketChannelChild* aChild, uint16_t aCode, 543 const nsACString& aReason) 544 : Runnable("net::CloseEvent"), 545 mChild(aChild), 546 mCode(aCode), 547 mReason(aReason) { 548 MOZ_RELEASE_ASSERT(!NS_IsMainThread()); 549 MOZ_ASSERT(aChild); 550 } 551 NS_IMETHOD Run() override { 552 MOZ_RELEASE_ASSERT(NS_IsMainThread()); 553 mChild->Close(mCode, mReason); 554 return NS_OK; 555 } 556 557 private: 558 RefPtr<WebSocketChannelChild> mChild; 559 uint16_t mCode; 560 nsCString mReason; 561 }; 562 563 NS_IMETHODIMP 564 WebSocketChannelChild::Close(uint16_t code, const nsACString& reason) { 565 if (!NS_IsMainThread()) { 566 MOZ_RELEASE_ASSERT(IsOnTargetThread()); 567 nsCOMPtr<nsIEventTarget> target = GetNeckoTarget(); 568 return target->Dispatch(new CloseEvent(this, code, reason), 569 NS_DISPATCH_NORMAL); 570 } 571 LOG(("WebSocketChannelChild::Close() %p\n", this)); 572 573 { 574 MutexAutoLock lock(mMutex); 575 if (mIPCState != Opened) { 576 return NS_ERROR_UNEXPECTED; 577 } 578 } 579 580 if (!SendClose(code, reason)) { 581 return NS_ERROR_UNEXPECTED; 582 } 583 584 return NS_OK; 585 } 586 587 class MsgEvent : public Runnable { 588 public: 589 MsgEvent(WebSocketChannelChild* aChild, const nsACString& aMsg, 590 bool aBinaryMsg) 591 : Runnable("net::MsgEvent"), 592 mChild(aChild), 593 mMsg(aMsg), 594 mBinaryMsg(aBinaryMsg) { 595 MOZ_RELEASE_ASSERT(!NS_IsMainThread()); 596 MOZ_ASSERT(aChild); 597 } 598 NS_IMETHOD Run() override { 599 MOZ_RELEASE_ASSERT(NS_IsMainThread()); 600 if (mBinaryMsg) { 601 mChild->SendBinaryMsg(mMsg); 602 } else { 603 mChild->SendMsg(mMsg); 604 } 605 return NS_OK; 606 } 607 608 private: 609 RefPtr<WebSocketChannelChild> mChild; 610 nsCString mMsg; 611 bool mBinaryMsg; 612 }; 613 614 NS_IMETHODIMP 615 WebSocketChannelChild::SendMsg(const nsACString& aMsg) { 616 if (!NS_IsMainThread()) { 617 MOZ_RELEASE_ASSERT(IsOnTargetThread()); 618 nsCOMPtr<nsIEventTarget> target = GetNeckoTarget(); 619 return target->Dispatch(new MsgEvent(this, aMsg, false), 620 NS_DISPATCH_NORMAL); 621 } 622 LOG(("WebSocketChannelChild::SendMsg() %p\n", this)); 623 624 { 625 MutexAutoLock lock(mMutex); 626 if (mIPCState != Opened) { 627 return NS_ERROR_UNEXPECTED; 628 } 629 } 630 631 if (!SendSendMsg(aMsg)) { 632 return NS_ERROR_UNEXPECTED; 633 } 634 635 return NS_OK; 636 } 637 638 NS_IMETHODIMP 639 WebSocketChannelChild::SendBinaryMsg(const nsACString& aMsg) { 640 if (!NS_IsMainThread()) { 641 MOZ_RELEASE_ASSERT(IsOnTargetThread()); 642 nsCOMPtr<nsIEventTarget> target = GetNeckoTarget(); 643 return target->Dispatch(new MsgEvent(this, aMsg, true), NS_DISPATCH_NORMAL); 644 } 645 LOG(("WebSocketChannelChild::SendBinaryMsg() %p\n", this)); 646 647 { 648 MutexAutoLock lock(mMutex); 649 if (mIPCState != Opened) { 650 return NS_ERROR_UNEXPECTED; 651 } 652 } 653 654 if (!SendSendBinaryMsg(aMsg)) { 655 return NS_ERROR_UNEXPECTED; 656 } 657 658 return NS_OK; 659 } 660 661 class BinaryStreamEvent : public Runnable { 662 public: 663 BinaryStreamEvent(WebSocketChannelChild* aChild, nsIInputStream* aStream, 664 uint32_t aLength) 665 : Runnable("net::BinaryStreamEvent"), 666 mChild(aChild), 667 mStream(aStream), 668 mLength(aLength) { 669 MOZ_RELEASE_ASSERT(!NS_IsMainThread()); 670 MOZ_ASSERT(aChild); 671 } 672 NS_IMETHOD Run() override { 673 MOZ_ASSERT(NS_IsMainThread()); 674 nsresult rv = mChild->SendBinaryStream(mStream, mLength); 675 if (NS_FAILED(rv)) { 676 LOG( 677 ("WebSocketChannelChild::BinaryStreamEvent %p " 678 "SendBinaryStream failed (%08" PRIx32 ")\n", 679 this, static_cast<uint32_t>(rv))); 680 } 681 return NS_OK; 682 } 683 684 private: 685 RefPtr<WebSocketChannelChild> mChild; 686 nsCOMPtr<nsIInputStream> mStream; 687 uint32_t mLength; 688 }; 689 690 NS_IMETHODIMP 691 WebSocketChannelChild::SendBinaryStream(nsIInputStream* aStream, 692 uint32_t aLength) { 693 if (!NS_IsMainThread()) { 694 MOZ_RELEASE_ASSERT(IsOnTargetThread()); 695 nsCOMPtr<nsIEventTarget> target = GetNeckoTarget(); 696 return target->Dispatch(new BinaryStreamEvent(this, aStream, aLength), 697 NS_DISPATCH_NORMAL); 698 } 699 700 LOG(("WebSocketChannelChild::SendBinaryStream() %p\n", this)); 701 702 IPCStream ipcStream; 703 if (NS_WARN_IF(!mozilla::ipc::SerializeIPCStream(do_AddRef(aStream), 704 ipcStream, 705 /* aAllowLazy */ false))) { 706 return NS_ERROR_UNEXPECTED; 707 } 708 709 { 710 MutexAutoLock lock(mMutex); 711 if (mIPCState != Opened) { 712 return NS_ERROR_UNEXPECTED; 713 } 714 } 715 716 if (!SendSendBinaryStream(ipcStream, aLength)) { 717 return NS_ERROR_UNEXPECTED; 718 } 719 720 return NS_OK; 721 } 722 723 NS_IMETHODIMP 724 WebSocketChannelChild::GetSecurityInfo( 725 nsITransportSecurityInfo** aSecurityInfo) { 726 LOG(("WebSocketChannelChild::GetSecurityInfo() %p\n", this)); 727 return NS_ERROR_NOT_AVAILABLE; 728 } 729 730 } // namespace net 731 } // namespace mozilla